📝个人主页:五敷有你
🔥系列专栏:并发编程
⛺️稳中求进,晒太阳
同步模式之保护性暂停
这个模式用到的基础就是wait-notify
详情可以看这篇文章=》:【并发编程】wait/notify
即Guarded Suspension,用在一个线程等待另一个线程的执行结果
要点:
- 有一个结果需要从一个线程传递到另一个线程,让他们关联同一个GuardedObject
- 如果有结果不断从一个线程到另一个线程那么可以使用消息队列(见 生产者 消费者)
- JDK中 join的实现,Future的实现,采用的就是此模式
- 因为要等待另一方的结果,因此归类到同步模式
实现
class GuardedObject {private Object response;private final Object lock = new Object();public Object get() {synchronized (lock) {// 条件不满足则等待while (response == null) {try {lock.wait();} catch (InterruptedException e) {e.printStackTrace();}}return response;}}public void complete(Object response) {synchronized (lock) {// 条件满足,通知等待线程this.response = response;lock.notifyAll();}}
}
应用
普通版GuardedObject
一个线程等待另一个线程
public static void main(String[] args) {GuardedObject guardedObject = new GuardedObject();new Thread(() -> {try {// 子线程执行下载List<String> response = download();log.debug("download complete...");guardedObject.complete(response);} catch (IOException e) {e.printStackTrace();}}).start();log.debug("waiting...");// 主线程阻塞等待Object response = guardedObject.get();log.debug("get response: [{}] lines", ((List<String>) response).size());}
执行结果
带超时版 GuardedObject
如果想要控制时间
class GuardedObjectV2 {private Object response;private final Object lock = new Object();public Object get(long millis) {synchronized (lock) {// 1) 记录最初时间long begin = System.currentTimeMillis();// 2) 已经经历的时间long timePassed = 0;while (response == null) {// 4) 假设 millis 是 1000,结果在 400 时唤醒了,那么还有 600 要等long waitTime = millis - timePassed;log.debug("waitTime: {}", waitTime);if (waitTime <= 0) {log.debug("break...");break;}try {lock.wait(waitTime);} catch (InterruptedException e) {e.printStackTrace();}// 3) 如果提前被唤醒,这时已经经历的时间假设为 400timePassed = System.currentTimeMillis() - begin;log.debug("timePassed: {}, object is null {}",timePassed, response == null);}return response;}}public void complete(Object response) {synchronized (lock) {// 条件满足,通知等待线程this.response = response;log.debug("notify...");lock.notifyAll();}}
}
测试,没有超时情况
public static void main(String[] args) {GuardedObjectV2 v2 = new GuardedObjectV2();new Thread(() -> {sleep(1);v2.complete(null);sleep(1);v2.complete(Arrays.asList("a", "b", "c"));}).start();Object response = v2.get(2500);if (response != null) {log.debug("get response: [{}] lines", ((List<String>) response).size());} else {log.debug("can't get response");}
}
输出
测试,超时情况
// 等待时间不足List lines = v2.get(1500);
// 等待时间不足,修改时间1500
List lines = v2.get(1500);
输出