1. 程式人生 > >單例模式之懶漢的併發問題,只需要新增一個 synchronized 就可以解決了

單例模式之懶漢的併發問題,只需要新增一個 synchronized 就可以解決了

復現併發問題:

package review.bank;

/**
 * Created by kodulf on 2017/2/26.
 */
public class SingleInstanceLazyMan {

    private SingleInstanceLazyMan(){

    }

    static SingleInstanceLazyMan singleInstanceLazyMan ;

    //synchronized 如果不新增,那麼會出現三個程序一起排程的情況
    public static SingleInstanceLazyMan getInstance(){
        if(singleInstanceLazyMan==null){
            System.out.println("before new "+Thread.currentThread().getName());
            System.out.println("before new "+Thread.currentThread().getName());
            System.out.println("before new "+Thread.currentThread().getName());
            System.out.println("before new "+Thread.currentThread().getName());
            System.out.println("before new "+Thread.currentThread().getName());
            System.out.println("before new "+Thread.currentThread().getName());
            System.out.println("before new "+Thread.currentThread().getName());
            System.out.println("before new "+Thread.currentThread().getName());
            System.out.println("before new "+Thread.currentThread().getName());
            System.out.println("before new "+Thread.currentThread().getName());
            System.out.println("before new "+Thread.currentThread().getName());
            System.out.println("before new "+Thread.currentThread().getName());
            System.out.println("before new "+Thread.currentThread().getName());
            System.out.println("before new "+Thread.currentThread().getName());
            System.out.println("before new "+Thread.currentThread().getName());
            System.out.println("before new "+Thread.currentThread().getName());
            System.out.println("before new "+Thread.currentThread().getName());
            System.out.println("before new "+Thread.currentThread().getName());
            System.out.println("before new "+Thread.currentThread().getName());
            System.out.println("before new "+Thread.currentThread().getName());

            singleInstanceLazyMan = new SingleInstanceLazyMan();

            System.out.println("after new "+Thread.currentThread().getName());
            System.out.println("after new "+Thread.currentThread().getName());
            System.out.println("after new "+Thread.currentThread().getName());
            System.out.println("after new "+Thread.currentThread().getName());
            System.out.println("after new "+Thread.currentThread().getName());
            System.out.println("after new "+Thread.currentThread().getName());
            System.out.println("after new "+Thread.currentThread().getName());
            System.out.println("after new "+Thread.currentThread().getName());
            System.out.println("after new "+Thread.currentThread().getName());
            System.out.println("after new "+Thread.currentThread().getName());
            System.out.println("after new "+Thread.currentThread().getName());
            System.out.println("after new "+Thread.currentThread().getName());
            System.out.println("after new "+Thread.currentThread().getName());
            System.out.println("after new "+Thread.currentThread().getName());
            System.out.println("after new "+Thread.currentThread().getName());
            System.out.println("after new "+Thread.currentThread().getName());
            System.out.println("after new "+Thread.currentThread().getName());
            System.out.println("after new "+Thread.currentThread().getName());
            System.out.println("after new "+Thread.currentThread().getName());
            System.out.println("after new "+Thread.currentThread().getName());
            System.out.println("after new "+Thread.currentThread().getName());

        }

        return singleInstanceLazyMan;
    }

}

新建三個程序去呼叫這個單例的getInstance方法

    public static  void testSingleInstance(){
        Thread thread1 = new Thread(new Runnable() {
            @Override
            public void run() {
                SingleInstanceLazyMan.getInstance();
            }
        });

        Thread thread2 = new Thread(new Runnable() {
            @Override
            public void run() {
                SingleInstanceLazyMan.getInstance();
            }
        });
        Thread thread3 = new Thread(new Runnable() {
            @Override
            public void run() {
                SingleInstanceLazyMan.getInstance();
            }
        });

        thread1.start();
        thread2.start();
        thread3.start();
    }


執行結果:會發現都呼叫了if == null的那個判斷了,就是執行了裡面的程式了

before new Thread-2
before new Thread-2
before new Thread-2
before new Thread-0
before new Thread-1
before new Thread-1
before new Thread-1
before new Thread-1
before new Thread-1
before new Thread-1
before new Thread-1
before new Thread-1
before new Thread-1
before new Thread-1
before new Thread-1
before new Thread-1
before new Thread-1
before new Thread-1
before new Thread-1
before new Thread-1
before new Thread-1
before new Thread-1
before new Thread-1
before new Thread-1
before new Thread-0
before new Thread-0
before new Thread-0
before new Thread-0
before new Thread-0
before new Thread-0
before new Thread-0
before new Thread-0
before new Thread-0
before new Thread-0
before new Thread-0
before new Thread-0
before new Thread-0
before new Thread-0
before new Thread-0
before new Thread-0
before new Thread-0
before new Thread-0
before new Thread-0
after new Thread-0
after new Thread-0
after new Thread-0
after new Thread-0
after new Thread-0
before new Thread-2
before new Thread-2
before new Thread-2
before new Thread-2
before new Thread-2
before new Thread-2
before new Thread-2
before new Thread-2
before new Thread-2
before new Thread-2
before new Thread-2
before new Thread-2
after new Thread-0
after new Thread-0
after new Thread-0
after new Thread-0
after new Thread-0
after new Thread-0
after new Thread-0
after new Thread-0
after new Thread-0
after new Thread-0
after new Thread-0
after new Thread-0
after new Thread-0
after new Thread-0
after new Thread-0
after new Thread-0
after new Thread-1
after new Thread-1
after new Thread-1
after new Thread-1
after new Thread-1
after new Thread-1
after new Thread-1
after new Thread-1
after new Thread-1
after new Thread-1
after new Thread-1
after new Thread-1
after new Thread-1
before new Thread-2
before new Thread-2
before new Thread-2
before new Thread-2
before new Thread-2
after new Thread-2
after new Thread-2
after new Thread-2
after new Thread-2
after new Thread-2
after new Thread-2
after new Thread-2
after new Thread-1
after new Thread-1
after new Thread-1
after new Thread-1
after new Thread-1
after new Thread-1
after new Thread-1
after new Thread-1
after new Thread-2
after new Thread-2
after new Thread-2
after new Thread-2
after new Thread-2
after new Thread-2
after new Thread-2
after new Thread-2
after new Thread-2
after new Thread-2
after new Thread-2
after new Thread-2
after new Thread-2
after new Thread-2

