栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 面试经验 > 面试问答

在Java中使用wait()和notify()的简单场景

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

在Java中使用wait()和notify()的简单场景

wait()
notify()
方法被设计为提供一种机制,以允许一个线程块,直到一个特定的条件被满足。为此,我假设你要编写一个阻塞队列实现,其中具有一些固定大小的元素后备存储。

你要做的第一件事是确定你希望方法等待的条件。在这种情况下,你将希望该

put()
方法阻塞直到存储空间可用,并且你将希望该
take()
方法阻塞直到返回某些元素。

public class BlockingQueue<T> {    private Queue<T> queue = new linkedList<T>();    private int capacity;    public BlockingQueue(int capacity) {        this.capacity = capacity;    }    public synchronized void put(T element) throws InterruptedException {        while(queue.size() == capacity) { wait();        }        queue.add(element);        notify(); // notifyAll() for multiple producer/consumer threads    }    public synchronized T take() throws InterruptedException {        while(queue.isEmpty()) { wait();        }        T item = queue.remove();        notify(); // notifyAll() for multiple producer/consumer threads        return item;    }}

关于必须使用等待和通知机制的方式,需要注意一些事项。

首先,你需要确保对代码的任何调用

wait()
notify()
在代码的同步区域内(并且
wait()
notify()
调用在同一对象上同步)。造成这种情况的原因(除了标准线程安全问题之外)是由于某种原因导致的信号丢失。

这样的一个示例是,

put()
当队列碰巧已满时,线程可能会调用,然后它检查条件,发现队列已满,但是在它可以阻止另一个线程调度之前。然后,第二个线程
take()
是队列中的一个元素,并通知等待线程该队列不再满。但是,由于第一个线程已经检查了条件,因此
wait()
即使可以进行进度,它也将在重新调度后简单地进行调用。

通过在共享库上同步,可以确保不会发生此问题,因为在第

take()
一个线程实际被阻塞之前,第二个线程的调用将无法进行。

其次,由于称为虚假唤醒的问题,你需要将要检查的条件放入while循环中,而不是if语句中。在这里有时可以在不

notify()
调用等待线程的情况下重新激活它。将此检查置于
while
循环中将确保如果发生虚假唤醒,将重新检查条件,并且线程将
wait()
再次调用。

就像其他答案中提到的那样,Java 1.5引入了一个新的并发库(在

java.util.concurrent
包中),该库旨在在等待/通知机制上提供更高级别的抽象。使用这些新功能,你可以像这样重写原始示例:

public class BlockingQueue<T> {    private Queue<T> queue = new linkedList<T>();    private int capacity;    private Lock lock = new ReentrantLock();    private Condition notFull = lock.newCondition();    private Condition notEmpty = lock.newCondition();    public BlockingQueue(int capacity) {        this.capacity = capacity;    }    public void put(T element) throws InterruptedException {        lock.lock();        try { while(queue.size() == capacity) {     notFull.await(); } queue.add(element); notEmpty.signal();        } finally { lock.unlock();        }    }    public T take() throws InterruptedException {        lock.lock();        try { while(queue.isEmpty()) {     notEmpty.await(); } T item = queue.remove(); notFull.signal(); return item;        } finally { lock.unlock();        }    }}

当然,如果你实际上需要阻塞队列,则应该使用BlockingQueue接口的实现 。

另外,对于这种事情,我强烈建议在实践中使用Java Concurrency,因为它涵盖了你可能希望了解的与并发相关的问题和解决方案的所有内容。



转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/402386.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

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

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