3.2要点用在一个线程等待另一个线程的执行结果
3.3 实现
一个线程需要得到另一个线程的结果,他们需要关联同一个GuardedObject
如果有结果不断从一个线程到另一个线程那么可以使用消息队列(见生产者/消费者)
JDK 中,join 的实现、Future 的实现,采用的就是此模式
因为要等待另一方的结果,因此归类到同步模式
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LPTZ5lpd-1655016006794)(F:Java_notejava笔记img同步模式之保护性暂停.png)]
package com.zjc.study.day611;
public class test1 {
public static void main(String[] args) {
GuardedObject guardedObject = new GuardedObject();
new Thread(()->{
guardedObject.getResponse();
},"t1").start();
new Thread(()->{
guardedObject.setResponse("hello");
},"t2").start();
}
}
//1.定义一个类GuardedObject作为桥梁
class GuardedObject {
//2.定义需要共享的资源
private Object response;
//3.get方法加锁
public synchronized Object getResponse() {
//4.如果response没有值就一直暂停
while (response == null) {
try {
//4.暂停
this.wait();
System.out.println((String)response);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//5.如果response不是null就返回
return response;
}
//6.set方法加锁
public synchronized void setResponse(String s) {
//7.给response赋值
this.response = s;
//8.唤醒等待的线程
this.notify();
}
}
3.4超时等待版GuardedObject
package com.zjc.study.day611;
import lombok.extern.slf4j.Slf4j;
import java.time.LocalDateTime;
@Slf4j
public class test1 {
public static void main(String[] args) {
GuardedObject guardedObject = new GuardedObject();
new Thread(() -> {
Object response = guardedObject.getResponse(2000);
System.out.println((String)response);
}, "t1").start();
new Thread(() -> {
try {
Thread.sleep(4000);
} catch (InterruptedException e) {
e.printStackTrace();
}
guardedObject.setResponse("hello");
}, "t2").start();
}
}
//1.定义一个类GuardedObject作为桥梁
@Slf4j
class GuardedObject {
//2.定义需要共享的资源
private Object response;
//3.get方法加锁
public synchronized Object getResponse(long millis) {
//统计起始时间
long start = System.currentTimeMillis();
//统计已经过去的时间
long timepass = 0;
//4.如果response没有值就一直暂停
while (response == null) {
try {
//计算等待时间
long waittime = millis - timepass;
//判断是否超时
if (waittime<=0){
break;
}
//4.暂停 传入等待参数
this.wait(waittime);
} catch (InterruptedException e) {
e.printStackTrace();
}
//每一花费的时间等于现在的系统时间减去开始时间
timepass = System.currentTimeMillis() - start;
log.info("timepass{}",timepass);
}
//5.如果response不是null就返回
return response;
}
//6.set方法加锁
public synchronized void setResponse(String s) {
//7.给response赋值
this.response = s;
//8.唤醒等待的线程
this.notify();
}
}
3.5 多任务版 GuardedObject
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-MbqSu8ay-1655016006797)(F:Java_notejava笔记img多任务GuardedObject.png)]
package com.zjc.study.day611;
import lombok.extern.slf4j.Slf4j;
import java.util.Hashtable;
import java.util.Map;
import java.util.Set;
public class test2 {
public static void main(String[] args) throws InterruptedException {
for (int i = 0; i < 3; i++) {
new People().start();
}
Thread.sleep(1000);
for (Integer id : Mailboxes.getIds()) {
new Postman(id, "内容" + id).start();
}
}
}
@Slf4j
class People extends Thread{
@Override
public void run() {
NewGuardedObject guardedObject = Mailboxes.createGuardedObject();
log.debug("开始收信 id:{}", guardedObject.getId());
// 收信 如果时间范围内收到了就返回mail就有值 否则就是null
Object mail = guardedObject.get(5000);
log.debug("收到信 id:{}, 内容:{}", guardedObject.getId(), mail);
}
}
@Slf4j
class Postman extends Thread {
private int id;
private String mail;
public Postman(int id, String mail) {
this.id = id;
this.mail = mail;
}
@Override
public void run() {
//获得到该给那个放
NewGuardedObject guardedObject = Mailboxes.getGuardedObject(id);
log.debug("送信 id:{}, 内容:{}", id, mail);
//这块才将内容放进去
guardedObject.complete(mail);
}
}
class Mailboxes {
private static Map boxes = new Hashtable<>();
private static int id = 1;
// 产生唯一 id 需要加锁
private static synchronized int generateId() {
return id++;
}
public static NewGuardedObject getGuardedObject(int id) {
return boxes.remove(id);
}
public static NewGuardedObject createGuardedObject() {
NewGuardedObject go = new NewGuardedObject(generateId());
boxes.put(go.getId(), go);
return go;
}
public static Set getIds() {
return boxes.keySet();
}
}
class NewGuardedObject {
// 标识 Guarded Object
private int id;
public NewGuardedObject(int id) {
this.id = id;
}
public int getId() {
return id;
}
// 结果
private Object response;
// 获取结果
// timeout 表示要等待多久 2000
public Object get(long timeout) {
synchronized (this) {
// 开始时间 15:00:00
long begin = System.currentTimeMillis();
// 经历的时间
long passedTime = 0;
while (response == null) {
// 这一轮循环应该等待的时间
long waitTime = timeout - passedTime;
// 经历的时间超过了最大等待时间时,退出循环
if (timeout - passedTime <= 0) {
break;
}
try {
this.wait(waitTime); // 虚假唤醒 15:00:01
} catch (InterruptedException e) {
e.printStackTrace();
}
// 求得经历时间
passedTime = System.currentTimeMillis() - begin; // 15:00:02 1s
}
return response;
}
}
// 产生结果
public void complete(Object response) {
synchronized (this) {
// 给结果成员变量赋值
this.response = response;
this.notifyAll();
}
}
}



