如何在多线程中使用等待和通知协议

2024-01-31

具体来说,有人可以告诉我这段代码有什么问题吗?它应该启动线程,因此应该打印“Entering thread..”5次,然后等待,直到调用notifyAll()。但是,它随机打印“正在输入..”和“完成..”,并且仍然继续等待其他人。

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();
        }
    }
}

您没有对方法调用做任何明显错误的事情,但是您有一个竞争条件 http://en.wikipedia.org/wiki/Race_condition.

尽管在理想情况下,主线程将在所有工作线程到达 wait() 调用后到达其同步块,无法保证这一点(您通过将线程设置为线程来明确告诉虚拟机您不希望线程与主线程一起按顺序执行)。线程调度程序可能会决定立即阻止所有工作线程(例如,如果您只有一个核心),以允许主线程继续运行。工作线程可能由于缓存未命中而被上下文切换。可能有一个工作线程因 I/O(打印语句)而阻塞,并且主线程被切换到其位置。

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

看看java.util.concurrent包 - 有几个锁类提供比基本同步锁更强大的功能 - 一如既往,Java 使您免于重新发明轮子。倒计时锁存器 http://download.oracle.com/javase/6/docs/api/java/util/concurrent/CountDownLatch.html似乎特别相关。

总结起来,并发就是hard。您必须进行设计,以确保当线程按照您不想要的顺序以及您想要的顺序执行时,一切仍然有效。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何在多线程中使用等待和通知协议 的相关文章

随机推荐