待機および通知メソッドを使用して実装
このようなシナリオがあります。2 つのスレッドがあり、そのうちの 1 つは他のスレッドの実行結果を待つ必要があります。その後、join メソッドを使用してそれを達成できますが、今は jon を使用してそれを達成していません。
package com.dongmu.test;
/**
* 多线程设计宝石之保护性暂停模式
*
* 这个设计模式相对于join方法有什么好处呢?
* 1:我们在工作线程结束之后还可以执行其他的操作,而join方法只能等待工作的线程执行结束之后才嫩返回
* 结果让主线程继续运行。
* 2:我们这里等待结果的变量是局部的而不是全局的。
*/
public class Test19 {
public static void main(String[] args) {
GuardedObject guardedObject = new GuardedObject();
new Thread(()->{
Object o = guardedObject.get();
System.out.println("等待获取数据成功");
},"t1").start();
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
new Thread(()->{
guardedObject.cmplete();
},"t2").start();
}
}
class GuardedObject{
// 需要获取的结果
private Object response;
private Object lock = new Object();
public Object get(){
synchronized (lock){
while (response==null){
try {
lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
return response;
}
}
public void cmplete(){
synchronized (lock){
response = new Object();
lock.notifyAll();
}
}
}
タイムアウトを設定できる get メソッド
public Object get(long timeout){
long now = System.currentTimeMillis();
long passtime = 0;
synchronized (lock){
while (response==null){
if (passtime>=timeout) break;
try {
// 这里这么写是为了避免虚假唤醒的问题。也就是调用complete方法传递null值
lock.wait(timeout-passtime);
} catch (InterruptedException e) {
e.printStackTrace();
}
passtime = System.currentTimeMillis() - now;
}
return response;
}
}
同時に、タイムアウト待機を使用する join メソッドの基本的な実装原理を確認することもできます. 上で書いたのは、結合タイムアウト待機の実装原理です.
public final synchronized void join(long millis)
throws InterruptedException {
long base = System.currentTimeMillis();
long now = 0;
if (millis < 0) {
throw new IllegalArgumentException("timeout value is negative");
}
if (millis == 0) {
while (isAlive()) {
wait(0);
}
} else {
while (isAlive()) {
long delay = millis - now;
if (delay <= 0) {
break;
}
wait(delay);
now = System.currentTimeMillis() - base;
}
}
}
上記はすべてシングルタスクのケースですが、上記のコードをマルチタスク バージョンに変更することもできます。
マルチタスク版
次のコードを GuradeObject クラスに追加します。
private int id;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public GuardedObject(int id) {
this.id = id;
}
そして、GuardedObject クラスを格納するパブリック クラスを作成します。
/*
这个MailBox是一个通用类,而上面的Postman和people都是和业务相关的代码,以后可以根据业务逻辑来实现
*/
class MailBox{
private static Map<Integer,GuardedObject> map = new ConcurrentHashMap<>();
private static int id = 1;
private static synchronized int getId(){
return id++;
}
public static GuardedObject getGuardedObject(int id){
return map.remove(id);
}
public static GuardedObject createGurdeObject (){
GuardedObject guardedObject = new GuardedObject(getId());
map.put(guardedObject.getId(),guardedObject);
return guardedObject;
}
public static Set<Integer> getIds(){
return map.keySet();
}
}
同時に業務クラスの作成、タスクの追加、実行結果の取得をそれぞれ行う
class People extends Thread{
@Override
public void run() {
GuardedObject gurdeObject = MailBox.createGurdeObject();
System.out.println("线程id"+gurdeObject.getId()+" 开始接收内容");
Object o = gurdeObject.get();
System.out.println("线程id"+gurdeObject.getId()+",获取到内容:"+o);
}
}
class PostMan extends Thread{
private int id;
public PostMan( int id) {
this.id = id;
}
@Override
public void run() {
GuardedObject guardedObject = MailBox.getGuardedObject(id);
guardedObject.cmplete("线程:"+id);
}
}
最後にテストするコードを書く
for (int i = 0; i < 3; i++) {
new People().start();
}
Thread.sleep(2000);
for (Integer id : MailBox.getIds()) {
new PostMan(id).start();
}