背景:
上一篇文章基於object的wait、notify實現了生產者、消費者模式。本篇文章繼續梳理Condition。 condition 介紹及demo
Condition是在java 1.5中才出現的,它用來替代傳統的Object的wait()、notify()實現線程間的協作,相比使用Object的wait()、notify(),使用Condition的await()、signal()這種方式實現線程間協作更加安全和高效。因此通常來說比較推薦使用Condition,阻塞隊列實際上是使用了Condition來類比線程間協作。 Condition是個介面,基本的方法就是await()和signal()方法; Condition依賴於Lock介面,產生一個Condition的基本代碼是lock.newCondition() 調用Condition的await()和signal()方法,都必須在lock保護之內,就是說必須在lock.lock()和lock.unlock之間才可以使用
Conditon中的await()對應Object的wait();
Condition中的signal()對應Object的notify();
Condition中的signalAll()對應Object的notifyAll()。
下面是demo:
package thread;import java.util.concurrent.locks.Condition;import java.util.concurrent.locks.Lock;import java.util.concurrent.locks.ReentrantLock;/** * * @author zhangliang * * 2016年4月8日 下午5:48:54 */public class ConTest { final Lock lock = new ReentrantLock(); final Condition condition = lock.newCondition();public static void main(String[] args) {// TODO Auto-generated method stubConTest test = new ConTest(); Producer producer = test.new Producer(); Consumer consumer = test.new Consumer(); consumer.start(); producer.start();} class Consumer extends Thread{ @Override public void run() { consume(); } private void consume() { try { lock.lock(); System.out.println("我在等一個新訊號"+this.currentThread().getName()); condition.await(); } catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();} finally{System.out.println("拿到一個訊號"+this.currentThread().getName()); lock.unlock(); } } } class Producer extends Thread{ @Override public void run() { produce(); } private void produce() { try { lock.lock(); System.out.println("我拿到鎖"+this.currentThread().getName()); condition.signalAll(); System.out.println("我發出了一個訊號:"+this.currentThread().getName()); } finally{ lock.unlock(); } } } }運行結果:
Condition的執行方式,是當線上程Consumer中調用await方法後,線程Consumer將釋放鎖,並且將自己沉睡,等待喚醒,線程Producer擷取到鎖後,開始做事,完畢後,調用Condition的signalall方法,喚醒線程Consumer,線程Consumer恢複執行。
以上說明Condition是一個多線程間協調通訊的工具類,使得某個,或者某些線程一起等待某個條件(Condition),只有當該條件具備( signal 或者 signalAll方法被帶調用)時 ,這些等待線程才會被喚醒,從而重新爭奪鎖。 Condition實現生產者、消費者模式:
package thread;import java.util.PriorityQueue;import java.util.concurrent.locks.Condition;import java.util.concurrent.locks.Lock;import java.util.concurrent.locks.ReentrantLock;public class ConTest2 { private int queueSize = 10; private PriorityQueue<Integer> queue = new PriorityQueue<Integer>(queueSize); private Lock lock = new ReentrantLock(); private Condition notFull = lock.newCondition(); private Condition notEmpty = lock.newCondition(); public static void main(String[] args) throws InterruptedException { ConTest2 test = new ConTest2(); Producer producer = test.new Producer(); Consumer consumer = test.new Consumer(); producer.start(); consumer.start(); Thread.sleep(0); producer.interrupt(); consumer.interrupt(); } class Consumer extends Thread{ @Override public void run() { consume(); } volatile boolean flag=true; private void consume() { while(flag){ lock.lock(); try { while(queue.isEmpty()){ try { System.out.println("隊列空,等待資料"); notEmpty.await(); } catch (InterruptedException e) { flag =false; } } queue.poll(); //每次移走隊首元素 notFull.signal(); System.out.println("從隊列取走一個元素,隊列剩餘"+queue.size()+"個元素"); } finally{ lock.unlock(); } } } } class Producer extends Thread{ @Override public void run() { produce(); } volatile boolean flag=true; private void produce() { while(flag){ lock.lock(); try { while(queue.size() == queueSize){ try { System.out.println("隊列滿,等待有空餘空間"); notFull.await(); } catch (InterruptedException e) { flag =false; } } queue.offer(1); //每次插入一個元素 notEmpty.signal(); System.out.println("向隊列取中插入一個元素,隊列剩餘空間:"+(queueSize-queue.size())); } finally{ lock.unlock(); } } } }}運行結果如下:
condition實現分析:
Condition介面包含了多種await方式和兩個通知方法 ConditionObject實現了Condition介面,是AbstractQueuedSynchronizer的內部類 Reentrantlock的newCondition方法返回與某個lock執行個體相關的Condition對象
public abstract class AbstractQueuedLongSynchronizer extends AbstractOwnableSynchronizer implements java.io.Serializable {
<span style="font-size:18px;">結合上面的類圖,我們看到condition實現是依賴於aqs,而aqs是個抽象類別。裡面定義了同步器的基本架構,實現了基本的結構功能。只留有狀態條件的維護由具體同步器根據具體情境來定製,如常見的 ReentrantLock 、 RetrantReadWriteLock和CountDownLatch 等等,AQS內容太多,盡量只簡明梳理condition相關流程,不太深入理解底層源碼。</span>
下面結合上面demo來分析流程。 reentrantLock.newCondition() 返回的是Condition的一個實現,該類在AbstractQueuedSynchronizer(AQS)中被實現,叫做newCondition()
public Condition newCondition() { return sync.newCondition(); } 我們看一下這個await的方法,它是AQS的方法,
| public final void await() throws InterruptedException { |
| 02 |
if (Thread.interrupted()) |
| 03 |
throw new InterruptedException(); |
| 04 |
Node node = addConditionWaiter(); //將當前線程封裝下後, |
| 05 |
//添加到Condition自己維護的一個鏈表中。 |
| 06 |
int savedState = fullyRelease(node);//釋放當前線程佔有的鎖,從demo中看到, |
| 09 |
int interruptMode = 0; |