底層是monitor
監視器,每個對象再建立的時候都會常見一個monitor
監視器,在使用synchronized
代碼塊的時候,會在代碼塊的先後產生一個monitorEnter和monitorexit
指令,來標識這是一個同步代碼塊。java
線程遇到同步代碼塊,給這個對象monitor
對象加1
,當線程退出當前代碼塊之後,給這個對象的monitor
對象減一,若是monitor
指令的值爲0
則當前線程釋放鎖。node
同步代碼塊反編譯安全
public void test01(){ synchronized (this){ int num = 1 ; } }
兩次monitorexit
的做用是避免同步代碼塊沒法跳出,所以存在兩種,正常退出和異常退出性能
同步方法反編譯優化
public synchronized void test01(){ int num = 1 ; }
能夠發現其沒有在同步方法先後添加monitor
指令,可是在其底層實際上也是經過monitor
指令實現的,只不過相較於同步代碼塊來講,他是隱式的。ui
在JDK1.5
的時候對於synchronzied
作了一系列優化操做,增長了諸如:偏向鎖,輕量級鎖,自旋鎖,鎖粗化,重量級鎖的概念。this
在一個線程在執行獲取鎖的時候,當前線程會在monitor
對象中存儲指向該線程的ID。當線程再次進入的時候,不須要經過CAS的方法再來進行加鎖或者解鎖,而是檢測偏向鎖的ID是否是當前要進行的線程,若是是,直接進入。spa
偏向鎖,適用於一個線程執行任務的狀況線程
在JDK1.6
中,默認是開啓的。能夠經過-XX:-UseBiasedLocking=false
參數關閉偏向鎖code
輕量級鎖是指鎖爲偏向鎖的時候,該鎖被其餘線程嘗試獲取,此時偏向鎖升級爲輕量級鎖,其餘線程會經過自旋的方式嘗試獲取鎖,線程不會阻塞,從而提供性能
升級爲輕量級鎖的狀況有兩種:
具體實現:
線程進行代碼塊之後,若是同步對象鎖狀態爲無鎖的狀態,虛擬機將首先在當前線程的棧幀中建立一個鎖記錄的空間。這個空間內存儲了當前獲取鎖的對象。
使用狀況:
兩個線程的互相訪問
在有超過2個線程訪問同一把鎖的時候,鎖自動升級爲重量級鎖,也就是傳統的synchronized
,此時其餘未獲取鎖的線程會陷入等待狀態,不可被中斷。
因爲依賴於monitor
指令,因此其消耗系統資源比較大
上面的三個階段就是鎖升級的過程
當在一個循環中,咱們屢次使用對同一個代碼進行加鎖,這個時候,JVM會自動實現鎖粗化,即在循環外進行添加同步代碼塊。
代碼案例:
鎖粗化以前:
for (int i = 0; i < 10; i++) { synchronized (LockBigDemo.class){ System.out.println(); } }
鎖粗化以後:
synchronized (LockBigDemo.class){ for (int i = 0; i < 10; i++) { System.out.println(); } }
本次關於synchronized
的底層原理沒有以代碼的方式展開,以後筆者會出一篇synchronized
底層原理剖析的文章
一個類級別的鎖,須要手動釋放鎖。能夠選擇性的選擇設置爲公平鎖或者不公平鎖。等待線程能夠被打斷。
底層是基於AQS
+AOS
。AQS
類完成具體的加鎖邏輯,AOS
保存獲取鎖的線程信息
咱們以ReentrantLock
爲例解析一下其加鎖的過程。
首先經過ReentrantLock
的構造方法的布爾值判斷建立的鎖是公平鎖仍是非公平鎖。
假設如今建立的是非公平鎖,他首先會判斷鎖有沒有被獲取,若是沒有被獲取,則直接獲取鎖;
若是鎖已經被獲取,執行一次自旋,嘗試獲取鎖。
若是鎖已經被獲取,則將當前線程封裝爲AQS
隊列的一個節點,而後判斷當前節點的前驅節點是否是HEAD
節點,若是是,嘗試獲取鎖;若是不是。則尋找一個安全點(線程狀態位SIGNAL=-1
的節點)。
開始不斷自旋。判斷前節點是否是HEAD
節點,若是是獲取鎖,若是不是掛起。
源碼解讀:
lock
final void lock() { //判斷是否存在鎖 if (compareAndSetState(0, 1)) //獲取鎖 setExclusiveOwnerThread(Thread.currentThread()); else acquire(1); }
public final void acquire(int arg) { if (!tryAcquire(arg) && acquireQueued(addWaiter(Node.EXCLUSIVE), arg)) selfInterrupt(); }
//非公平鎖的自旋邏輯 protected final boolean tryAcquire(int acquires) { return nonfairTryAcquire(acquires); } final boolean nonfairTryAcquire(int acquires) { final Thread current = Thread.currentThread(); //獲取鎖狀態 int c = getState(); //若是鎖沒被獲取,獲取鎖 if (c == 0) { if (compareAndSetState(0, acquires)) { setExclusiveOwnerThread(current); return true; } } //當前線程已經獲取到了鎖 else if (current == getExclusiveOwnerThread()) { //線程進入次數增長 int nextc = c + acquires; if (nextc < 0) // overflow throw new Error("Maximum lock count exceeded"); setState(nextc); return true; } return false; }
//將線程封裝爲一個線程節點,傳入鎖模式,排他或者共享 private Node addWaiter(Node mode) { Node node = new Node(Thread.currentThread(), mode); // 獲取尾節點 Node pred = tail; //若是尾節點不爲Null,直接將這個線程節點添加到隊尾 if (pred != null) { node.prev = pred; if (compareAndSetTail(pred, node)) { pred.next = node; return node; } } //爲空,自旋設置尾節點 enq(node); return node; } private Node enq(final Node node) { for (;;) { Node t = tail; //初始化 if (t == null) { // Must initialize if (compareAndSetHead(new Node())) tail = head; } else { node.prev = t; //將頭結點和尾結點都設置爲當前節點 if (compareAndSetTail(t, node)) { t.next = node; return t; } } } }
//嘗試入隊 final boolean acquireQueued(final Node node, int arg) { boolean failed = true; try { boolean interrupted = false; for (;;) { //獲取節點的前驅節點,若是前驅節點爲head節點,則嘗試獲取鎖 final Node p = node.predecessor(); if (p == head && tryAcquire(arg)) { setHead(node); p.next = null; // help GC failed = false; return interrupted; } //若是不是,尋找安全位 if (shouldParkAfterFailedAcquire(p, node) && parkAndCheckInterrupt()) interrupted = true; } } finally { if (failed) cancelAcquire(node); } }
private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) { int ws = pred.waitStatus; //前驅節點已經安全 if (ws == Node.SIGNAL) return true; //前驅節點不安全,尋找一個線程狀態爲`Signal`的節點做爲前驅節點 if (ws > 0) { do { node.prev = pred = pred.prev; } while (pred.waitStatus > 0); pred.next = node; } else { //不然直接設置這個前驅節點的線程等待狀態值 compareAndSetWaitStatus(pred, ws, Node.SIGNAL); } return false; } //中斷線程 private final boolean parkAndCheckInterrupt() { LockSupport.park(this); return Thread.interrupted(); }
代碼解讀:
public void unlock() { sync.release(1); }
public final boolean release(int arg) { //嘗試釋放鎖 if (tryRelease(arg)) { //獲取隊列頭元素,喚醒該線程節點,執行任務 Node h = head; if (h != null && h.waitStatus != 0) unparkSuccessor(h); return true; } return false; }
protected final boolean tryRelease(int releases) { int c = getState() - releases; //判斷是否爲當前線程擁有鎖 if (Thread.currentThread() != getExclusiveOwnerThread()) throw new IllegalMonitorStateException(); boolean free = false; //釋放成功 if (c == 0) { free = true; setExclusiveOwnerThread(null); } setState(c); return free; }
private void unparkSuccessor(Node node) { int ws = node.waitStatus; if (ws < 0) compareAndSetWaitStatus(node, ws, 0); Node s = node.next; if (s == null || s.waitStatus > 0) { s = null; for (Node t = tail; t != null && t != node; t = t.prev) if (t.waitStatus <= 0) s = t; } //喚醒下一個節點 if (s != null) LockSupport.unpark(s.thread); }
/** 共享鎖,讀鎖使用 */ static final Node SHARED = new Node(); /** 獨佔鎖*/ static final Node EXCLUSIVE = null; /** 不安全線程 */ static final int CANCELLED = 1; /** 須要進行線程喚醒的線程 */ static final int SIGNAL = -1; /**condition等待中 */ static final int CONDITION = -2; //線程等待狀態 volatile int waitStatus; volatile Node prev; volatile Node next; volatile Thread thread; Node nextWaiter;
Lock
鎖是API層面,synchronized
是CPU
源語級別的Lock
鎖等待線程能夠被中斷,synchronized
等待線程不能夠被中斷Lock
鎖能夠指定公平鎖和非公平鎖,synchronized
只能爲非公平鎖Lock
鎖須要主動釋放鎖,synchronized
執行完代碼塊之後自動釋放鎖更多原創文章請關注公衆號@MakerStack