標籤:style java 使用 os io strong for ar
分享JUC中的Condition的比較少見,我見了大部分文章都是講其中的一個例子BoundedBuffer。今天先從Condition介面的幾個方法說起,然後在把BoundedBuffer搞死結了。來看看Condition在使用的時候需要注意什麼。
原始碼
上原始碼:(字數限時,原諒我把注釋都去掉了)
public interface Condition { void await() throws InterruptedException; void awaitUninterruptibly(); long awaitNanos(long nanosTimeout) throws InterruptedException; boolean await(long time, TimeUnit unit) throws InterruptedException; boolean awaitUntil(Date deadline) throws InterruptedException; void signal(); void signalAll();}
Condtion介面主要是用來描述一個鎖的幾個狀態。具體建立方法如下
Condition notFull = lock.newCondition();
其實Condition的功能有點類似Object當中的wait和notify方法。但是稍做了加強。提供了多種wait的策略。另外用Condition的最大好處就是,一個鎖是可以擁有多個狀態的。如果用Object的wait和notify只能有一個。
具體看一下以下幾個wait方法:
void await() throws InterruptedException; void awaitUninterruptibly(); long awaitNanos(long nanosTimeout) throws InterruptedException; boolean await(long time, TimeUnit unit) throws InterruptedException; boolean awaitUntil(Date deadline) throws InterruptedException;
await()
解讀:會將當前線程設定成等待狀態,一直到有signal方法的觸發或者Interrupt的發生才會恢複狀態。當然interrupt了就直接拋異常了,不會繼續往下走
異常:InterruptedException
awaitUninterruptibly()
解讀:會將當前線程設定成等待狀態,一直到有signal方法的觸發。不會被Interrupt阻斷。
long awaitNanos(long nanosTimeout)
參數:最大的等待的時間
返回:實際的剩餘時間的估算(nanosTimeout - 實際等待時間)正值可以用於後續的繼續等待,例如消極式載入這樣的情境,可以讓程式繼續等待剩下的時間,完成計時。如果為0或者負數時,表示沒有剩餘時間了。
解讀:會將當前線程設定成等待狀態一直到設定的最大等待時間。當遇到singal或者Interrupt時才會恢複。
異常:InterruptedException
boolean await(long time, TimeUnit unit) 和 boolean awaitUntil(Date deadline)
參數:具體時間一個是間斷的時間,另一個是具體的時刻。但實質是一樣的。
解讀:具體等待一段時間或一個到一個時間點。如果遇到singal則返回True,否則返回false.
異常:InterruptedException
void signal(); void signalAll();
void signal()
解讀:喚醒一個等待的線程,如果所有的線程都在等待此條件,則選擇其中的一個喚醒。在從 await 返回之前,該線程必須重新擷取鎖。
void signalAll()
解讀:喚醒所有線程,如果所有的線程都在等待此條件,則選擇其中的一個喚醒。在從 await 返回之前,該線程必須重新擷取鎖。
看一個例子:
public class BoundedBuffer {final Lock lock = new ReentrantLock();final Condition notFull = lock.newCondition();final Condition notEmpty = lock.newCondition();final Object[] items = new Object[2];int putptr, takeptr, count;public void put(Object x) throws InterruptedException {String threadName = Thread.currentThread().getName();System.out.println(threadName+" is waiting for lock");lock.lock();System.out.println(threadName+" got lock");try {while (count == items.length){System.out.println(threadName+" is waiting for notFull condition");notFull.await();System.out.println(threadName+" left notFull condition");}items[putptr] = x;if (++putptr == items.length){putptr = 0;}++count;notEmpty.signal();} finally {lock.unlock();}}public Object take() throws InterruptedException {String threadName = Thread.currentThread().getName();System.out.println(threadName+" is waiting for lock");lock.lock();System.out.println(threadName+" got lock");try {while (count == 0){System.out.println(threadName+" is waiting for notEmpty condition");notEmpty.await();System.out.println(threadName+" left notEmpty condition");}Object x = items[takeptr];if (++takeptr == items.length){takeptr = 0;}--count;notFull.signal();return x;} finally {lock.unlock();}}}
問得最多的一個問題:這裡的await有必要嗎?
while (count == 0){ System.out.println(threadName+" is waiting for notEmpty condition"); notEmpty.await(); System.out.println(threadName+" left notEmpty condition");}
回答:有必要,當count等於0的時候.如果沒有await釋放鎖,那麼其他線程會認為lock一直被佔有,將無法獲得鎖。
為了驗證這一點,寫了一個測試方法:
public class PutTask implements Runnable {BoundedBuffer bb = new BoundedBuffer();int count = 0;public PutTask(BoundedBuffer bb){this.bb = bb;this.count = 0;}@Overridepublic void run() {try {String threadName = Thread.currentThread().getName();bb.put(count);System.out.println(threadName+" put "+count);count++;} catch (InterruptedException e) {e.printStackTrace();}}}public class TakeTask implements Runnable {BoundedBuffer bb = new BoundedBuffer();public TakeTask(BoundedBuffer bb){this.bb = bb;}@Overridepublic void run() {try {System.out.println(Thread.currentThread().getName()+" take "+bb.take());} catch (InterruptedException e) {e.printStackTrace();}}}public class ConditionTest {public static void main(String[] args) throws InterruptedException{BoundedBuffer bb = new BoundedBuffer();PutTask putTask = new PutTask(bb);TakeTask takeTask1 = new TakeTask(bb);TakeTask takeTask2 = new TakeTask(bb);final ScheduledExecutorService service = Executors.newScheduledThreadPool(3);//service.scheduleAtFixedRate(putTask, 0, 1, TimeUnit.SECONDS);service.scheduleAtFixedRate(takeTask1, 0, 1, TimeUnit.SECONDS);service.scheduleAtFixedRate(takeTask2, 0, 1, TimeUnit.SECONDS);Thread.currentThread().sleep(3000l);Thread t = new Thread(putTask);t.start();}}
將notEmpty.await()注釋掉,執行的結果為
pool-1-thread-2 is waiting for lock
pool-1-thread-2 got lock
pool-1-thread-1 is waiting for lock
Thread-0 is waiting for lock
可以看到除了pool-1-thread-2獲得了鎖,其他線程都在等待鎖。但這個時候pool-1-thread-2被while(count==0)鎖死,無法跳出。程式進入死結。
恢複notEmpty.await()的注釋,執行的結果為
pool-1-thread-2 is waiting for lock
pool-1-thread-2 got lock
pool-1-thread-2 is waiting for notEmpty condition
pool-1-thread-1 is waiting for lock
pool-1-thread-1 got lock
pool-1-thread-1 is waiting for notEmpty condition
Thread-0 is waiting for lock
Thread-0 got lock
Thread-0 put 0
pool-1-thread-2 left notEmpty condition
pool-1-thread-2 take 0
pool-1-thread-2 is waiting for lock
pool-1-thread-2 got lock
pool-1-thread-2 is waiting for notEmpty condition