调用等待并通知的两个线程

时间:2014-09-04 19:40:13

标签: java multithreading wait

我所见过的代码并没有像我预期的那样有效。

static Integer sync = 1;

    static void m() throws Exception {
        synchronized (sync) {
            System.err.println("First");
            sync.notify();
            sync.wait(1000L);
            System.err.println("Second");
            System.err.println("Third");
        }
    }

    public static void main(String[] args) throws Exception {
        Runnable r = new Runnable() {
            @Override
            public void run() {
                try {
                    m();
                } catch (Exception ex) {
                    Logger.getLogger(IO.class.getName()).log(Level.SEVERE, null, ex);
                }
            }
        };
        Runnable t = new Runnable() {
            @Override
            public void run() {
                try {
                    m();
                } catch (Exception ex) {
                    Logger.getLogger(IO.class.getName()).log(Level.SEVERE, null, ex);
                }
            }
        };
        Thread th1 = new Thread(r);
        Thread th2 = new Thread(t);
        th1.run();
        th2.run();
   }

我们有两个线程执行m()的syncjronized语句。当第一个线程执行一个并遇到wait()时,它将被添加到等待集中。在此之后,第二个线程开始执行synchronized语句,并执行notify()。由于输出必须

First
First
....

但实际上它是

First
Second
Third
First
Second
Third

为什么?

3 个答案:

答案 0 :(得分:4)

首先,您的程序没有创建任何线程。您必须调用th1.start()和th2.start()来创建线程。

t.start()是库为您启动线程时要调用的代码提供的方法。 run()是为库提供在新线程中调用的方法。您的run()方法定义了线程将执行的操作。 IMO,run()是一个非常误导的名字。

其次,通知()和等待()不要做你认为他们会做的事情。特别是,如果当前没有其他线程在sync.wait()中,sync.notify()根本不会做任何事情。

使用notify()和wait()的正确方法是,一个线程执行此操作:

synchronized(lock) {
    while (! someCondition()) {
         lock.wait()
    }
    doSomethingThatRequiresSomeConditionToBeTrue();
}

另一个线程执行此操作

synchronized(lock) {
    doSomethingThatMakesSomeConditionTrue();
    lock.notify();
}

使用此模式时,除了在同步(锁定)块内部之外,任何线程都不应更改someCondition()的结果。

答案 1 :(得分:1)

首先,要实际创建新线程,请使用

th1.start() th2.start()

inplace of run(),它只是对线程对象的常规方法调用。

其次,第二个帖子可能是第二个' th'在1000毫秒被填充时没有开始运行,所以第一个线程完成了等待(1000)并执行了剩余的代码行。

如果您想要输出如下:

first
first
second
third
second
third

然后删除wait()的时间间隔,这将使线程等到通知为止。 如:

static void m() throws Exception {
        synchronized (sync) {
            System.err.println("First");
            sync.notify();
            sync.wait();
            System.err.println("Second");
            System.err.println("Third");
        }
    }

答案 2 :(得分:1)

  1. 使用.start()代替run()将可运行的内容添加到队列中而不是立即运行它们

  2. Documentation表示wait超时等待此对象上的任何notify 超时。在你的情况下,一个接一个地执行runnables它会:

    • r:首先
    • r:等待1000毫秒并尝试锁定
    • r:它已经可以访问锁定对象(这个代码完全锁定了)所以继续
    • r:第二
    • r:第三
    • t:首先,等等......
  3. PS。调用run()而没有设置超时会导致t等待死锁,因为它已经有了对象,但是等待永远不会被通知。

    希望这有帮助。