Java 设计模式 单例模式

通常单例模式在Java语言中,有两种构建方式:
  • 懒汉方式:指全局的单例实例在第一次被使用时构建。延迟初始化
  • 饿汉方式:指全局的单例实例在类装载时构建。 急切初始化
1,饿汉式单例类

/**
 * 饿汉模式,是线程安全的,但是性能不好
 *   @author   Administrator
 */
public   class   StarvingSingleton {
       // 私有化构造函数
       private   StarvingSingleton(){}
       // 类加载时 即初始化
       private   static   final   StarvingSingleton   INSTANCE   =   new   StarvingSingleton();
       public   static   StarvingSingleton getInstance(){
               return   INSTANCE ;
      }
}
2,懒汉式单例类
/**
 * 懒汉模式,在使用时在初始化,有多线程问题,需要做同步处理
 *   @author   Administrator
 */
public   class   LazySingletion {
      //属性instatnce是被volatile修饰的,因为volatile具有synchronized的可见性特点,
       //也就是说线程能够自动发现volatile变量的最新值。
       //这样,如果instatnce 实例化成功,其他线程便能立即发现。
       private   static   volatile   LazySingletion   INSTANCE   =   null ;
       private   LazySingletion(){}
       //做双重检查
       public   static   LazySingletion getInstance(){
               if (   INSTANCE   ==   null ){
                     synchronized   (LazySingletion.   class ) {
                           if (   INSTANCE   ==   null ){
                                 INSTANCE   =   new   LazySingletion(){};
                        }
                  }
            }
               return   INSTANCE ;
      }
}

volatile  

volatile, 用更低的代价替代同步

为什么使用volatile比同步代价更低?
同步的代价, 主要由其覆盖范围决定, 如果可以降低同步的覆盖范围, 则可以大幅提升程序性能.而volatile的覆盖范围仅仅变量级别的. 因此它的同步代价很低.

volatile原理是什么?
volatile的语义, 其实是告诉处理器, 不要将我放入工作内存, 请直接在主存操作我.(工作内存详见java内存模型).因此, 当多核或多线程在访问该变量时, 都将直接
操作主存, 这从本质上, 做到了变量共享.

volatile的有什么优势?
1, 更大的程序吞吐量
2, 更少的代码实现多线程
3, 程序的伸缩性较好
4, 比较好理解, 无需太高的学习成本

volatile有什么劣势?
1, 容易出问题
2, 比较难设计

volatile使用jdk要求1.5版本及1.5以上,因为  out-of-order writes   问题
这是由于Java平台的内存模式容许out-of-order writes引起的,假定有两个线程,Thread 1和Thread 2,它们执行以下步骤:
1.     Thread 1发现instatnce没有被实例化,它获得锁并去实例化此对象,JVM容许在没有完全实例化完成时,instance变量就指向此实例,因为这些步骤可以是out-of-order writes的,此时instance==null为false,之前的版本即使用volatile关键字修饰也无效。
2.     在初始化完成之前,Thread 2进入此方法,发现instance已经不为null了,Thread 2便认为该实例初始化完成了,使用这个未完全初始化的实例对象,则很可能引起系统的崩溃。 

现在流行用枚举类型做
public   enum   EnumSingletion {
       INSTANCE ;
}

默认枚举实例的创建是线程安全的,但是在枚举中的其他任何方法由程序员自己负责。

传统单例存在的另外一个问题是一旦你实现了序列化接口,那么它们不再保持单例了,因为readObject()方法一直返回一个新的对象就像java的构造方法一样,你可以通过使用readResolve()方法来避免此事发生,看下面的例子:
private Object   readResolve(){
        return INSTANCE;
    }
 但是枚举单例,JVM对序列化有保证


参考:
http://www.importnew.com/6461.html
http://www.importnew.com/6662.html


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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值