Table of Contents
ToggleDifference Between Condition await and signal in Java
兩個執行緒共享一些資源並執行兩個不同的任務,希望執行緒僅在另一個執行緒完成某些任務 B 後才執行某些任務 A ,簡而言之,該執行緒必須檢查是否滿足某些條件才能執行任務 A , Difference Between Condition signal and await in Java 調用 await 方法時,調用執行緒停止執行,直到 signal 或 signalAll 方法被其他某個執行緒調用, Difference Between Condition await and signal Methods in Java 本篇增加了範例,並透過單元測試來驗證產出結果。
檔案目錄
./
+- src
+- test
| +- org
| +- ruoxue
| +- java_147
| +- synchronization
| +- reentrantlock
| +- DifferenceConditionAwaitSignalTest.java
單元測試
Difference Between Condition await and signal 提供執行緒暫停、喚醒、拋出例外等操作。
worker
Difference Between Condition await and signal 建立 1 個物件,提供儲存跟讀取 2 個方法,當儲存執行緒調用 put 方法耗時 3 秒,完成任務時,會喚醒另一條讀取執行緒,因調用 take 方法而被暫停的執行緒, Difference Between Condition signal and await 建立 2 條執行緒,分別調用 1 個物件儲存跟讀取的方法。
protected class Worker {
private volatile boolean done = false;
private final Lock lock = new ReentrantLock();
private Condition condition = lock.newCondition();
public Worker() {
}
public void put() throws InterruptedException {
lock.lock();
try {
TimeUnit.SECONDS.sleep(3);
System.out.println(String.format("T[%d] put finished", Thread.currentThread().getId()));
done = true;
condition.signal();
} finally {
lock.unlock();
}
}
public boolean take() throws InterruptedException {
lock.lock();
try {
while (!done) {
System.out.println(String.format("T[%d] take waiting", Thread.currentThread().getId()));
condition.await();
}
} finally {
lock.unlock();
}
return done;
}
}
@Test
public void worker() {
Worker worker = new Worker();
Thread threadA = new Thread(() -> {
String id = "A";
try {
System.out.println(String.format("T[%d] worker: %s ready", Thread.currentThread().getId(), id));
worker.put();
System.out.println(String.format("T[%d] worker: %s finished", Thread.currentThread().getId(), id));
worker.put();
} catch (InterruptedException ex) {
ex.printStackTrace();
}
});
Thread threadB = new Thread(() -> {
String id = "B";
try {
System.out.println(String.format("T[%d] worker: %s ready", Thread.currentThread().getId(), id));
boolean done = worker.take();
System.out.println(String.format("T[%d] worker: %s finished, result: %b",
Thread.currentThread().getId(), id, done));
} catch (InterruptedException ex) {
ex.printStackTrace();
}
});
threadB.start();
threadA.start();
try {
threadA.join();
threadB.join();
} catch (InterruptedException ex) {
ex.printStackTrace();
}
}
T[12] worker: B ready
T[12] take waiting
T[11] worker: A ready
T[11] put finished
T[11] worker: A finished
T[12] worker: B finished, result: true
interruptWorker
Difference Between Condition await and signal 建立 1 個物件,提供儲存跟讀取 2 個方法,當儲存執行緒,調用 put 方法耗時 3 秒,完成任務時,沒有喚醒另一條讀取執行緒,因調用 take 方法而被暫停的執行緒, Difference Between Condition signal and await 建立 2 條執行緒,分別調用 1 個物件儲存跟讀取的方法,主執行緒等待 2 秒後,調用 interrupt 中斷讀取執行緒。
protected class InterruptWorker {
private volatile boolean done = false;
private final Lock lock = new ReentrantLock();
private Condition condition = lock.newCondition();
public InterruptWorker() {
}
public void put() throws InterruptedException {
lock.lock();
try {
TimeUnit.SECONDS.sleep(3);
System.out.println(String.format("T[%d] put finished", Thread.currentThread().getId()));
done = true;
// condition.signal();
} finally {
lock.unlock();
}
}
public boolean take() throws InterruptedException {
lock.lock();
try {
while (!done) {
System.out.println(String.format("T[%d] take waiting", Thread.currentThread().getId()));
condition.await();
}
} finally
{
lock.unlock();
}
System.out.println(lock);
return done;
}
}
@Test
public void interruptWorker() {
InterruptWorker worker = new InterruptWorker();
Thread threadA = new Thread(() -> {
String id = "A";
try {
System.out.println(String.format("T[%d] worker: %s ready", Thread.currentThread().getId(), id));
worker.put();
System.out.println(String.format("T[%d] worker: %s finished", Thread.currentThread().getId(), id));
} catch (InterruptedException ex) {
ex.printStackTrace();
}
});
Thread threadB = new Thread(() -> {
String id = "B";
try {
System.out.println(String.format("T[%d] worker: %s ready", Thread.currentThread().getId(), id));
boolean done = worker.take();
System.out.println(String.format("T[%d] worker: %s finished, result: %b",
Thread.currentThread().getId(), id, done));
} catch (InterruptedException ex) {
ex.printStackTrace();
}
});
threadB.start();
threadA.start();
try {
threadA.join();
} catch (InterruptedException ex) {
ex.printStackTrace();
}
long startTime = System.currentTimeMillis();
while (true) {
if (System.currentTimeMillis() - startTime > 1000) {
threadB.interrupt();
break;
}
}
}
T[12] worker: B ready
T[12] take waiting
T[11] worker: A ready
T[11] put finished
T[11] worker: A finished
java.lang.InterruptedException
at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.reportInterruptAfterWait(AbstractQueuedSynchronizer.java:2014)
at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:2048)
at org.ruoxue.java_147.synchronization.DifferenceConditionAwaitSignalTest$InterruptWorker.take(DifferenceConditionAwaitSignalTest.java:110)
at org.ruoxue.java_147.synchronization.DifferenceConditionAwaitSignalTest.lambda$3(DifferenceConditionAwaitSignalTest.java:141)
at java.lang.Thread.run(Thread.java:750)
DifferenceConditionAwaitSignalTest.java
Difference Between Condition signal and await 新增單元測試,驗證是否符合預期。
package org.ruoxue.java_147.synchronization.reentrantlock;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import org.junit.Test;
public class DifferenceConditionAwaitSignalTest {
protected class Worker {
private volatile boolean done = false;
private final Lock lock = new ReentrantLock();
private Condition condition = lock.newCondition();
public Worker() {
}
public void put() throws InterruptedException {
lock.lock();
try {
TimeUnit.SECONDS.sleep(3);
System.out.println(String.format("T[%d] put finished", Thread.currentThread().getId()));
done = true;
condition.signal();
} finally {
lock.unlock();
}
}
public boolean take() throws InterruptedException {
lock.lock();
try {
while (!done) {
System.out.println(String.format("T[%d] take waiting", Thread.currentThread().getId()));
condition.await();
}
} finally {
lock.unlock();
}
return done;
}
}
@Test
public void worker() {
Worker worker = new Worker();
Thread threadA = new Thread(() -> {
String id = "A";
try {
System.out.println(String.format("T[%d] worker: %s ready", Thread.currentThread().getId(), id));
worker.put();
System.out.println(String.format("T[%d] worker: %s finished", Thread.currentThread().getId(), id));
worker.put();
} catch (InterruptedException ex) {
ex.printStackTrace();
}
});
Thread threadB = new Thread(() -> {
String id = "B";
try {
System.out.println(String.format("T[%d] worker: %s ready", Thread.currentThread().getId(), id));
boolean done = worker.take();
System.out.println(String.format("T[%d] worker: %s finished, result: %b",
Thread.currentThread().getId(), id, done));
} catch (InterruptedException ex) {
ex.printStackTrace();
}
});
threadB.start();
threadA.start();
try {
threadA.join();
threadB.join();
} catch (InterruptedException ex) {
ex.printStackTrace();
}
}
protected class InterruptWorker {
private volatile boolean done = false;
private final Lock lock = new ReentrantLock();
private Condition condition = lock.newCondition();
public InterruptWorker() {
}
public void put() throws InterruptedException {
lock.lock();
try {
TimeUnit.SECONDS.sleep(3);
System.out.println(String.format("T[%d] put finished", Thread.currentThread().getId()));
done = true;
// condition.signal();
} finally {
lock.unlock();
}
}
public boolean take() throws InterruptedException {
lock.lock();
try {
while (!done) {
System.out.println(String.format("T[%d] take waiting", Thread.currentThread().getId()));
condition.await();
}
} finally
{
lock.unlock();
}
System.out.println(lock);
return done;
}
}
@Test
public void interruptWorker() {
InterruptWorker worker = new InterruptWorker();
Thread threadA = new Thread(() -> {
String id = "A";
try {
System.out.println(String.format("T[%d] worker: %s ready", Thread.currentThread().getId(), id));
worker.put();
System.out.println(String.format("T[%d] worker: %s finished", Thread.currentThread().getId(), id));
} catch (InterruptedException ex) {
ex.printStackTrace();
}
});
Thread threadB = new Thread(() -> {
String id = "B";
try {
System.out.println(String.format("T[%d] worker: %s ready", Thread.currentThread().getId(), id));
boolean done = worker.take();
System.out.println(String.format("T[%d] worker: %s finished, result: %b",
Thread.currentThread().getId(), id, done));
} catch (InterruptedException ex) {
ex.printStackTrace();
}
});
threadB.start();
threadA.start();
try {
threadA.join();
} catch (InterruptedException ex) {
ex.printStackTrace();
}
long startTime = System.currentTimeMillis();
while (true) {
if (System.currentTimeMillis() - startTime > 1000) {
threadB.interrupt();
break;
}
}
}
}
心得分享
Difference Between Condition await and signal Methods in Java 執行緒持續檢查是否滿足條件,如果不滿足,會釋放對資源的鎖定並進入等待狀態,另一條執行緒調用 singnal 方法,會喚醒原執行緒,如果滿足條件,原執行緒可以完成工作,否則將再次重複該過程, Difference Between Condition signal and await 提供這兩個方法的區別與使用。