现在的位置: 首页 > 综合 > 正文

java多线程环境下单利模式的实现

2018年02月16日 ⁄ 综合 ⁄ 共 1432字 ⁄ 字号 评论关闭

通常我们设计一个单例模式时,会在内部构造一个类,并对外提供一个static getInstance方法提供回去该单利对象的方法【ps这种方式我们也成为惰性加载】

   

public class Singleton {
    private static Singleton uniqueInstance = null;
 
    private Singleton() {
       // Exists only to defeat instantiation.
    }
 
    public static Singleton getInstance() {
       if (uniqueInstance == null) {
           uniqueInstance = new Singleton();
       }
       return uniqueInstance;
    }
    // Other methods...
}

但是这中方式在多线程中问题:

如果两个线程A和B同时执行了该方法,执行如下:  

    1: A线程进入if判断,此时fool为null,则进入if内部

    2: B线程进入if判断,此时A还没有创建fool,因此fool为null,所以B也进入if内部

   3: A创建了fool返回

   4:B创建了fool返回

  此时我们发现,我们的单例被创建了两次,这不是我们需要的结果

所以我们可以使用class的锁机制给getInstance方法加一个synchronize前缀,这样我们可以做到每次在同一时刻只允许一个线程调用getInstance

public class Singleton {
    private static Singleton uniqueInstance = null;
 
    private Singleton() {
       // Exists only to defeat instantiation.
    }
 
 //加入synchronized锁
    public static synchronized Singleton getInstance() {
       if (uniqueInstance == null) {
           uniqueInstance = new Singleton();
       }
       return uniqueInstance;
    }
    // Other methods...
}

这种解决方法可以防止错误的出现,但是最大的为题是影响性能:每次调用getInstance的时候必须获取synchronized锁,而实际上,当单例模式被创建后,其后的请求没必要再使用互斥机制了。。。

曾今有人使用过double-checked locking方法来解决这个为题【大家到网上搜索哈】

为了实现惰性加载,并且不希望每次调用getInstance都必须互斥,解决方案如下:

public class Singleton {
    private Singleton() {
       // Exists only to defeat instantiation.
    }
 
    private static class SingletoContainer(){
	     private static Singleton instance = new Singleton();
	 }

    public static  Singleton getInstance() {
       return SingletoContainer.instance;
    }
    // Other methods...
}

JVM内部的机制能够保证当一个类被加载的时候,这个类的加载过程是线程互斥的。这样,当我们第一次调用getInstance的时候,JVM能够帮助我们instance只被创建一次,并且会保证把赋值给instance的内存初始化完毕,该方法只会在第一次调用的时候互斥

抱歉!评论已关闭.