Condition作用和Object.wait()和Object.notify()方法作用類似,但是wait()和notify()是和synchronized關鍵字結合使用的,而Condition是和ReentrantLock(重入鎖)相關聯的且更靈活:一個鎖實例,可以綁定多個Condition實例,實現多路通知;notify()方法進行通知時,是隨機進行選擇的,但重入鎖結合Condition對象,可以實現有選擇性的通知。
Condition接口API:
public interface Condition {
//阻塞當前線程。使當前線程加入等待隊列中,同時釋放當前鎖,當其他線程使用signal()或者signalAll()方法時,線程會重新請求鎖,得到鎖後會繼續執行。或者當線程被中斷時,也能跳出等待。類似Object.wait()方法
void await() throws InterruptedException;
//調用該方法的前提是,當前線程已經成功獲得與該Condition對象綁定的重入鎖,否則調用該方法時會拋出IllegalMonitorStateException。
//基本同await()方法,但是不會在等待過程中響應中斷。調用該方法後,結束等待的唯一方法是其它線程調用該條件對象的signal()或signalALL()方法。等待過程中如果當前線程被中斷,該方法仍然會繼續等待,同時保留該線程的中斷狀態。
void awaitUninterruptibly();
//調用該方法的前提是,當前線程已經成功獲得與該Condition對象綁定的重入鎖,否則調用該方法時會拋出IllegalMonitorStateException。
//等待的的最大時間(單位爲納秒)。若指定時間內收到signal()或signalALL()則返回nanosTimeout減去已經等待的時間;若指定時間內未收到通知,則返回0或負數。
//在等待過程中會響應中斷,若指定時間內有其它線程中斷該線程,則拋出InterruptedException並清除當前線程的打斷狀態。
long awaitNanos(long nanosTimeout) throws InterruptedException;
//與await()基本一致,不同點:指定時間之內沒有收到signal()或signalALL()或線程中斷會返回false;其它情況返回true。
boolean await(long time, TimeUnit unit) throws InterruptedException;
//與awaitNanos(long nanosTimeout)一致,不同點在於它不是等待指定時間,而是等待時間到達參數指定的某一時刻。
boolean awaitUntil(Date deadline) throws InterruptedException;
//喚醒一個等待隊列中的線程。與Object.notify()相似,但是signal()喚醒的線程與該Condition對象有關
void signal();
//喚醒等待隊列中所有線程。與object.notifyAll()相似,但是signalAll()喚醒的線程與該Condition對象有關
void signalAll();
}
代碼Demo:
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
/**
* 可重入鎖不同condition測試
*/
public class MyReentrantLockCondition implements Runnable {
//共享鎖
public static ReentrantLock lock = new ReentrantLock();
//condition不共享
public Condition condition;
//共享變量
//public static volatile int i = 1;
public MyReentrantLockCondition() {
//每個對象獨立condition
this.condition = lock.newCondition();
}
public void await() {
//自旋獲取鎖,直到獲取鎖成功
lock.lock();
try {
System.out.println("-->await(): " + Thread.currentThread().getName() + " 獲取了鎖");
//當前線程等待,釋放了鎖。類比Object.wait()。多線程操作共享變量是否有問題?沒有問題,喚醒時會重新獲取鎖重新獲取值
condition.await();
System.out.println("-->await(): " + Thread.currentThread().getName() + " 結束執行");
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
//任何情況都釋放鎖對象
lock.unlock();
}
}
public void signal() {
lock.lock();
try {
//喚醒等待隊列中關聯condition的一個線程.類比Object.notify()
condition.signal();
} finally {
lock.unlock();
}
}
//測試
public static void main(String[] args) throws InterruptedException {
MyReentrantLockCondition condition1 = new MyReentrantLockCondition();
MyReentrantLockCondition condition2 = new MyReentrantLockCondition();
MyReentrantLockCondition condition3 = new MyReentrantLockCondition();
MyReentrantLockCondition condition4 = new MyReentrantLockCondition();
new Thread(condition1).start();
new Thread(condition2).start();
new Thread(condition3).start();
new Thread(condition4).start();
Thread.sleep(3000);
//通知線程繼續執行
condition1.signal();
condition2.signal();
// condition3.signal();
/* MyReentrantLockCondition.lock.lock();
try {
condition4.condition.signalAll();
} finally {
MyReentrantLockCondition.lock.unlock();
}*/
}
@Override
public void run() {
await();
}
}
運行main()方法,可看到結果:
-->await(): Thread-0 獲取了鎖
-->await(): Thread-1 獲取了鎖
-->await(): Thread-2 獲取了鎖
-->await(): Thread-3 獲取了鎖
-->await(): Thread-0 結束執行
-->await(): Thread-1 結束執行
Thread-2、Thread-3沒有“結束執行”,還在一直等待signal()喚醒。
Condition在JDK源碼中的應用:
java.util.concurrent.ArrayBlockingQueue阻塞隊列:基於數組的阻塞隊列實現,在ArrayBlockingQueue內部,維護了一個定長數組,以便緩存隊列中的數據對象,還保存着兩個整形變量,分別標識着隊列的頭部和尾部在數組中的位置。
public class ArrayBlockingQueue<E> extends AbstractQueue<E>
implements BlockingQueue<E>, java.io.Serializable {
final Object[] items;
int takeIndex;
int putIndex;
int count;
final ReentrantLock lock;
/** Condition for waiting takes */
private final Condition notEmpty;
/** Condition for waiting puts */
private final Condition notFull;
//往隊列中添加對象
public void put(E e) throws InterruptedException {
checkNotNull(e);
final ReentrantLock lock = this.lock;
lock.lockInterruptibly();//自旋獲取鎖
try {
while (count == items.length)//隊列已滿
notFull.await();//進入等待隊列中等待,關聯notFull條件
enqueue(e);
} finally {
lock.unlock();
}
}
//隊列中移除對象
private E dequeue() {
// assert lock.getHoldCount() == 1;
// assert items[takeIndex] != null;
final Object[] items = this.items;
@SuppressWarnings("unchecked")
E x = (E) items[takeIndex];
items[takeIndex] = null;
if (++takeIndex == items.length)
takeIndex = 0;
count--;
if (itrs != null)
itrs.elementDequeued();
notFull.signal();//喚醒一個等待隊列中等待notFull條件的線程
return x;
}
}