在java中,每一個對象有且僅有一個同步鎖。這也意味著,同步鎖是依賴于對象而存在。 當我們調用某對象的synchronized方法時,就獲取了該對象的同步鎖。例如,synchronized(obj)就獲取了“obj這個對象”的同步鎖。 不同線程對同步鎖的訪問是互斥的。也就是說,某時間點,對象的同步鎖只能被一個線程獲取到!通過同步鎖,我們就能在多線程中,實現對“對象/方法”的互斥訪問。 例如,現在有兩個線程A和線程B,它們都會訪問“對象obj的同步鎖”。假設,在某一時刻,線程A獲取到“obj的同步鎖”并在執行一些操作;而此時,線程B也企圖獲取“obj的同步鎖” —— 線程B會獲取失敗,它必須等待,直到線程A釋放了“該對象的同步鎖”之后線程B才能獲取到“obj的同步鎖”從而才可以運行。
sychronized有三條原則: 1. 當一個線程訪問“某對象”的“synchronized方法”或者“synchronized代碼塊”時,其他線程對“該對象”的該“synchronized方法”或者“synchronized代碼塊”的訪問將被阻塞。 2. 當一個線程訪問“某對象”的“synchronized方法”或者“synchronized代碼塊”時,其他線程仍然可以訪問“該對象”的非同步代碼塊。 3. 當一個線程訪問“某對象”的“synchronized方法”或者“synchronized代碼塊”時,其他線程對“該對象”的其他的“synchronized方法”或者“synchronized代碼塊”的訪問將被阻塞。
synchronized會在進入同步塊的前后分別形成monitorenter和monitorexit字節碼指令.在執行monitorenter指令時會嘗試獲取對象的鎖,如果此沒對象沒有被鎖,或者此對象已經被當前線程鎖住,那么鎖的計數器加一,每當monitorexit被鎖的對象的計數器減一.直到為0就釋放該對象的鎖.由此synchronized是可重入的,不會出現自己把自己鎖死.
ReentrantLock是一個可重入的互斥鎖,又被稱為“獨占鎖”。
顧名思義,ReentrantLock鎖在同一個時間點只能被一個線程鎖持有;而可重入的意思是,ReentrantLock鎖,可以被單個線程多次獲取。 ReentrantLock分為 公平鎖 和 非公平鎖 。它們的區別體現在獲取鎖的機制上是否公平。鎖 是為了保護競爭資源,防止多個線程同時操作線程而出錯,ReentrantLock在同一個時間點只能被一個線程獲取(當某線程獲取到“鎖”時,其它線程就必須等待);ReentraantLock是通過一個FIFO的等待隊列來管理獲取該鎖所有線程的。在“公平鎖”的機制下,線程依次排隊獲取鎖;而“非公平鎖”在鎖是可獲取狀態時,不管自己是不是在隊列的開頭都會獲取鎖。 以對象的方式來操作對象鎖,相對于sychronized需要在finally中去釋放鎖。
除了synchronized的功能,多了三個高級功能。 等待可中斷,公平鎖,綁定多個Condition。 1. 等待可中斷:在持有鎖的線程長時間不釋放鎖的時候,等待的線程可以選擇放棄等待,tryLock(long timeout, TimeUnit unit)
2. 公平鎖:按照申請鎖的順序來一次獲得鎖稱為公平鎖,synchronized的是非公平鎖,ReentrantLock可以通過構造函數實現公平鎖。new RenentrantLock(boolean fair) 3. 綁定多個Condition:通過多次newCondition可以獲得多個Condition對象,可以簡單的實現比較負責的線程同步的功能,通過await(),signal();
sychronized
public static class Depot { PRivate int mCapacity; private int mSize; public Depot(int capacity) { mCapacity = capacity; mSize = 0; } public synchronized void produce(int val) { try { int left = val; while (left > 0) { while (mSize >= mCapacity) wait(); int inc = (mSize + left) > mCapacity ? (mCapacity - mSize) : left; mSize += inc; left -= inc; System.out.println("produce Thread: " + Thread.currentThread().getName() + " val: " + val + " mSize: " + mSize + " left: " + left); notifyAll(); } } catch (InterruptedException e) { e.printStackTrace(); } } public synchronized void consume(int val) { try { int left = val; while (left > 0) { while (mSize <= 0) wait(); int inc = (mSize - left) < 0 ? mSize : left; mSize -= inc; left -= inc; System.out.println("consume Thread: " + Thread.currentThread().getName() + " val: " + val + " mSize: " + mSize + " left: " + left); notifyAll(); } } catch (InterruptedException e) { e.printStackTrace(); } } } private static class Producer { private Depot depot; public Producer(Depot depot) { this.depot = depot; } public void produce(int val) { new Thread() { @Override public void run() { depot.produce(val); } }.start(); } } static class Customer { private Depot depot; public Customer(Depot depot) { this.depot = depot; } public void consume(int val) { new Thread() { @Override public void run() { depot.consume(val); } }.start(); } } public static void main(String[] args) { Depot depot = new Depot(100); Producer producer = new Producer(depot); Customer customer = new Customer(depot); producer.produce(60); producer.produce(120); customer.consume(90); customer.consume(150); producer.produce(110); }ReentrantLock
public static class Depot { private int mCapacity; private int mSize; private Lock mLock; private Condition mFullCondition; private Condition mEmptyCondition; public Depot(int capacity) { mCapacity = capacity; mSize = 0; mLock = new ReentrantLock(); mFullCondition = mLock.newCondition(); mEmptyCondition = mLock.newCondition(); } public void produce(int val) { mLock.lock(); try { int left = val; while (left > 0) { while (mSize >= mCapacity) mFullCondition.await(); int inc = (mSize + left) > mCapacity ? (mCapacity - mSize) : left; mSize += inc; left -= inc; System.out.println("produce Thread: " + Thread.currentThread().getName() + " mSize: " + mSize + " left: " + left); mEmptyCondition.signal(); } } catch (InterruptedException e) { e.printStackTrace(); } finally { mLock.unlock(); } } public void consume(int val) { mLock.lock(); try { int left = val; while (left > 0) { while (mSize <= 0) mEmptyCondition.await(); int inc = (mSize - left) < 0 ? mSize : left; mSize -= inc; left -= inc; System.out.println("consume Thread: " + Thread.currentThread().getName() + " mSize: " + mSize + " left: " + left); mFullCondition.signal(); } } catch (InterruptedException e) { e.printStackTrace(); } finally { mLock.unlock(); } } } static class Producer { private Depot depot; public Producer(Depot depot) { this.depot = depot; } public void produce(int val) { new Thread() { @Override public void run() { depot.produce(val); } }.start(); } } static class Customer { private Depot depot; public Customer(Depot depot) { this.depot = depot; } public void consume(int val) { new Thread() { @Override public void run() { depot.consume(val); } }.start(); } } public static void main(String[] args) { Depot depot = new Depot(100); Producer producer = new Producer(depot); Customer customer = new Customer(depot); producer.produce(60); producer.produce(120); customer.consume(90); customer.consume(150); producer.produce(110); }新聞熱點
疑難解答