在同步塊中修改指向同步對象的引用

原由

最近上網忽然看到別人提的一個問題,感受蠻有趣的,本身重來沒有想過.java

把它抽象出來就是:若是我再synchronized中鎖住了一個對象,而後在同步塊中修改了指向這個對象的引用會怎麼樣?ide

 

實驗

 1 public class SynchronizedTest1 implements Runnable {
 2     public static Object lock = new Object();
 3 
 4     @Override
 5     public void run() {
 6         synchronized (lock) {
 7             System.out.println(Thread.currentThread().getName() + lock);
 8             lock = new Object();
 9             try {
10                 Thread.sleep(1000);
11             } catch (InterruptedException e) {
12                 // TODO Auto-generated catch block
13                 e.printStackTrace();
14             }
15             System.out.println(Thread.currentThread().getName() + lock);
16         }
17     }
18 
19     public static void main(String[] args) {
20         Thread t1 = new Thread(new SynchronizedTest1());
21         Thread t2 = new Thread(new SynchronizedTest1());
22         t1.start();
23         t2.start();
24     }
25 
26 }

可能的輸出:spa

Thread-0java.lang.Object@153bcbc8
Thread-1java.lang.Object@8bfc25c
Thread-0java.lang.Object@65712a80
Thread-1java.lang.Object@65712a80線程

這說明在線程0作完lock=new Object()的時候,線程1能夠馬上進入同步塊.code

 

另外1個例子:對象

 1 public class SynchronizedTest2 implements Runnable {
 2     public static String lock = "123";
 3 
 4     @Override
 5     public void run() {
 6         synchronized (lock) {
 7             System.out.println(Thread.currentThread().getName() + lock);
 8             lock = "123";
 9             try {
10                 Thread.sleep(1000);
11             } catch (InterruptedException e) {
12                 // TODO Auto-generated catch block
13                 e.printStackTrace();
14             }
15             System.out.println(Thread.currentThread().getName() + lock);
16         }
17     }
18 
19     public static void main(String[] args) {
20         Thread t1 = new Thread(new SynchronizedTest2());
21         Thread t2 = new Thread(new SynchronizedTest2());
22         t1.start();
23         t2.start();
24     }
25 
26 }

輸出:blog

Thread-0123
Thread-0123
Thread-1123
Thread-1123get

線程0和線程1不會交叉輸出.同步

 

結論

2個例子的差異就是第二個例子裏由於有常量池的緣由,lock永遠指向的是同一個String對象,因此雖然在線程0中修改了lock的指向,可是仍是指向了同一個String對象,因此線程1仍是在synchronized那裏阻塞.io

而在例子一中,當lock=new Object()的時候線程1能夠便可進入synchronized,由於這個時候線程1synchronzed的對象已經和線程0synchronized的對象不一樣了.

這2個例子說明鎖是鎖在對象上的,而不是引用上的.

相關文章
相關標籤/搜索