单例模式思考java并发

版权声明:原创文章,转载需注明转载出处! https://blog.csdn.net/zhoumingsong123/article/details/82832599
//First Version
public class SingletonKerriganA {     
      
    /**   
     * 单例对象实例   
     */    
    private static SingletonKerriganA instance = null;     
      
    public static SingletonKerriganA getInstance() {     
        if (instance == null) {                              //line A     
            instance = new SingletonKerriganA();          //line B     
        }     
        return instance;     
    }     
}     

//由于不支持并发,所以再改进

//Second Version
public class SingletonKerriganB {     
      
    /**   
     * 单例对象实例   
     */    
    private static SingletonKerriganB instance = null;     
      
    public synchronized static SingletonKerriganB getInstance() {     
        if (instance == null) {     
            instance = new SingletonKerriganB();     
        }     
        return instance;     
    }     
}    

//这里synchronized 保证对instance的赋值是原子的,可见的,有序的。
//但是性能不好,因为当第一次这个被new之后(需要做同步),以后多线程就不需要
//做同步(没有修改),直接返回即可。
//因此改成以下版本

//Third Version
public class SingletonKerriganD {     
      
    /**   
     * 单例对象实例   
     */    
    private static volatile SingletonKerriganD instance = null;  //这里为什么要加volatile,不加不行  
    //吗? 
   
   //因为这里instance是引用,其可以被两个线程同时拥有,因此两个线程都可以读取修改其对
   //象。所以得保证instance的修改立即可见。
   //(如果某个线程修改了变量,便立即将变量写回到主内存,
   //如果某个线程使用的话,都是从主内存读取值,x86处理器缓存一致性协议
   //注意:volatile并不保证对变量的操作是原子性的。)
  
  //对于基本类型变量可以直接从主内存复制到工作内存中然后修改。那对象怎么办,特别大的对象怎么解决?(猜测:每个对象最终也是基本类型组成的,只拷贝待修改的基本类型,最后写回)

 //当线程1在对instance赋值时(这个操作是原子的,中间不会被中断,但是instance应用在其他地方还有,所以别的线程可以偷窥到。)
 //另外一个线程可以通过instance来查看其引用的对象。(2,3可能存在重排序,3在前,所以并没有对对象进行初始化,而此时线程2已经读取到instance不为空直接返回,然后该线程就拥有违背初始化的对象,可能会造成严重错误。而使用了volatile,2,3就不会重排序(为什么通过volatile (cpu lock指令),可以实现2,3的不重排?不是只是通过lock来讲instance修改的结果立即写回到主内存嘛,2,3又没数据依赖),所以instance要么为null,要么指向已经初始化的对象。)
 
   
   
    
      
    public static SingletonKerriganD getInstance() {     
        if (instance == null) {     //当instance为空的时候,需要new ,要保证同步
            synchronized (SingletonKerriganD.class) {     
                if (instance == null) {     
                    instance = new SingletonKerriganD();   
                    //这条语句可以分配为三个操作
                    // 1.分配内存
                   //  2.   初始化对象
                   //  3.   将instance指向该内存。
                }     
            }     
        }     
        return instance;  //当instance不为空的时候直接返回,不需要线程同步   
    }     
} 

猜你喜欢

转载自blog.csdn.net/zhoumingsong123/article/details/82832599