概念
synchronized 是 Java 中的關鍵字,是利用鎖的機制來實現同步的。
鎖機制有如下兩種特性:
-
互斥性:即在同一時間只允許一個線程持有某個對象鎖,通過這種特性來實現多線程中的協調機制,這樣在同一時間只有一個線程對需同步的代碼塊(復合操作)進行訪問。互斥性我們也往往稱為操作的原子性。
-
可見性:必須確保在鎖被釋放之前,對共享變量所做的修改,對於隨后獲得該鎖的另一個線程是可見的(即在獲得鎖時應獲得最新共享變量的值),否則另一個線程可能是在本地緩存的某個副本上繼續操作從而引起不一致。
對象鎖
synchronized修飾非靜態方法時是對象鎖,等同於synchronized(this),在同一個對象中是線程安全的。
package com.dwz.concurrency.chapter7; /** * 兩個方法鎖定的都是this即同一個對象thisLock, * 同時調用的結果是一個執行完再執行下一個 */ public class SynchronizedThis { public static void main(String[] args) { ThisLock thisLock = new ThisLock(); new Thread("T1") { @Override public void run() { thisLock.m1(); } }.start(); new Thread("T2") { @Override public void run() { thisLock.m2(); } }.start(); } } class ThisLock {
public synchronized void m1() { try { System.out.println(Thread.currentThread()); Thread.sleep(10_000); } catch (InterruptedException e) { e.printStackTrace(); } } public synchronized void m2() { try { System.out.println(Thread.currentThread()); Thread.sleep(10_000); } catch (InterruptedException e) { e.printStackTrace(); } } }
執行結果:m1和m2先后執行
package com.dwz.concurrency.chapter7; /** * 鎖定的是兩個不同的對象,沒有起到鎖的作用,還是多線程執行 */ public class SynchronizedThis2 { public static void main(String[] args) { ThisLock2 thisLock = new ThisLock2(); new Thread("T1") { @Override public void run() { thisLock.m1(); } }.start(); new Thread("T2") { @Override public void run() { thisLock.m2(); } }.start(); } } class ThisLock2 { private final Object LOCK = new Object(); public void m2() { synchronized (LOCK) { try { System.out.println(Thread.currentThread()); Thread.sleep(10_000); } catch (InterruptedException e) { e.printStackTrace(); } } } public void m1() { synchronized (this) { try { System.out.println(Thread.currentThread()); Thread.sleep(10_000); } catch (InterruptedException e) { e.printStackTrace(); } } } }
執行結果:m1和m2同時執行
類鎖
synchronized修飾靜態方法時是類鎖,等同於synchronized(類.class),是線程安全的。
package com.dwz.concurrency.chapter7; public class SynchronizedStatic { public synchronized static void m1() { System.out.println("m1" + Thread.currentThread()); try { Thread.sleep(10_000); } catch (InterruptedException e) { e.printStackTrace(); } } public synchronized static void m2() { System.out.println("m2" + Thread.currentThread()); try { Thread.sleep(10_000); } catch (InterruptedException e) { e.printStackTrace(); } } public synchronized static void m3() { System.out.println("m3" + Thread.currentThread()); try { Thread.sleep(10_000); } catch (InterruptedException e) { e.printStackTrace(); } } }
測試類
package com.dwz.concurrency.chapter7; public class SynchronizedTest2 { public static void main(String[] args) { new Thread("T1") { @Override public void run() { SynchronizedStatic.m1(); }; }.start(); new Thread("T2") { @Override public void run() { SynchronizedStatic.m2(); }; }.start(); new Thread("T3") { @Override public void run() { SynchronizedStatic.m3(); }; }.start(); } }
執行結果:T1 T2 T3是先后執行的
總結
1、對於靜態方法,由於此時對象還未生成,所以只能采用類鎖;
2、只要采用類鎖,就會攔截所有線程,只能讓一個線程訪問。
3、對於對象鎖(this),如果是同一個實例,就會按順序訪問,但是如果是不同實例,就可以同時訪問。
4、如果對象鎖跟訪問的對象沒有關系,那么就會都同時訪問。