單例模式之懶漢的併發問題,只需要新增一個 synchronized 就可以解決了
阿新 • • 發佈:2019-01-09
復現併發問題:
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