java中使用wait()和notify()的简单场景
我可以获得一个完整的简单场景,即建议如何使用它的教程,特别是使用队列?
Can I get a complete simple scenario i.e. tutorial that suggest how this should be used, specifically with a Queue?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(8)
wait()
和notify()
方法旨在提供一种机制,允许线程阻塞直到满足特定条件。为此,我假设您想要编写一个阻塞队列实现,其中有一些固定大小的元素后备存储。您要做的第一件事是确定您希望方法等待的条件。在这种情况下,您将希望
put()
方法阻塞,直到存储中有可用空间,并且您将希望take()
方法阻塞,直到有可用空间。是一些要返回的元素。关于使用等待和通知机制的方式,有几点需要注意。
首先,您需要确保对
wait()
或notify()
的任何调用都位于代码的同步区域内(使用wait()
> 和notify()
调用在同一对象上同步)。造成这种情况的原因(除了标准线程安全问题之外)是由于丢失信号造成的。一个例子是,当队列碰巧已满时,线程可能会调用 put() ,然后它会检查条件,发现队列已满,但是在它可以阻止另一个线程之前已安排。然后,第二个线程从队列中
take()
获取一个元素,并通知等待线程队列已满。然而,因为第一个线程已经检查了条件,所以即使它可以取得进展,它也会在重新调度后简单地调用wait()
。通过同步共享对象,您可以确保不会发生此问题,因为在第一个线程实际阻塞之前,第二个线程的
take()
调用将无法取得进展。其次,由于存在称为虚假唤醒的问题,您需要将要检查的条件放入 while 循环中,而不是 if 语句中。有时可以在不调用
notify()
的情况下重新激活等待线程。将此检查放入 while 循环中将确保如果发生虚假唤醒,将重新检查条件,并且线程将再次调用wait()
。正如其他一些答案所提到的,Java 1.5 引入了一个新的并发库(在 java.util.concurrent 包中),该库旨在为等待/通知机制提供更高级别的抽象。使用这些新功能,您可以像这样重写原始示例:
当然,如果您确实需要一个阻塞队列,那么您应该使用 BlockingQueue 接口。
另外,对于这样的东西,我强烈推荐 Java Concurrency在实践中,因为它涵盖了您可能想了解的有关并发相关问题和解决方案的所有内容。
The
wait()
andnotify()
methods are designed to provide a mechanism to allow a thread to block until a specific condition is met. For this I assume you're wanting to write a blocking queue implementation, where you have some fixed size backing-store of elements.The first thing you have to do is to identify the conditions that you want the methods to wait for. In this case, you will want the
put()
method to block until there is free space in the store, and you will want thetake()
method to block until there is some element to return.There are a few things to note about the way in which you must use the wait and notify mechanisms.
Firstly, you need to ensure that any calls to
wait()
ornotify()
are within a synchronized region of code (with thewait()
andnotify()
calls being synchronized on the same object). The reason for this (other than the standard thread safety concerns) is due to something known as a missed signal.An example of this, is that a thread may call
put()
when the queue happens to be full, it then checks the condition, sees that the queue is full, however before it can block another thread is scheduled. This second thread thentake()
's an element from the queue, and notifies the waiting threads that the queue is no longer full. Because the first thread has already checked the condition however, it will simply callwait()
after being re-scheduled, even though it could make progress.By synchronizing on a shared object, you can ensure that this problem does not occur, as the second thread's
take()
call will not be able to make progress until the first thread has actually blocked.Secondly, you need to put the condition you are checking in a while loop, rather than an if statement, due to a problem known as spurious wake-ups. This is where a waiting thread can sometimes be re-activated without
notify()
being called. Putting this check in a while loop will ensure that if a spurious wake-up occurs, the condition will be re-checked, and the thread will callwait()
again.As some of the other answers have mentioned, Java 1.5 introduced a new concurrency library (in the
java.util.concurrent
package) which was designed to provide a higher level abstraction over the wait/notify mechanism. Using these new features, you could rewrite the original example like so:Of course if you actually need a blocking queue, then you should use an implementation of the BlockingQueue interface.
Also, for stuff like this I'd highly recommend Java Concurrency in Practice, as it covers everything you could want to know about concurrency related problems and solutions.
不是队列示例,但非常简单:)
一些要点:
1) 永远不要
总是使用 while(condition),因为
从等待状态而不是
由任何人通知。 (即使当
披萨师傅没有按铃,
有人会决定尝试吃
比萨。)。
获得后再次条件
同步锁。就说披萨吧
不要永远持续下去。你醒了,
排队买披萨,但事实并非如此
对每个人来说都足够了。如果你不这样做
检查一下,你可能会吃纸! :)
(可能更好的例子是
while(!pizzaExists){ 等待(); }。
2)在调用wait/nofity之前必须持有锁(同步)。线程还必须在唤醒之前获取锁。
3)尽量避免在同步块中获取任何锁,并努力不调用外来方法(您不确定它们在做什么的方法)。如果必须的话,请务必采取措施避免僵局。
4) 小心使用notify()。坚持使用notifyAll(),直到你知道自己在做什么。
5)最后但并非最不重要的一点是,阅读Java 并发实践!
Not a queue example, but extremely simple :)
Some important points:
1) NEVER do
Always use while(condition), because
from waiting state without being
notified by anyone. (even when the
pizza guy didn't ring the chime,
somebody would decide try eating the
pizza.).
condition again after acquiring the
synchronized lock. Let's say pizza
don't last forever. You awake,
line-up for the pizza, but it's not
enough for everybody. If you don't
check, you might eat paper! :)
(probably better example would be
while(!pizzaExists){ wait(); }
.2) You must hold the lock (synchronized) before invoking wait/nofity. Threads also have to acquire lock before waking.
3) Try to avoid acquiring any lock within your synchronized block and strive to not invoke alien methods (methods you don't know for sure what they are doing). If you have to, make sure to take measures to avoid deadlocks.
4) Be careful with notify(). Stick with notifyAll() until you know what you are doing.
5)Last, but not least, read Java Concurrency in Practice!
即使您特别要求
wait()
和notify()
,我觉得这句话仍然足够重要:Josh Bloch,Effective Java 2nd Edition,第 69 条:优先使用并发实用程序而不是
wait
和notify
(强调他的):Even though you asked for
wait()
andnotify()
specifically, I feel that this quote is still important enough:Josh Bloch, Effective Java 2nd Edition, Item 69: Prefer concurrency utilities to
wait
andnotify
(emphasis his):您看过这个Java 教程吗?
此外,我建议您不要在真正的软件中使用此类东西。使用它很好,这样你就知道它是什么,但是并发到处都有陷阱。如果您正在为其他人构建软件,最好使用更高级别的抽象和同步集合或 JMS 队列。
至少我就是这么做的。我不是并发专家,因此我尽可能避免手动处理线程。
Have you taken a look at this Java Tutorial?
Further, I'd advise you to stay the heck away from playing with this kind of stuff in real software. It's good to play with it so you know what it is, but concurrency has pitfalls all over the place. It's better to use higher level abstractions and synchronized collections or JMS queues if you are building software for other people.
That is at least what I do. I'm not a concurrency expert so I stay away from handling threads by hand wherever possible.
例子
Example
该问题要求使用涉及队列(缓冲区)的 wait() + notification() 。首先想到的是使用缓冲区的生产者-消费者场景。
我们系统中的三个组件:
生产者线程:
生产者将值插入缓冲区,直到缓冲区已满。
如果缓冲区已满,生产者调用 wait() 并进入等待阶段,直到消费者唤醒它。
消费者线程:
消费者线程从缓冲区中删除值,直到缓冲区为空。
如果缓冲区为空,消费者调用 wait() 方法并进入等待状态,直到生产者发送通知信号。
UTIL 方法:
应用程序代码:
示例输出:
The question asks for a wait() + notify() involving a queue(buffer). The first thing that comes to mind is a producer-consumer scenario using a buffer.
Three Components in our system:
PRODUCER THREAD:
The producer inserts values in the buffer and until the buffer is full.
If the buffer is full, the producer call wait() and enters the wait stage, until the consumer awakes it.
CONSUMER THREAD:
Consumer thread removes value from the buffer until the buffer is empty.
If the buffer is empty, consumer calls wait() method and enter wait state until a producer sends a notify signal.
UTIL METHOD:
Application Code:
A Sample Output:
对于等待通知的简单场景,我们将考虑 2 个线程:
1)线程“计算”,它为我们提供从 0 到 5 的所有数字的总和
2)线程“ >WaitNotifyDemo”,这是主线程
目标:我们希望WaitNotifyDemo线程等待,直到Calculate线程完成计算
步骤1]首先让我们创建一个线程来计算sum:
}
这个类有:
第 2 步] 让我们创建使用 wait 方法的类它用于使主线程直到计算完成
这个类有:
Output
所以我们可以看到我们在一个对象上调用了 wait ,这使得主线程等待计算,然后执行该类的剩余代码。
For a simple scenario of wait notify we will consider 2 threads :
1)Thread "Calculate" which gives us sum of all number from 0 to 5
2)Thread "WaitNotifyDemo" which is main thread
Objective : We want WaitNotifyDemo thread to wait till Calculate thread completes the calculation
Step 1] First lets create a thread that calculates the sum:
}
This class has :
Step 2] lets create class which uses wait method which is used to make the Main thread till calculation completes
This class has :
Output
So we can see that we have called wait on an object which makes main thread wait for calculation and then executes remaining code of the class.
线程中 wait() 和 notifyall() 的示例。
同步静态数组列表用作资源,如果数组列表为空,则调用 wait() 方法。一旦为数组列表添加了一个元素,notify() 方法就会被调用。
Example for wait() and notifyall() in Threading.
A synchronized static array list is used as resource and wait() method is called if the array list is empty. notify() method is invoked once a element is added for the array list.