【并发编程】同步模式之保护性暂停

发布时间:2024年01月19日

? ? ? ?📝个人主页:五敷有你? ? ??
?🔥系列专栏:并发编程
??稳中求进,晒太阳

同步模式之保护性暂停

这个模式用到的基础就是wait-notify

详情可以看这篇文章=:【并发编程】wait/notify

即Guarded Suspension,用在一个线程等待另一个线程的执行结果

要点:

  • 有一个结果需要从一个线程传递到另一个线程,让他们关联同一个GuardedObject
  • 如果有结果不断从一个线程到另一个线程那么可以使用消息队列(见 生产者 消费者)
  • JDK中 join的实现,Future的实现,采用的就是此模式
  • 因为要等待另一方的结果,因此归类到同步模式

实现

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) {
                        e.printStackTrace();
                    }
                }
                return response;
            }
        }
        
        public void complete(Object response) {
            synchronized (lock) {
                // 条件满足,通知等待线程
                this.response = response;
                lock.notifyAll();
            }
        }
}

应用

普通版GuardedObject

一个线程等待另一个线程

 public static void main(String[] args) {
            GuardedObject guardedObject = new GuardedObject();
            new Thread(() -> {
                try {
                    // 子线程执行下载
                    List<String> response = download();
                    log.debug("download complete...");
                    guardedObject.complete(response);
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }).start();
            
            log.debug("waiting...");
            // 主线程阻塞等待
            Object response = guardedObject.get();
            log.debug("get response: [{}] lines", ((List<String>) response).size());
        }

执行结果

带超时版 GuardedObject

如果想要控制时间


class GuardedObjectV2 {
    private Object response;
    private final Object lock = new Object();
    public Object get(long millis) {
        synchronized (lock) {
            // 1) 记录最初时间
            long begin = System.currentTimeMillis();
            // 2) 已经经历的时间
            long timePassed = 0;
            while (response == null) {
            // 4) 假设 millis 是 1000,结果在 400 时唤醒了,那么还有 600 要等
                long waitTime = millis - timePassed;
                log.debug("waitTime: {}", waitTime);
                if (waitTime <= 0) {
                    log.debug("break...");
                    break;
                }
                try {
                    lock.wait(waitTime);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                // 3) 如果提前被唤醒,这时已经经历的时间假设为 400
                timePassed = System.currentTimeMillis() - begin;
                log.debug("timePassed: {}, object is null {}",
                        timePassed, response == null);
            }
            return response;
        }
    }
    public void complete(Object response) {
        synchronized (lock) {
            // 条件满足,通知等待线程
            this.response = response;
            log.debug("notify...");
            lock.notifyAll();
        }
    }
}

测试,没有超时情况

public static void main(String[] args) {
    GuardedObjectV2 v2 = new GuardedObjectV2();
    new Thread(() -> {
        sleep(1);
        v2.complete(null);
        sleep(1);
        v2.complete(Arrays.asList("a", "b", "c"));
    }).start();
    Object response = v2.get(2500);
    if (response != null) {
        log.debug("get response: [{}] lines", ((List<String>) response).size());
    } else {
        log.debug("can't get response");
    }
}

输出

测试,超时情况

// 等待时间不足List lines = v2.get(1500);

// 等待时间不足,修改时间1500
List lines = v2.get(1500);

输出

文章来源:https://blog.csdn.net/m0_62645012/article/details/135689115
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。