单例与多线程

单例的两种实现:

1、立即加载(饿汉模式)

public class Singleton {

    private static Singleton singleton = new Singleton();
    private Singleton(){

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

在方法调用之前,就已经创建好了实例,故不存在多线程安全的问题。

2、延迟加载(懒汉模式)

public class Singleton {

    private static Singleton singleton ;
    private Singleton(){

    }
    public static Singleton getInstance(){
        if(singleton == null){
            singleton = new Singleton();
        }
        return singleton;
    }
}

延迟加载的缺点:在多线程的情况下,无法保证单例,会创建出“多例”。

测试:

public class Singleton {

    private static Singleton singleton ;
    private Singleton(){

    }
    public static Singleton getInstance(){
        try {
            if(singleton == null){
                Thread.sleep(3000);
                singleton = new Singleton();
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return singleton;
    }
}
public class MyThread extends Thread {

    @Override
    public void run() {
        System.out.println(Singleton.getInstance().hashCode());
    }
}
public class Run {

    public static void main(String[] args) {
        MyThread myThread1 = new MyThread();
        MyThread myThread2 = new MyThread();
        MyThread myThread3 = new MyThread();

        myThread1.start();
        myThread2.start();
        myThread3.start();

    }

}

测试结果;

结果打印出了两种hashCode,说明创建了两个对象,并非单例。

解决方案:

1、采用同步方法

synchronized  public static Singleton getInstance(){
        try {
            if(singleton == null){
                Thread.sleep(3000);
                singleton = new Singleton();
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return singleton;
    }

此方法是直接锁住了一个方法,粒度有点大,同步运行,效率非常低,当下一个线程想要获取对象,必须得等到上一个线程释放锁,才可以继续执行。

2、使用双检查锁

public static Singleton getInstance(){
        try {
            if(singleton == null){
                Thread.sleep(3000);
                synchronized (Singleton.class){
                    if(singleton == null){
                        singleton = new Singleton();
                    }
                }
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return singleton;
    }

此方法只是锁住了部分代码,效率明显提高。

猜你喜欢

转载自blog.csdn.net/yu532164710/article/details/82764153