Process finished with exit code 0


要解決這個問題:

只需要新增一個單詞,synchronized 就可以了

package review.bank;

/**
 * Created by zhangyinshan on 2017/2/26.
 */
public class SingleInstanceLazyMan {

    private SingleInstanceLazyMan(){

    }

    static SingleInstanceLazyMan singleInstanceLazyMan ;

    //synchronized 如果不新增,那麼會出現三個程序一起排程的情況
    public static synchronized SingleInstanceLazyMan getInstance(){
        if(singleInstanceLazyMan==null){
            System.out.println("before new "+Thread.currentThread().getName());
            System.out.println("before new "+Thread.currentThread().getName());
            System.out.println("before new "+Thread.currentThread().getName());
            System.out.println("before new "+Thread.currentThread().getName());
            System.out.println("before new "+Thread.currentThread().getName());
            System.out.println("before new "+Thread.currentThread().getName());
            System.out.println("before new "+Thread.currentThread().getName());
            System.out.println("before new "+Thread.currentThread().getName());
            System.out.println("before new "+Thread.currentThread().getName());
            System.out.println("before new "+Thread.currentThread().getName());
            System.out.println("before new "+Thread.currentThread().getName());
            System.out.println("before new "+Thread.currentThread().getName());
            System.out.println("before new "+Thread.currentThread().getName());
            System.out.println("before new "+Thread.currentThread().getName());
            System.out.println("before new "+Thread.currentThread().getName());
            System.out.println("before new "+Thread.currentThread().getName());
            System.out.println("before new "+Thread.currentThread().getName());
            System.out.println("before new "+Thread.currentThread().getName());
            System.out.println("before new "+Thread.currentThread().getName());
            System.out.println("before new "+Thread.currentThread().getName());

            singleInstanceLazyMan = new SingleInstanceLazyMan();

            System.out.println("after new "+Thread.currentThread().getName());
            System.out.println("after new "+Thread.currentThread().getName());
            System.out.println("after new "+Thread.currentThread().getName());
            System.out.println("after new "+Thread.currentThread().getName());
            System.out.println("after new "+Thread.currentThread().getName());
            System.out.println("after new "+Thread.currentThread().getName());
            System.out.println("after new "+Thread.currentThread().getName());
            System.out.println("after new "+Thread.currentThread().getName());
            System.out.println("after new "+Thread.currentThread().getName());
            System.out.println("after new "+Thread.currentThread().getName());
            System.out.println("after new "+Thread.currentThread().getName());
            System.out.println("after new "+Thread.currentThread().getName());
            System.out.println("after new "+Thread.currentThread().getName());
            System.out.println("after new "+Thread.currentThread().getName());
            System.out.println("after new "+Thread.currentThread().getName());
            System.out.println("after new "+Thread.currentThread().getName());
            System.out.println("after new "+Thread.currentThread().getName());
            System.out.println("after new "+Thread.currentThread().getName());
            System.out.println("after new "+Thread.currentThread().getName());
            System.out.println("after new "+Thread.currentThread().getName());
            System.out.println("after new "+Thread.currentThread().getName());

        }

        return singleInstanceLazyMan;
    }

}


執行結果:只調用了一次,這個就是我們想要的

before new Thread-0
before new Thread-0
before new Thread-0
before new Thread-0
before new Thread-0
before new Thread-0
before new Thread-0
before new Thread-0
before new Thread-0
before new Thread-0
before new Thread-0
before new Thread-0
before new Thread-0
before new Thread-0
before new Thread-0
before new Thread-0
before new Thread-0
before new Thread-0
before new Thread-0
before new Thread-0
after new Thread-0
after new Thread-0
after new Thread-0
after new Thread-0
after new Thread-0
after new Thread-0
after new Thread-0
after new Thread-0
after new Thread-0
after new Thread-0
after new Thread-0
after new Thread-0
after new Thread-0
after new Thread-0
after new Thread-0
after new Thread-0
after new Thread-0
after new Thread-0
after new Thread-0
after new Thread-0
after new Thread-0

Process finished with exit code 0