Guarded Suspension: 用于一个线程等待另一个线程的执行结果。
1.t1线程需要等待t2线程的结果,让t1和t2关联同一个GuardedObject。
2.如果有结果不断的从t2到t1,那么可以使用消息队列(生产者 消费者)
3.JDK中,join()和Future的实现就是采用这个模式
4.将t2产生的结果放入GuardedObject的response中。t1从GuardedObject的response中拿到t2的值。
5.在t2产生结果的过程中t1需要用wait()来等待。
import lombok.extern.slf4j.Slf4j;
@Slf4j(topic = "TC8")
public class TC8 {
public static void main(String[] args) {
GuardedObject guardedObject = new GuardedObject();
Thread thread1 = new Thread(() -> {
log.debug("获取到结果:{}", guardedObject.getResponse(2000));
});
Thread thread2 = new Thread(() -> {
guardedObject.setResponse("产生了结果");
});
thread1.start();
thread2.start();
}
}
class GuardedObject{
private Object response;
public Object getResponse(long timeOut) {
synchronized (this){
long startTime = System.currentTimeMillis();
long spendTime = 0;
while(response==null) {
long waitTime = timeOut - spendTime; //防止虚假唤醒,唤醒时,object==null
if (waitTime<=0) {
break;
}
try {
this.wait(waitTime);
} catch (InterruptedException e) {
e.printStackTrace();
}
spendTime = System.currentTimeMillis()-startTime;
}
return response;
}
}
public void setResponse(Object object) {
synchronized (this) {
this.response = object;
this.notifyAll();
}
}
}
如果有多个线程一一对应传递消息,需要有个解耦类来管理各个GuardedObject.
t1,t3,t5给GuardedObject1.2.3传递结果;t0,t2,t4从GuardedObject1.2.3中拿到结果。
import lombok.extern.slf4j.Slf4j;
import java.util.Hashtable;
import java.util.Map;
import java.util.Set;
public class TC9 {
public static void main(String[] args) throws InterruptedException {
for (int i = 0; i < 3; i++) {
new PersonTest().start();
}
Thread.sleep(1000);//等待生成GuardedObject,使postman循环得以执行
for (Integer id : MailBoxTest.getIDs()) {
new PostmanTest(id,"内容:"+id).start();
}
}
}
@Slf4j(topic = "PersonTest")
class PersonTest extends Thread{
@Override
public void run() {
GuardedObjectTest guardedObjectTest = MailBoxTest.generateGuardedObject();
log.debug("收信前ID:{}",guardedObjectTest.getId());
Object result = guardedObjectTest.getResult(5000);
log.debug("收信ID:{}, 收信内容:{}",guardedObjectTest.getId(),result);
}
}
@Slf4j(topic = "PostmanTest")
class PostmanTest extends Thread{
private int id;
private String message;
public PostmanTest(int id, String message) {
this.id=id;
this.message=message;
}
@Override
public void run() {
GuardedObjectTest object = MailBoxTest.getGuardedObjectByID(id);
log.debug("发信id:{}, 发信内容:{}",id,message);
object.setResult(message);
}
}
class MailBoxTest{
public static Map<Integer,GuardedObjectTest> boxes = new Hashtable<>();
private static int id=1;
public synchronized static int generateId() {
return id++;
}
public static GuardedObjectTest generateGuardedObject() {
GuardedObjectTest guardedObjectTest = new GuardedObjectTest(generateId());
boxes.put(guardedObjectTest.getId(),guardedObjectTest);
return guardedObjectTest;
}
public static GuardedObjectTest getGuardedObjectByID(int id) {
return boxes.remove(id);
}
public static Set<Integer> getIDs() {
return boxes.keySet();
}
}
class GuardedObjectTest{
private int id;
private Object object;
public GuardedObjectTest(int id) {
this.id = id;
}
public int getId() {
return id;
}
public Object getResult(long timeOut) {
long start = System.currentTimeMillis();
long spendTime=0;
synchronized (this) {
long waitTime = timeOut-spendTime;
while(object==null){
if (waitTime<=0) {
break;
}
try {
this.wait(waitTime);
} catch (InterruptedException e) {
e.printStackTrace();
}
spendTime=System.currentTimeMillis()-start;
}
return object;
}
}
public synchronized void setResult(Object object) {
this.object = object;
this.notifyAll();
}
}