多线程设计模式-保护性暂停模式

利用wait和notify方法实现

有这么一个场景,我们有两个线程,其中一个线程需要等待获取另外一个线程的执行结果,之气那我们是使用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方法的底层实现原理,这里面也用到了超时等待,我们上面所写的就是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();
        }

h

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

北海冥鱼未眠

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值