单例模式与DCL

相信单例模式大家已经不陌生, 是比较常见的几种模式之一,在spring中默认的bean都是单例.


下面对该模式做下回顾与总结.


主要分为饿汉式和懒汉式, 饿汉式是在类加载时进行初始化, 懒汉式是延迟加载, 当第一次调用时,进行初始化.


单例模式需要注意的是: 


1. 要有私有构造方法, 避免外部直接实例化.

2. 要有静态的getInstance()方法.

 

3. 对于懒汉式, 要在getInstance()方法前加上同步, 避免多线程环境下出现并发问题.


单例模式基本传统实现: 
 

//饿汉式 
public class Singleton { 

  //将构造函数私有化 
  private Singleton(){ } 

  private static Singleton instance = new Singleton(); 

  public static Singleton getInstance() { 
     return instance; 
  } 
} 




//懒汉式 
public class Singleton1 { 

  private static Singleton1 instance = null; 

  //将构造函数私有化 
  private Singleton(){ } 



  public  static synchronized Singleton1 getInstance() { 
    if(instance == null){ 
     instance = new Singleton1(); 
    } 
    return instance; 
  } 
} 



 

 这个实现对于懒汉式有个问题, 就是同步了整个方法, 这样锁的粒度过大, 会影响多线程环境下的效率. 这样, 我们可以采用DCL模式进行细粒度的加锁. 如下.

 

public class Singleton {   
       
    private static volatile Singleton st;   
  
       private Singleton (){}   
  
    public static Singleton getInstance() {   
        if (null == st) {   
            synchronized (Singleton.class) {   
                if (st == null) {   
                    st = new Singleton();   
                    return st;   
                }   
            }   
        }   
        return st;   
    }   
}  

 

 注意: 此种DCL模式只有在jdk1.4 之后才有效, 因为java5对内存模型作了重要的改动,其中最主要的改动就是对volatile和final语义的改变.

 

在java 5中多增加了一条happen-before规则:

  • 对volatile字段的写操作happen-before后续的对同一个字段的读操作。

利用这条规则我们可以将instance声明为volatile.

 

关于happen-before

 

我们一般说一个操作happen-before另一个操作,这到底是什么意思呢?当说操作A happen-before操作B时,我们其实是在说在发生操作B之前,操作A对内存施加的影响能够被观测到。所谓“对内存施加的影响”就是指对变量的写入,“被观测到”指当读取这个变量时能够得到刚才写入的值(如果中间没有发生其它的写入)。

 

下面是我列出的三条非常重要的happen-before规则,利用它们可以确定两个操作之间是否存在happen-before关系。

  1. 同一个线程中,书写在前面的操作happen-before书写在后面的操作。这条规则是说,在单线程 中操作间happen-before关系完全是由源代码的顺序决定的,这里的前提“在同一个线程中”是很重要的,这条规则也称为单线程规则 。这个规则多少说得有些简单了,考虑到控制结构和循环结构,书写在后面的操作可能happen-before书写在前面的操作,不过我想读者应该明白我的意思。
  2. 对锁的unlock操作happen-before后续的对同一个锁的lock操作。这里的“后续”指的是时间上的先后关系,unlock操作发生在退出同步块之后,lock操作发生在进入同步块之前。这是条最关键性的规则,线程安全性主要依赖于这条规则。但是仅仅是这条规则仍然不起任何作用,它必须和下面这条规则联合起来使用才显得意义重大。这里关键条件是必须对“同一个锁”的lock和unlock。
  3. 如果操作A happen-before操作B,操作B happen-before操作C,那么操作A happen-before操作C。这条规则也称为传递规则。

 

还有一种利用延迟加载实现懒汉式单例模式的例子:

 

public class Singleton4 {   
       
    private static class SingletonHolder {   
        public static final Singleton4 INSTANCE = new Singleton4();   
    }   
       
    private Singleton4() {}   
       
    public static Singleton4 getInstance() {   
        return SingletonHolder.INSTANCE;   
    }   
}  

 

 

推荐一篇好文:

http://soongbo.iteye.com/blog/1343683

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值