如何使用多个线程的wait和notify协议 [英] How to use wait and notify protocol with multiple threads

查看:112
本文介绍了如何使用多个线程的wait和notify协议的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

具体来说,有人可以告诉我这段代码有什么问题。它应该启动线程,所以应该打印输入线程...5次,然后等到调用notifyAll()。但是,它随机打印Entering ..和Done ..并且仍在等待其他人。

Specifically, can somebody tell me what is wrong with this piece of code. It should start the threads, so should print "Entering thread.." 5 times and then wait until notifyAll() is called. But, it randomly prints "Entering.." and "Done.." and still keeps waiting on others.

public class ThreadTest implements Runnable {
    private int num;
    private static Object obj = new Object();
    ThreadTest(int n) {
        num=n;
    }
    @Override
    public void run() {
        synchronized (obj) {
            try {
                System.out.println("Entering thread "+num);
                obj.wait();
                System.out.println("Done Thread "+num);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }   
        }   
    }   

    public static void main(String[] args) {
        Runnable tc;
        Thread t;
        for(int i=0;i<5;i++) {
            tc = new ThreadTest(i);
            t = new Thread(tc);
            t.start();
        }
        synchronized (obj) {
            obj.notifyAll();
        }
    }
}


推荐答案

你没有对方法调用做任何明显的错误,但你有一个竞争条件

You're not doing anything blatantly wrong with the method calls, but you have a race condition.

虽然在理想的世界中主线程将在所有工作线程到达wait()调用后到达其synchronized块,无法保证那个(你明确地告诉虚拟机你不希望线程通过使它们成为线程来与主线程一起执行)。可能会发生(例如,如果您只有一个核心)线程调度程序决定立即阻止所有工作线程,它们开始允许主线程继续。可能由于高速缓存未命中而将工作线程切换出上下文。可能是一个工作线程阻塞I / O(print语句),主线程在其位置切换。

Although in an ideal world the main thread will reach its synchronized block after all the worker threads reach the wait() call, there is no guarantee of that (you explicitly told the virtual machine that you didn't want the threads to execute in sequence with the main thread by making them threads). It may happen (e.g. if you have only one core) that the thread scheduler decides to block all the worker threads immediately they start to allow the main thread to continue. It may be that the worker threads are context switched out because of a cache miss. It may be that one worker thread blocks for I/O (the print statement) and the main thread is switched in in its place.

因此,如果主线程管理要在所有工作线程到达wait()调用之前到达同步块,那些尚未到达wait()调用的工作线程将无法按预期运行。由于当前设置不允许您控制此操作,因此必须添加对此的显式处理。您可以添加某种变量,当每个工作线程到达wait()并且主线程不调用notifyAll()直到此变量达到5,或者您可以让主线程循环并重复调用notifyAll()时,会增加某种变量。以便工作线程在多个组中发布。

Thus, if the main thread manages to reach the synchronized block before all the worker threads have reached the wait() call, those worker threads that have not reached the wait() call will fail to operate as intended. Since the current set up does not allow you to control this, you must add explicit handling of this. You could either add some sort of variable that is incremented as each worker thread reaches wait() and have the main thread not call notifyAll() until this variable reaches 5, or you could have the main thread loop and repeatedly call notifyAll(), so that worker threads are released in multiple groups.

查看 java.util.concurrent 包 - 有几个锁类提供比基本同步锁更强大的功能 - 一如既往,Java可以避免重新发明轮子。 CountDownLatch 似乎特别相关。

Have a look in the java.util.concurrent package - there are several lock classes that provide more powerful capabilities than basic synchronized locks - as ever, Java saves you from re-inventing the wheel. CountDownLatch would seem to be particularly relevant.

总之,并发性是 hard 。您必须设计以确保当线程在您不想要的订单中执行时所有内容仍然有效,以及您希望的订单。

In summary, concurrency is hard. You have to design to make sure that everything still works when the threads execute in the orders you don't want, as well as the orders you would like.

这篇关于如何使用多个线程的wait和notify协议的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