java单例模型

最近在一个项目当中遇到了需要一个单实例模型的问题,就认真查了下资料,复习了下java的单例设计

1.饿汉式:在系统启动的时候就讲对象 实例化。

public class Test{

     private static Test instance=new Test();

 

     private Test(){}//必须定义为私有的构造方法 使得不能再外部new一个实例

     public static Test getInstance(){

         return instance;

     }

}

 

2.懒式:在第一次使用到的时候去判断是否为空,然后去实例化

public class Test{

     private static Test instance=null;

 

     private Test(){}//必须定义为私有的构造方法 使得不能再外部new一个实例

     public static Test getInstance(){

         if(instance==null){

              instance=new Test();

          }

         return instance;

     }

}

 

但是 第二种方法只适用于单线程的程序代码当中,不能保证在多线程访问的服务器端程序中运行时候保证单实例。所以在网上出现了将 第二种方法改造为同步锁定的代码如下:

public static synchronized Test getInstance(){

         if(instance==null){

              instance=new Test();

          }

         return instance;

     }

但于此同时也产生了为了保持同步,必须付出昂贵的代价。事实上只有在第一次使用的时候才用到同步,但是如果把同步加到方法上,就在每一次调用获取实例化对象的时候都将产生同步,这样是在服务器端非常耗资源的。

 

一些聪明的程序员为了解决这个问题,发明了一个新的名词:“双重检查锁定”,代码如下

public class Test{

     private static Test instance=null;

 

     private Test(){}//必须定义为私有的构造方法 使得不能再外部new一个实例

     public static Test getInstance(){

         if(instance==null){

              synchronized (Test .class){

                  if(instance==null){

                       instance=new Test();

                   }

              }

        }

         return instance;

     }

}

双重检查锁定背后的理论是完美的。不幸地是,现实完全不同。双重检查锁定的问题是:并不能保证它会在单处理器或多处理器计算机上顺利运行。双重检查锁定失败的问题并不归咎于 JVM 中的实现 bug,而是归咎于 Java 平台内存模型。内存模型允许所谓的“无序写入”,这也是这些习语失败的一个主要原因。

多线程访问的时候会 返回一个非null但是没有被实例化的残缺对象

 

为避免单例中代价高昂的同步,程序员非常聪明地发明了双重检查锁定习语。不幸的是,鉴于当前的内存模型的原因,该习语尚未得到广泛使用,就明显成为了一种不安全的编程结构。重定义脆弱的内存模型这一领域的工作正在进行中。尽管如此,即使是在新提议的内存模型中,双重检查锁定也是无效的。对此问题最佳的解决方案是接受同步或者使用一个 static field

 

本文来自IBM一位开发工程师的日志 详情请参阅:http://www.ibm.com/developerworks/java/library/j-dcl.html 以及 http://ajava.org/course/java/13502.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值