本博客系列是學習並發編程過程中的記錄總結。由於文章比較多,寫的時間也比較散,所以我整理了個目錄貼(傳送門),方便查閱。
接口簡介
Condition可以看做是Obejct類的wait()
、notify()
、notifyAll()
方法的替代品,與Lock配合使用。
當線程執行condition對象的await
方法時,當前線程會立即釋放鎖,並進入對象的等待區,等待其它線程喚醒或中斷。
JUC在實現Conditon對象時,其實是通過實現AQS框架,來實現了一個Condition等待隊列,這個在后面講AQS框架時會詳細介紹,目前只要了解Condition如何使用即可。
接口定義
public interface Condition {
void await() throws InterruptedException;
long awaitNanos(long nanosTimeout) throws InterruptedException;
boolean await(long time, TimeUnit unit) throws InterruptedException;
boolean awaitUntil(Date deadline) throws InterruptedException;
void signal();
void signalAll();
}
使用示例
wait-notify模式的一個典型應用就是可以實現生產者-消費者模式。讓我印象很深是我畢業那年阿里巴巴校園招聘的一個筆試題:
有一個蘋果箱,有10個人向這個箱子中每次隨機放入一個蘋果,有10個人每次隨機從這個箱子中隨機拿走一個蘋果,同時需要滿足箱子中的蘋果總數不能超過50個。請用代碼實現上面的場景(不能使用並發集合框架)
這個題目使用wait-notify模式可以很好地解決。下面使用Condition
模式來寫下。
public class AppleBoxConditon {
private int appleCount;
private static Lock lock = new ReentrantLock();
private static Condition fullCondition = lock.newCondition();
private static Condition emptyCondition = lock.newCondition();
public void putApple() {
lock.lock();
try {
while (appleCount >= 10) {
try {
fullCondition.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
appleCount++;
System.out.println("放入一個,當前盒子中蘋果數:" + appleCount);
emptyCondition.signalAll();
} finally {
lock.unlock();
}
}
public void takeApple() {
lock.lock();
try{
while (appleCount <= 0) {
try {
emptyCondition.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
appleCount--;
System.out.println("拿走一個,當前盒子中蘋果數:" + appleCount);
fullCondition.signalAll();
}finally {
lock.unlock();
}
}
private static class AppleTaker implements Runnable {
private AppleBoxConditon appleBox;
public AppleTaker(AppleBoxConditon appleBox) {
this.appleBox = appleBox;
}
@Override
public void run() {
while (true) {
appleBox.takeApple();
try {
TimeUnit.MILLISECONDS.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
private static class ApplePutter implements Runnable {
private AppleBoxConditon appleBox;
public ApplePutter(AppleBoxConditon appleBox) {
this.appleBox = appleBox;
}
@Override
public void run() {
while (true) {
appleBox.putApple();
try {
TimeUnit.MILLISECONDS.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public static void main(String[] args) {
AppleBoxConditon appleBox = new AppleBoxConditon();
for (int i = 0; i < 20; i++) {
Thread t = new Thread(new AppleBoxConditon.ApplePutter(appleBox));
t.setName("ApplePutter:"+i);
t.start();
}
for (int i = 0; i < 20; i++) {
Thread t = new Thread(new AppleBoxConditon.AppleTaker(appleBox));
t.setName("AppleTaker:"+i);
t.start();
}
}
}