并发编程之保护性暂停模式
目录
一、定义(Guarded Suspension Design Pattern)
一、定义(Guarded Suspension Design Pattern)
- 某个结果需要在多线程之间传递,则可以让这些线程关联到一个对象GuardedObject
- 但是这个对象需要不断从一个线程到另外一个线程,那么可以使用消息队列
- join和future采用的就是这种模式
二、简单实现
@Slf4j(topic = "liheng")
public class GuardedObject {
private Object response;
Object lock = new Object();
/**
* 加锁获取 response的值 如果response 没有值则等待
* @return
*/
public Object getResponse(){
synchronized (lock) {
log.debug("主线程 获取 response 如果为null则wait");
while (response == null) {
try {
lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
return response;
}
/**
* t1 给response设置值
* @param response
*/
public void setResponse(Object response) {
synchronized (lock) {
this.response = response;
//设置完成之后唤醒主线程
lock.notifyAll();
}
}
}
模拟耗时类:
public class Operate {
public static String dbOprate(){
try {
TimeUnit.SECONDS.sleep(4);
} catch (InterruptedException e) {
e.printStackTrace();
}
return "result";
}
}
测试类:
@Slf4j(topic = "liheng")
public class Test {
public static void main(String[] args) {
GuardedObject guardedObject = new GuardedObject();
new Thread(() -> {
String result = Operate.dbOprate();
log.debug("t1 set完毕...");
guardedObject.setResponse(result);
},"t1").start();
log.debug("主线程等待(wait)t1 set");
Object response = guardedObject.getResponse();
log.debug("response: [{}] lines",response);
}
}
/**
---------------打印结果---------------
19:17:50.640 [main] DEBUG liheng - 主线程等待(wait)t1 set
19:17:50.642 [main] DEBUG liheng - 主线程 获取 response 如果为null则wait
19:17:54.645 [t1] DEBUG liheng - t1 set完毕...
19:17:54.646 [main] DEBUG liheng - response: [result] lines
*/
三、超时实现
@Slf4j(topic = "liheng")
public class GuardedObject1 {
private Object response;
Object lock = new Object();
/**
* 加锁获取 response的值 如果response 没有值则等待
*
** @return
*/
public Object getResponse(long millis){
synchronized (lock) {
log.debug("主线程 获取 response 如果为null则wait");
while (response == null) {
try {
lock.wait(millis);
break;
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
return response;
}
/**
* t1 给response设置值
* @param response
*/
public void setResponse(Object response) {
synchronized (lock) {
this.response = response;
//设置完成之后唤醒主线程
lock.notifyAll();
}
}
}
四、最终实现
最终实现考虑了,如果阻塞线程被别人叫醒的情况
@Slf4j(topic = "liheng")
public class GuardedObjectTimeOut {
private Object response;
Object lock = new Object();
/**
* 加锁获取 response的值 如果response 没有值则等待
* @return
*/
public Object getResponse(long millis){
synchronized (lock) {
//开始时间
long begin = System.currentTimeMillis();
//经历了多少时间 开始肯定是0
long timePassed = 0;
while (response == null) {
//睡多少时间
long waitTime = millis-timePassed;
log.debug("主线程 判断如果没有结果则wait{}毫秒",waitTime);
if (waitTime <= 0) {
log.debug("超时了 直接结束while 不等了");
break;
}
try {
lock.wait(waitTime);
} catch (InterruptedException e) {
e.printStackTrace();
}
//如果被别人提前唤醒 先不结束 先計算一下经历时间
timePassed = System.currentTimeMillis() - begin;
log.debug("经历了: {}", timePassed);
}
}
return response;
}
/**
* t1 给response设置值
* @param response
*/
public void setResponse(Object response) {
synchronized (lock) {
this.response = response;
//设置完成之后唤醒主线程
lock.notifyAll();
}
}
}