Java等待/通知

时间:2015-02-14 00:35:20

标签: java notify

我试了很多年才找出为什么这不起作用但却找不到答案。 我想要做的是让两个班级“互相交谈”。 基本上我希望A做某事并为B做什么(同样为B)

class ParaTest {
    boolean aCanTalk;

    public static void main(String[] args) {
        Test t = new Test();
        t.t();
    }
}

class Test {
    boolean aCanTalk;
    Thread a;
    Thread b;
    void t() {
        aCanTalk = true;
        a = new Thread(new A(this));
        b = new Thread(new B(this));
        a.start();
        b.start();
    }
}

class A implements Runnable {
    Test t;
    A(Test t) {
        this.t = t;
    }

    public void run() {
        while(t.aCanTalk) {
            System.out.println("I am A");
            t.aCanTalk = false;
            synchronized(this) {
                notifyAll();
            }
            try {
                synchronized(t.b) {
                    t.b.wait();
                }
            } catch(InterruptedException e) {};
        }
    }
}

class B implements Runnable {
    Test t;
    B(Test t) {
        this.t = t;
    }

    public void run() {
        while(!t.aCanTalk) {
            System.out.println("I am B");
            t.aCanTalk = true;
            synchronized(this) {
                notify();
            }           
            try {
                synchronized(t.a) {
                    t.a.wait();
                }
            } catch(InterruptedException e) {};
        }       
    }
}

3 个答案:

答案 0 :(得分:1)

您的代码还有其他问题(见下文),但您遇到的问题是,因为在进入等待之前检查了条件,如B

  public void run() {
    while(!t.aCanTalk) {
    ....
    }
  }

如果t.aCanTalk为真,则run方法将返回,并且线程将死亡。

(我最初误读你的代码说明了以下内容:-))

那就是说,你应该重新构建代码,因为如果你使用更多的“打包”方法制作一个合适的监视器,它就不会出错,例如一个简单的rendez-vous示例:

class Test {
    private boolean aCanTalk = true;

    public synchronized waitA() {
        while(!aCanTalk) {
            wait();
        }
    }

    public synchronized signalB() {
        aCanTalk = false;
        notifyAll();
    }

    public synchronized waitB() {
        while(aCanTalk) {
            wait();
        }
    }

    public synchronized signalA() {
        aCanTalk = true;
        notifyAll();
    }
}

并在你的线程中使用它,例如 在A:

public void run() {
    while(true) {
        t.waitA();
        System.out.println("I am A");
        t.signalB();
    }
}

和B:

public void run() {
    while(true) {
        t.waitB();
        System.out.println("I am B");
        t.signalA();
    }
}

InterruptedException为了简洁而被忽略,它应该像你在代码中那样被捕获或抛出)

答案 1 :(得分:1)

  1. 应使用相同的锁来同步两个线程。使用不同的对象来锁定,会使情况变得不必要。
  2. waitnotifynotifyAll的任何来电都应该被包围 try / catch子句(适用于IllegalMonitorStateExceptionInterruptedException)。
  3. 如果您希望线程在完成运行后等待另一个线程,则应使用join
  4. 在您的情况下,两个主题应该在Boolean aCanTalk;上同步(请注意大写B!)。
  5. 应检查wait()循环中的任何while 改变我们正在同步的对象的状态。
  6. 更好的做法是不使用notify(),而只使用notifyAll()(尽管在这种特殊情况下无关紧要,因为只有两个线程)。
  7. waitnotify引入以来,Java已经发展,今天,在大多数情况下,您不必使用其中任何一个。
  8. 以下实现不使用waitnotify,仍然可以实现相同的执行同步:

    class ParaTest {
        volatile boolean aCanTalk;
    
        public static void main(String[] args) {
            Test t = new Test();
            t.t();
        }
    }
    
    class Test {
        volatile Boolean aCanTalk;
        Thread a;
        Thread b;
        void t() {
            aCanTalk = true;
            a = new Thread(new A(this));
            b = new Thread(new B(this));
            a.start();
            b.start();
            try {
                a.join();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
    
    class A implements Runnable {
        Test t;
        A(Test t) {
            this.t = t;
        }
    
        public void run() {
            System.out.println("I am A");
            synchronized(t.aCanTalk) {
                System.out.println("in synchronized (A)");
                t.aCanTalk = false;
            }
            System.out.println("finished (A)");
        }
    
    }
    
    class B implements Runnable {
        Test t;
        B(Test t) {
            this.t = t;
        }
    
        public void run() {
            System.out.println("I am B");
            synchronized(t.aCanTalk) {
                System.out.println("in synchronized (B)");
                t.aCanTalk = true;
            }
            System.out.println("finished (B)");
    
        }
    
    }
    

答案 2 :(得分:-1)

如果您想等待线程完成,请尝试“加入”。 java文档中有一个很好的例子: http://docs.oracle.com/javase/tutorial/essential/concurrency/join.html

所以,在你的情况下,如果你想在B之前调用start之前等待A完成。

a.start();
a.join();
b.start();

至少,这是我认为你在问的问题(你的问题似乎有点不清楚)。