Javaマルチスレッド同期モードでの保護の一時停止

1.保護サスペンションの定義

つまり、あるスレッドで別のスレッドの実行結果を待機するために使用されるGuardedSuspensionです。

フォーカス:

  • 同じGuardedObjectに関連付けられるように、あるスレッドの結果を別のスレッドに渡す必要があります。
  • あるスレッドから別のスレッドに継続的に渡される結果がある場合は、メッセージキューを考慮する必要があります
  • JDKでは、join()とFutureがこのモードを採用しています
  • これは一方のパーティがもう一方のパーティを待機した結果であるため、これはすべて同期モードです。

アイコン:
ここに画像の説明を挿入

2.実現

上の図によると、t2スレッドが応答をダウンロードするのを待つt1スレッドを実装します

@Slf4j(topic = "c.TestGuardedObject")
public class TestGuardedObject {
    
    
    public static void main(String[] args) {
    
    
        GuardedObject guardedObject = new GuardedObject();
        new Thread(()->{
    
    
            List<String> list = (List<String>) guardedObject.get();
            log.debug("t1获取到结果");
            log.debug("文件大小:" + list.size());
        },"t1").start();

        new Thread(()->{
    
    
            try {
    
    
                List<String> download = download();
                log.debug("t2下载完成");
                guardedObject.complate(download);
                log.debug("t2任务完成");
            } catch (IOException e) {
    
    
                e.printStackTrace();
            }
        },"t2").start();
    }

}

class GuardedObject{
    
    

    private Object response;
    private final Object lock = new Object();

    //去GuardedObject取结果
    public Object get(){
    
    
        synchronized (lock){
    
    
            //没有结果则等待
            while(response == null){
    
    
                try {
    
    
                    lock.wait();
                } catch (InterruptedException e) {
    
    
                    e.printStackTrace();
                }
            }
        }
        return response;
    }

    //给GuardedObject设置结果
    void complate(Object response){
    
    
        synchronized (lock){
    
    
            this.response = response;
            lock.notifyAll();
        }
    }
}

ダウンロードツール:

public class Downloader {
    
    
    public static List<String> download() throws IOException {
    
    
        HttpURLConnection conn = (HttpURLConnection) new URL("https://www.baidu.com/").openConnection();
        List<String> lines = new ArrayList<>();
        try (BufferedReader reader =
                     new BufferedReader(new InputStreamReader(conn.getInputStream(), StandardCharsets.UTF_8))) {
    
    
            String line;
            while ((line = reader.readLine()) != null) {
    
    
                lines.add(line);
            }
        }
        return lines;
    }
}

タイムアウトバージョンのGuardedObject

永遠に待つことはできませんよね?t2を1年間ダウンロードする場合、t1はもう1年待つ必要がありますか?
タイムアウト待機を設定するにはどうすればよいですか?

@Slf4j(topic = "c.TestGuardedObject")
public class TestGuardedObject {
    
    
public static void main(String[] args) {
    
    
        GuardedObject guardedObject = new GuardedObject();
        new Thread(()->{
    
    
            log.debug("开始");
            Object o = guardedObject.get(2000);
            log.debug("结果:{}",o);
        },"t1").start();

        new Thread(()->{
    
    
            log.debug("开始");
            try {
    
    
                Thread.sleep(3000);
                guardedObject.complate(1111);
            } catch (InterruptedException e) {
    
    
                e.printStackTrace();
            }
            log.debug("结束");
        },"t2").start();
    }

class GuardedObject{
    
    

    private Object response;
    private final Object lock = new Object();

    //去GuardedObject取结果,有点不好理解
    public Object get(long timeout){
    
    
        synchronized (lock){
    
    
            //记录最初的是按
            long begin = System.currentTimeMillis();
            long passed = 0;
            //没有结果则等待
            while(response == null){
    
    
                long waitTime = timeout - passed;
                if(waitTime <= 0){
    
    
                    break;
                }
                try {
    
    
                    //如果不满足waitTime <= 0,说明还需要等待
                   //用waitTime不用timeout是为了防止被打断,时间反被延迟
                    lock.wait(waitTime);
                } catch (InterruptedException e) {
    
    
                    e.printStackTrace();
                }
                //经历的时间
                passed = System.currentTimeMillis() - begin;
            }
        }
        return response;
    }

    //给GuardedObject设置结果
    void complate(Object response){
    
    
        synchronized (lock){
    
    
            this.response = response;
            lock.notifyAll();
        }
    }

}

Join()の原則

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;
         }
     }
 }

スレッドがまだ生きている間

 while (isAlive()) {
    
    
             long delay = millis - now;
             if (delay <= 0) {
    
    
                 break;
             }
             wait(delay);
             now = System.currentTimeMillis() - base;
         }

このコードは、保護一時停止モードの使用も示しています。

マルチタスク用のGuardedObject

ここに画像の説明を挿入
図と同様に、現時点では、一意のIDで識別される複数のGuardedObjectがあり、各GuardedObjectは通信のために2つのスレッドに接続されています。設計モードは、同期モードの保護的な一時停止です。

@Slf4j(topic = "c.TestGuardedObject")
public class TestGuardedObject {
    
    
    public static void main(String[] args) {
    
    

        //3个人收信
        for (int i = 0; i < 3; i++) {
    
    
            new Person().start();
        }
        Sleeper.sleep(1);
        //读取信内容
        for (Integer id : Mailboxes.getIds()) {
    
    
            new PostMan(id, "内容" + id).start();
        }

    }

}
@Slf4j(topic = "c.Person")
class Person extends Thread{
    
    
    @Override
    public void run() {
    
    
        GuardedObject guardedObject = Mailboxes.createGuardedObject();
        log.debug("开始收信 id:{}", guardedObject.getId());
        Object mail = guardedObject.get(5000);
        log.debug("收到信 id:{}, 内容:{}", guardedObject.getId(), mail);

    }
}
@Slf4j(topic = "c.PostMan")
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() {
    
    
        GuardedObject guardedObject = Mailboxes.getGuardedObject(id);
        log.debug("送信 id:{}, 内容:{}", id, mail);
        guardedObject.complate(mail);
    }
}

//信箱类,解耦收信人和邮递员
class Mailboxes{
    
    
    //保证信箱id唯一
    private static int id;

    private static Map<Integer,GuardedObject> map = new Hashtable<>();

    //根据id取信
    public static GuardedObject getGuardedObject(int id){
    
    
        return map.remove(id);
    }

    //生成一个唯一信封的id
    public static synchronized int generatorId(){
    
    
        return id ++;
    }

    //创建信件
    public static GuardedObject createGuardedObject(){
    
    
        GuardedObject guardedObject = new GuardedObject(generatorId());
        map.put(guardedObject.getId(),guardedObject);
        return guardedObject;
    }
    //获取信件id集合
    public static Set<Integer> getIds(){
    
    
        return map.keySet();
    }
}

class GuardedObject{
    
    

    //新增id来标识GuardedObject
    private Integer id;

    public Integer getId() {
    
    
        return id;
    }

    public void setId(Integer id) {
    
    
        this.id = id;
    }

    public GuardedObject(Integer id) {
    
    
        this.id = id;
    }

    private Object response;
    private final Object lock = new Object();

    //去GuardedObject取结果
    public Object get(long timeout){
    
    
        synchronized (lock){
    
    
            //记录最初的是按
            long begin = System.currentTimeMillis();
            long passed = 0;
            //没有结果则等待
            while(response == null){
    
    
                long waitTime = timeout - passed;
                if(waitTime <= 0){
    
    
                    break;
                }
                try {
    
    
                    //如果不满足waitTime <= 0,说明还需要等待
                    //用waitTime不用timeout是为了防止被打断,时间反被延迟
                    lock.wait(waitTime);
                } catch (InterruptedException e) {
    
    
                    e.printStackTrace();
                }
                //经历的时间
                passed = System.currentTimeMillis() - begin;
            }
        }
        return response;
    }

    //给GuardedObject设置结果
    void complate(Object response){
    
    
        synchronized (lock){
    
    
            this.response = response;
            lock.notifyAll();
        }
    }

}

出力:
ここに画像の説明を挿入
出力結果から判断すると、これらはすべて1対1の対応であり、それらの間のブリッジはGuardedObjectの一意のIDです。

学習資料:https://www.bilibili.com/video/BV16J411h7Rd?p = 105&spm_id_from = pageDriver

おすすめ

転載: blog.csdn.net/JAYU_37/article/details/113444475
おすすめ