java ren

matinhua的小站

  DonewsBlog  |  Donews首页  |  Donews社区  |  Donews邮箱  |  我的首页  |  联系作者  |  聚合   |  登录
  189篇文章 :: 0篇收藏:: 39篇评论:: 3个Trackbacks

文章

收藏

相册

存档


正在读取评论……


jsp/servlet


    摘要:请问request.getParameter()与request.getAttribute()有什么区别?     (全文共438字)——点击此处阅读全文

简单地说:MQ的核心部分是一个能够存储消息的服务器及一组能够转发消息的进程,分布在多个系统(异地、异种平台)上的应用程序依靠这种机制来交换要处理的数据2。队列管理器作为一个服务器,把消息以可靠的方式存储,即使机器发生故障重新启动后依然不会丢失,其可靠级别与数据库服务器相等。队列管理器间通过特别的交换机制保证数据不会因为底层网络的故障而丢失,并且能够在多点间接力式地传送。

  JMS是J2EE中的一个接口标准,为JAVA程序定义了一种标准的使用消息交换数据的编程方式,但JMS本身并不能实现消息的传送,一个调用JMS的应用程序发出消息调用后,具体的消息传送工作还需要底层的消息中间件来执行传送工作。JMS的作用就是使应用程序开发人员不需要关心底层的传送软件的种类,同一段程序,既可以用MQ传送,也可以用其他消息中间件来传送,如WEBLOGIC内含的具有消息中间件功能的部件。

Java 线程/内存模型的缺陷和增强
作者: wjmmml
出处: 论坛
责任编辑: 方舟
[ 2004-02-18 15:11 ]
  二、DCL失效

  这一节我们要讨论的是一个让Java丢脸的话题:DCL失效。在开始讨论之前,先介绍一下LazyLoad,这种技巧很常用,就是指一个类包含某个成员变量,在类初始化的时候并不立即为该变量初始化一个实例,而是等到真正要使用到该变量的时候才初始化之。

  例如下面的代码:

  代码1

class Foo
{
 private Resource res = null;
 public Resource getResource()
 {
  if (res == null) res = new Resource();
  return res;
 }
}

  由于LazyLoad可以有效的减少系统资源消耗,提高程序整体的性能,所以被广泛的使用,连Java的缺省类加载器也采用这种方法来加载Java类。

  在单线程环境下,一切都相安无事,但如果把上面的代码放到多线程环境下运行,那么就可能会出现问题。假设有2条线程,同时执行到了if(res == null),那么很有可能res被初始化2次,为了避免这样的Race Condition,得用synchronized关键字把上面的方法同步起来。代码如下:

  代码2

Class Foo
{
 Private Resource res = null;
 Public synchronized Resource getResource()
 {
  If (res == null) res = new Resource();
  return res;
 }
}

  现在Race Condition解决了,一切都很好。

  N天过后,好学的你偶然看了一本Refactoring的魔书,深深为之打动,准备自己尝试这重构一些以前写过的程序,于是找到了上面这段代码。你已经不再是以前的Java菜鸟,深知synchronized过的方法在速度上要比未同步的方法慢上100倍,同时你也发现,只有第一次调用该方法的时候才需要同步,而一旦res初始化完成,同步完全没必要。所以你很快就把代码重构成了下面的样子:

  代码3

Class Foo
{
 Private Resource res = null;
 Public Resource getResource()
 {
  If (res == null)
  {
   synchronized(this)
   {
    if(res == null)
    {
     res = new Resource();
    }
   }
  }
  return res;
 }
}

  这种看起来很完美的优化技巧就是Double-Checked Locking。但是很遗憾,根据Java的语言规范,上面的代码是不可靠的。

 一、Java内存模型

  在了解Java的同步秘密之前,先来看看JMM(Java Memory Model)。

  Java被设计为跨平台的语言,在内存管理上,显然也要有一个统一的模型。而且Java语言最大的特点就是废除了指针,把程序员从痛苦中解脱出来,不用再考虑内存使用和管理方面的问题。
可惜世事总不尽如人意,虽然JMM设计上方便了程序员,但是它增加了虚拟机的复杂程度,而且还导致某些编程技巧在Java语言中失效。

  JMM主要是为了规定了线程和内存之间的一些关系。对Java程序员来说只需负责用synchronized同步关键字,其它诸如与线程/内存之间进行数据交换/同步等繁琐工作均由虚拟机负责完成。如图1所示:根据JMM的设计,系统存在一个主内存(Main Memory),Java中所有变量都储存在主存中,对于所有线程都是共享的。每条线程都有自己的工作内存(Working Memory),工作内存中保存的是主存中某些变量的拷贝,线程对所有变量的操作都是在工作内存中进行,线程之间无法相互直接访问,变量传递均需要通过主存完成。


图1 Java内存模型示例图

  线程若要对某变量进行操作,必须经过一系列步骤:首先从主存复制/刷新数据到工作内存,然后执行代码,进行引用/赋值操作,最后把变量内容写回Main Memory。Java语言规范(JLS)中对线程和主存互操作定义了6个行为,分别为load,save,read,write,assign和use,这些操作行为具有原子性,且相互依赖,有明确的调用先后顺序。具体的描述请参见JLS第17章。

  我们在前面的章节介绍了synchronized的作用,现在,从JMM的角度来重新审视synchronized关键字。

  假设某条线程执行一个synchronized代码段,其间对某变量进行操作,JVM会依次执行如下动作:

  (1) 获取同步对象monitor (lock)

  (2) 从主存复制变量到当前工作内存 (read and load)

  (3) 执行代码,改变共享变量值 (use and assign)

  (4) 用工作内存数据刷新主存相关内容 (store and write)

  (5) 释放同步对象锁 (unlock)

  可见,synchronized的另外一个作用是保证主存内容和线程的工作内存中的数据的一致性。如果没有使用synchronized关键字,JVM不保证第2步和第4步会严格按照上述次序立即执行。因为根据JLS中的规定,线程的工作内存和主存之间的数据交换是松耦合的,什么时候需要刷新工作内存或者更新主内存内容,可以由具体的虚拟机实现自行决定。如果多个线程同时执行一段未经synchronized保护的代码段,很有可能某条线程已经改动了变量的值,但是其他线程却无法看到这个改动,依然在旧的变量值上进行运算,最终导致不可预料的运算结果。


    摘要:深入研究Servlet线程安全性问题    (全文共6481字)——点击此处阅读全文


    摘要:Servlet 结构和线程安全     (全文共604字)——点击此处阅读全文


    摘要:在JSP中如何定义方法     (全文共341字)——点击此处阅读全文


    摘要:JSP中变量的定义域     (全文共2203字)——点击此处阅读全文


    摘要:jsp及servlet中的多线程同步问题    (全文共16799字)——点击此处阅读全文


    摘要: log4j使用1    (全文共150217字)——点击此处阅读全文

第1页,共4页