单例模式的懒汉式的线程安全版本

使用同步机制将单例模式中的懒汉式改写为线程安全的

public class BankTest {


}
class Bank{

    private Bank(){


    }
    private static Bank instance=null;

    public static Bank getInstance(){

        if(instance==null){
            //说明之前没有被创建
            instance=new Bank();
        }
        return instance;
    }

}

要求Bank这个类是单例的
如果在run方法中调用了getInstance方法,创建多个线程,在各自的run方法中,各自又调了getInstance。首次调用的时候instance是null,最开始的那个线程就进入了if语句,但进去之后可能就阻塞了,即使不阻塞,CPU也可能切换到其他的线程,使得当前线程进入就绪状态,另外的线程就进来了。同样判断instance还是null,所以也进入了if,所以会造出不止一个对象,就不是单例模式了

出现了线程的安全问题,因为存在共享数据为instance
注意return instance虽然用了共享数据,但不算是对共享数据的操作,但是判断和赋值都是明显的对共享数据进行操作
方法一:使用同步方法,声明为synchronized:

静态同步方法的锁是当前类本身Bank.class

class Bank{

    private Bank(){


    }
    private static Bank instance=null;

    public static synchronized Bank getInstance(){

        if(instance==null){
            //说明之前没有被创建
            instance=new Bank();
        }
        return instance;
    }

}

第一个进入的线程之后的其他线程进入进行判断if得到的结果都是false,直接就return

第二种方法:使用同步代码块:
快速形成同步代码块的方法,选中同步代码块中的代码,Alt+shift+z,再点击synchronized即可

class Bank{

    private Bank(){


    }
    private static Bank instance=null;

    public static  Bank getInstance(){

        synchronized (Bank.class) {
            if(instance==null){
                //说明之前没有被创建
                instance=new Bank();
            }
            return instance;
        }

    }
}

还有效率更高的方法:
本质上第一个进入的线程执行完之后对象就创建好了,那么其他的线程只要不是第一个线程就可以直接拿对象走了,因为对象已经造好了,没有必要等了,所以可以把同步代码块包小一点,换句话说可以不把return instance看成是对共享数据的操作
最外层的if因为没有加同步所以都能判断,在同步代码块开始的地方就开始抢锁,假设线程一抢到了,new完之后返回对象,已经来到同步代码块头处的线程是需要等线程1的。但如果是再后来的线程,他们去判断if就已经不是null了,所以直接return而不会到同步代码块头等着了

class Bank{

    private Bank(){


    }
    private static Bank instance=null;

    public static  Bank getInstance(){

        if(instance==null) {
            synchronized (Bank.class) {
                if (instance == null) {//注意,不能把里面的if删掉
                    //说明之前没有被创建
                    instance = new Bank();
                }
            }

        }
        return instance;
    }
}

写的时候建议写这种写法,效率比较高

上一篇:常见JS


下一篇:数据库模拟银行业务(二)