3

java | 设计模式 同步模式-保护性暂停 优化 超时

 1 year ago
source link: https://benpaodewoniu.github.io/2022/12/18/java110/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

java | 设计模式 同步模式-保护性暂停 优化 超时

这是对 java | 设计模式 同步模式-保护性暂停 的优化,增加了超时。

之前的代码,如果,返回迟迟不给,那么,就会一直等待。

package com.redisc;

import lombok.extern.slf4j.Slf4j;

class Downloader {
public static String download() throws InterruptedException {
Thread.sleep(4000);
return "success";
}
};

@Slf4j(topic = "c.Run")
public class Run {

public static void main(String[] args) throws Exception {
// 线程1 等待 线程2 的下载结果
GuardedObject guardedObject = new GuardedObject();
new Thread(() -> {
log.debug("等待结果");
Object state = (String) guardedObject.get(2000);
log.debug("下载结果[{}]", state);
}, "t1").start();

new Thread(() -> {
log.debug("开始下载");
try {
String state = Downloader.download();
guardedObject.complete(state);
} catch (InterruptedException e) {
e.printStackTrace();
}
}, "t2").start();
}

}

class GuardedObject {
private Object response;

// 获取结果
public Object get(long timeout) {
// 开始时间
long begin = System.currentTimeMillis();
synchronized (this) {
// 经历时间
long passedTime = 0;
// 解决虚假唤醒
while (response == null) {
System.out.println(1);
if (passedTime >= timeout) {
break;
}
try {
this.wait(timeout - passedTime);
} catch (InterruptedException e) {
e.printStackTrace();
}
// 求得经历时间
passedTime = System.currentTimeMillis() - begin;
}
return response;
}
}

// 产生结果
public void complete(Object response) {
synchronized (this) {
// 给结果成员变量赋值
this.response = response;
this.notifyAll();
}
}
}
12:25:32.171 [t2] DEBUG c.Run - 开始下载
12:25:32.171 [t1] DEBUG c.Run - 等待结果
1
1
12:25:34.179 [t1] DEBUG c.Run - 下载结果[null]

关于这个代码需要解释 2 个地方。

为什么输出两个 1

第一个 1 是因为,刚进入 while (response == null) 循环,输出 1

第二个 1 是因为,this.wait(timeout - passedTime); 倒计时事件结束,再次进入到 get 方法,输出第二个 1

为什么 this.wait(timeout - passedTime);

有的人想写成 this.wait(timeout);

考虑虚假唤醒问题,如果,有一个线程虚假唤醒了方法,那个进入到方法体内后,又要睡眠 timeout,如果极端情况,多次虚假唤醒,每次都要重新睡眠 timeout


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK