栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

保护性暂停模式与join原理

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

保护性暂停模式与join原理

文章为在B站学习黑马并发编程视频整理笔记和个人理解,如果有错误,望指正

1.保护性暂停模式

通过wait和notify/notifyAll实现保护性暂停模式,即用在一个线程等待另一个线程的执行结果

要点:有一个结果需要从一个线程传递到另一个线程,让他们关联同一个 GuardedObject,如果有结果不断从一个线程到另一个线程那么可以使用消息队列(见生产者/消费者),JDK 中,join 的实现、Future 的实现,采用的就是此模式;

代码实现:

@Slf4j
public class TestGuardedObject {

    public static void main(String[] args) {
        //实现一个线程等待另一个线程的执行结果
        GuardedObject guardedObject = new GuardedObject();
        Thread thread = new Thread(() -> {
            log.info("进入阻塞来进行等待guardedObject返回");
            Object o = guardedObject.get(1000);
            log.info("返回结果为:{}", o);
        }, "t1");
        thread.start();

        new Thread(() -> {
            log.info("执行任务代码处理,耗时两秒");
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            guardedObject.complete("结果处理完成返回值");
        }, "t2").start();
    }

}

@Slf4j
class GuardedObject {
    private Object response;

    private final Object lock = new Object();

    public Object get() {
        synchronized (lock) {
            while (response == null) {
                try {
                    lock.wait();
                } catch (InterruptedException e) {
                    log.info("GuardedObject在get方法中被打断");
                }
            }
        }
        return response;
    }

    //带超时时间
    public Object get(long millis) {
        synchronized (lock) {
            long begin = System.currentTimeMillis();
            long passTime = 0;
            while (response == null) {
                //设置等待时间
                long waitTime = millis - passTime;
                if (waitTime <= 0) {
                    log.info("已经等待超时,跳出while...");
                    break;
                }
                try {
                    lock.wait(waitTime);
                } catch (InterruptedException e) {
                    log.info("GuardedObject在get方法中被打断");
                }
                //设置passTime的通过时间,防止条件不成立后仍然等待millis时间
                passTime = System.currentTimeMillis() - begin;
            }
        }
        return response;
    }

    public void complete(Object response) {
        synchronized (lock) {
            this.response = response;
            lock.notifyAll();
        }
    }
}

多线程版:

public class TestMultiGuardedObject {

    public static void main(String[] args) throws InterruptedException {
        for (int i = 0; i < 3; i++) {
            new Person().start();
        }
        Thread.sleep(3000);
        for (Integer id : MailBoxes.getIds()) {
            new Postman(id, id + "的信件").start();
        }
    }

}

//负责进行收信 查看个人的邮箱是否有信件
@Slf4j
class Person extends Thread {

    @Override
    public void run() {
        //人收信
        MultiGuardedObject multiGuardedObject = MailBoxes.createMultiGuardedObject();
        int id = multiGuardedObject.getId();
        log.info("开始收信,id为:{}", id);
        Object o = multiGuardedObject.get(5000);
        log.info("收到信件, 内容为:{}", o);
    }
}

//负责进行送信 查看邮箱是否有信件需要送
@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() {
        //开始送信到person他们的邮箱中
        log.info("开始送信,id={},mail={}", id, mail);
        MultiGuardedObject multiGuardedObject = MailBoxes.getMultiGuardedObject(id);
        multiGuardedObject.complete(mail);
    }
}

class MailBoxes {
    private static Map mailBox = new Hashtable<>();

    private static int i = 1;

    public static MultiGuardedObject createMultiGuardedObject() {
        int id = getId();
        MultiGuardedObject multiGuardedObject = new MultiGuardedObject(id);
        mailBox.put(id, multiGuardedObject);
        return multiGuardedObject;
    }

    public static MultiGuardedObject getMultiGuardedObject(int id) {
        MultiGuardedObject multiGuardedObject = mailBox.get(id);
        mailBox.remove(id);
        return multiGuardedObject;
    }

    public static Set getIds() {
        return mailBox.keySet();
    }

    private static synchronized int getId() {
        return i++;
    }
}

@Slf4j
class MultiGuardedObject {
    private int id;

    private Object response;

    private final Object lock = new Object();

    public MultiGuardedObject(int id) {
        this.id = id;
    }

    public int getId() {
        return id;
    }

    public Object get() {
        synchronized (lock) {
            while (response == null) {
                try {
                    lock.wait();
                } catch (InterruptedException e) {
                    log.info("GuardedObject在get方法中被打断");
                }
            }
        }
        return response;
    }

    //带超时时间
    public Object get(long millis) {
        synchronized (lock) {
            long begin = System.currentTimeMillis();
            long passTime = 0;
            while (response == null) {
                //设置等待时间
                long waitTime = millis - passTime;
                if (waitTime <= 0) {
                    log.info("已经等待超时,跳出while...");
                    break;
                }
                try {
                    lock.wait(waitTime);
                } catch (InterruptedException e) {
                    log.info("GuardedObject在get方法中被打断");
                }
                //设置passTime的通过时间,防止条件不成立后仍然等待millis时间
                passTime = System.currentTimeMillis() - begin;
            }
        }
        return response;
    }

    public void complete(Object response) {
        synchronized (lock) {
            this.response = response;
            lock.notifyAll();
        }
    }
}

分析主要流程逻辑大致如下

2.join方法实现原理

如下为join方法的源码截图

可以查看join方法的流程也是保护性暂停的流程逻辑,join方法不是一个static类型方法,所以synchronized锁的是当前的调用方,那么如果t1线程中操作t2线程的join方法,则通过isAlive判断t2线程是否仍然在运行,如果在运行就进入到阻塞,将t1线程加入到t2线程monitor锁的waitset中进入等待;并且加入while循环为了防止虚假唤醒;

代码逻辑大致相当于:

//t2线程对象即是lock锁,而且是线程对象可以判断是否正在运行
synchronized (t2) {
  // 调用者线程进入 t1 的 waitSet 等待, 直到 t1 运行结束
  while (t2.isAlive()) {
    //调用wait会让t1线程进入到阻塞
    t2.wait(0);
  }
}
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/930330.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号