想象一下,你在Java中一个典型的生产者 - 消费者模式。 要有点更高效的要使用notify()
而不是notifyAll()
当新的元素添加到队列中。 如果两个生产者线程调用通知,是保证两个不同的等待消费者线程会被唤醒? 还是可以有两个notify()
S中的每个其他事业一样comsumer线程排队等待唤醒两次后不久开除了? 我无法找到部分是描述如何精确地工作的API。 请问java的有唤醒线程恰好一次一些原子内部操作?
如果只有一个comsumer等待那么第二个通知都将丢失,这是没有问题的。
我的回答有一些实施的具体信息。 它是基于Sun JVM和其他线程库的行为我的工作经验。
如果两个生产者线程调用通知,是保证两个不同的等待消费者线程会被唤醒?
不它不是。 谁也不能保证会有任何惊醒消费者。 什么是保证的是,如果有2个线程在等待,然后2个不同的线程将被放入运行队列。
还是可以有两个notify()
S中的每个其他事业一样comsumer线程排队等待唤醒两次后不久开除了?
二号notify()
调用不会导致同样的消费者线程排队两次。 但是,由于它可能会导致被唤醒一个线程,并有可能不会有其他线程等待,所以第二个notify()
调用可能什么也不做。 当然,线程可以被惊醒,然后走了右后卫再次等待,因此获得第二notify()
调用的方式,但我不认为认为,这是你的要求。
请问java的有唤醒线程恰好一次一些原子内部操作?
是。 该Thread
的代码有许多同步点。 一旦线程已经通知它被移出的wait
队列。 未来调用notify()
将寻找到wait
队列中,并没有找到线索。
一个更重要的一点。 随着生产者/消费者模型,始终确保您在测试条件while
循环。 其原因是,有竞争条件与被挡在了锁,但不等待条件的消费者。
synchronized (workQueue) {
// you must do a while here
while (workQueue.isEmpty()) {
workQueue.wait();
}
workQueue.remove();
}
Consumer1
可以等待workQueue
。 Consumer2
可能在被阻止synchronized
,但在运行队列。 如果事情被放入workQueue
和workQueue.notify()
被调用。 Consumer2
现已投入运行队列,但背后 Consumer1
谁是那里第一次。 这是一个常见的实现。 所以Consumer1
进去一个将删除的项目workQueue
是Consumer2
被通报了一下。 Consumer2
有再次测试,如果workQueue
为空,否则remove()
将抛出,因为队列为空一次。 在这里看到比赛的更多细节 。
同样重要的是要认识到虚假唤醒已被记录在案,因此while
循环防止一个线程被唤醒的无wait()
调用。
所有这一切都表示,如果可以通过使用降低生产者/消费者代码BlockingQueue
在其他的答案建议,那么你应该这样做。 该BlockingQueue
代码已经解决了所有这些问题。
是的,你描述会发生什么。
如在所描述的Javadoc , notify
唤醒一个任意的线程。 所以,如果你的线程执行完毕,并呼吁wait
先下一notify
,那么它是清醒的任意候选人之一。
我有一个多线程应用程序的丰富经验,我发现我使用这两种模式中的一种:
有哪些需要唤醒一个事件多线程睡眠,并在他们醒来无关紧要的顺序。 在这种情况下,我使用notifyAll
唤醒他们。
有哪些需要唤醒对某一事件的睡眠线程。 在这种情况下,我使用的notify
来唤醒它。
如果我有哪里有多个线程睡眠的情况下,我想只唤醒其中的一个,我用不同的设计来实现这一目标。 基本上,我打造出来的东西自己,所以有运行时环境中进行,不能任意决定。 我总是想知道会唤醒什么。
我打破设计成这两种情况之一,或我用从什么的java.util.concurrent包。 我从未有虚假通知的问题,但我还对我使用锁定的对象非常小心。 我往往把香草Object
实例,其唯一目的是为了锁定操作的目标,但偶尔我会使用一个对象的类类型的明确定义和我的控制之下。
从的Javadoc通知() :
其中螺纹的选择通知“是任意的,并在执行的自由裁量权发生”
这几乎肯定不会是一个“公平”的算法(如该术语在计算机科学和并行使用),以唤醒线程。 这是完全有可能的是同一个线程在连续快速唤醒的两倍。 还要注意的是虚假的通知也是可能的。
在一般情况下,我同意建议使用意见的BlockingQueue的实现,而不是这样做你自己。
您可以使用的ReentrantLock获得一个公平的到达顺序的政策。 接口ReadWriteLock中 ,你得到的生产者-消费者的行为。 类的ReentrantReadWriteLock结合这两种能力。
要么
您应该使用ArrayBlockingQueue ,在这种模式已经实施。
int capacity = 10;
boolean fair = true;
new ArrayBlockingQueue(capacity, fair);