单例设计模式线程安全问题

单例设计模式线程安全问题

懒汉式

class Lazy {
    private Lazy(){
        System.out.println("test Lazy");
    }
    private  static Lazy lazy=null;
    public static Lazy getInstance(){
        if(lazy==null){
            lazy=new Lazy();
        }
      return lazy;
    }
}

懒汉式先声明一个private对象,对象为空,静态方法中判断是否为空,如果为空,则new一个对象给声明的private对象,并返回该对象。

分析

单线程:此状态下是安全的,第一次调用静态方法之后,“lazy”就不为空了,第二次调用静态方法的时候,判断"lazy"不为空,返回该对象,和第一次调用静态方法产生的对象是同一个。

多线程:此状态下是不安全的,若多个线程一开始同时进入静态方法中,对"lazy"进行判断,全部线程都判断为空,那么都会创造一个对象,那么就破坏了单例。

改进方案:

 class Lazy {
         private static volatile Lazy instance = null;
          private Lazy() {
              System.out.println("test Lazy");
          }
         public static Lazy getInstance() {
         if (instance == null) {
             synchronized(Lazy.class){
                 if(instance==null)
                     instance=new Lazy();
                }
            }
         return instance;
         }
 }

分析: 声明私有对象的时候加上了volatile,为了保证 "instance=new Lazy();" 这一句不会被指令重排,保证了其原子性,其次用了synchronized来加锁,当初次多个线程进来时,开始时判断 "instance" 为空,多个线程进入,然后只有一个线程获得锁,该线程进去之后再次判断是否为空,为空,new一个对象赋给 "instance",释放锁,然后第二个抢到锁的,进去发现 "instance" 已经不为空了,释放锁,所有的线程都出来之后,返回 "instance"。

饿汉式

class Hungry {
    private Hungry(){
        System.out.println("test Hungry");
    }
    private  static Hungry hungry=new Hungry();
    public static Hungry get(){
        return hungry3;
    }
}

分析: 因为实例声明为static,且被实例化,在类加载的时候就已经被加载完成,还未使用该类的时候就已经创建好了实例,而且只有一个实例,就算多个线程进来也无法创建新的实例,所以多线程时是安全的,但是,未使用的时候就创建了实例,会浪费空间,造成内存不必要的消耗。

枚举类型

 enum EnumTest{
    INSTANCE;
    public  EnumTest getInstance(){
    return INSTANCE;
    }
}
上一篇:gmoj 6808. 【2020.10.29提高组模拟】easy


下一篇:【洛谷P2710】数列