一、原始構成
synchronized是關鍵字屬於JVM層面,monitorenter(底層是通過monitor對象來完成,其實wait/notify等方法也依賴monitor對象只有在同步代碼塊和同步方法中才能調用wait/notify等方法)
Lock是具體的類,是api層面的鎖;
二、使用方法
synchronized不需要用戶手動釋放鎖,synchronized代碼執行完成以后系統會自動讓線程釋放對鎖的占有
ReentrantLock則需要用戶手動去釋放鎖,若沒有主動釋放鎖,就有可能導致死鎖現象。需要使用lock()和unlock()方法配合try finally語句塊來完成。
三、等待是否可以中斷
synchronized不可中斷,除非拋出異常或者正常運行完成。
ReetrantLock可中斷,
1. 設置超時方法tryLock(long timeout, TimeUnit unit);
2.lockInterruptibly()放入代碼塊中,調用interrupt()方法可中斷;
四、加鎖是否公平
synchronized是非公平鎖
ReentrantLock默認是非公平鎖,可設置為公平鎖。
五、鎖綁定多個條件condition
synchronized沒有;
ReentrantLock用來實現分組喚醒需要喚醒的線程們,可以精確喚醒,而不是像synchronized要么隨機喚醒一個,要么喚醒全部線程。
六、案例
題目:多線程之間按找順序調用,實現A->B->C三個線程啟動,要求如下:
AA打印5次,BB打印10次,CC打印15次,重復上述過程10次.
class ShareResource{ private int number = 1; // A:1, B:2, C:3 private Lock lock = new ReentrantLock(); private Condition conditionA = lock.newCondition(); private Condition conditionB = lock.newCondition(); private Condition conditionC = lock.newCondition(); public void print5(){ try { lock.lock(); while (number != 1){ conditionA.await(); } for (int i = 1; i <= 5; i++){ System.out.print("A"); } System.out.println(); number++; conditionB.signal(); } catch (InterruptedException e) { e.printStackTrace(); } finally { lock.unlock(); } } public void print10(){ try { lock.lock(); while (number != 2){ conditionB.await(); } for (int i = 1; i <= 10; i++){ System.out.print("B"); } System.out.println(); number++; conditionC.signal(); } catch (InterruptedException e) { e.printStackTrace(); } finally { lock.unlock(); } } public void print15(){ try { lock.lock(); while (number != 3){ conditionC.await(); } for (int i = 1; i <= 15; i++){ System.out.print("C"); } System.out.println(); number = 1; conditionA.signal(); } catch (InterruptedException e) { e.printStackTrace(); } finally { lock.unlock(); } } } public class SynchronizedLockDifference { public static void main(String[] args) { ShareResource shareResource = new ShareResource(); new Thread(()->{ for (int i = 1; i <= 10; i++){ shareResource.print5(); } }, "A").start(); new Thread(()->{ for (int i = 1; i <= 10; i++){ shareResource.print10(); } }, "B").start(); new Thread(()->{ for (int i = 1; i <= 10; i++){ shareResource.print15(); } }, "C").start(); } }
輸出結果:
AAAAA
BBBBBBBBBB
CCCCCCCCCCCCCCC
AAAAA
BBBBBBBBBB
CCCCCCCCCCCCCCC
AAAAA
BBBBBBBBBB
CCCCCCCCCCCCCCC
AAAAA
BBBBBBBBBB
CCCCCCCCCCCCCCC
AAAAA
BBBBBBBBBB
CCCCCCCCCCCCCCC
AAAAA
BBBBBBBBBB
CCCCCCCCCCCCCCC
AAAAA
BBBBBBBBBB
CCCCCCCCCCCCCCC
AAAAA
BBBBBBBBBB
CCCCCCCCCCCCCCC
AAAAA
BBBBBBBBBB
CCCCCCCCCCCCCCC
AAAAA
BBBBBBBBBB
CCCCCCCCCCCCCCC
Process finished with exit code 0