Java等待/通知

Java等待/通知,java,notify,Java,Notify,我花了很长时间试图找出为什么这不起作用,但根本找不到答案。 我想做的是,让两个班级互相“交谈”。 基本上,我想让A做点什么,以及为B做什么(B也一样) 如果要等待线程完成,请尝试“加入”。java文档中有一个很好的例子: 因此,在您的情况下,如果您想在调用B上的start之前等待A完成 a.start(); a.join(); b.start(); 至少,这是我认为您要问的问题(您的问题似乎有点不清楚)。您的代码还有其他问题(见下文),但您遇到的问题是,由于在等待之前检查了条件,如B:

我花了很长时间试图找出为什么这不起作用,但根本找不到答案。 我想做的是,让两个班级互相“交谈”。 基本上,我想让A做点什么,以及为B做什么(B也一样)


如果要等待线程完成,请尝试“加入”。java文档中有一个很好的例子:

因此,在您的情况下,如果您想在调用B上的start之前等待A完成

a.start();
a.join();
b.start();
至少,这是我认为您要问的问题(您的问题似乎有点不清楚)。

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

  public void run() {
    while(!t.aCanTalk) {
    ....
    }
  }
如果
t.aCanTalk
为true,则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();
    }
}
并在线程中使用它,例如 以一种方式:

B:

public void run() {
    while(true) {
        t.waitB();
        System.out.println("I am B");
        t.signalA();
    }
}
InterruptedException
为简洁起见被忽略,它应该像在代码中一样被捕获或抛出)

  • 同步两个线程应该使用同一个锁。使用不同的对象来锁定,会使情况变得不必要的复杂
  • wait
    notify
    notifyAll
    的任何调用都应该用 try/catch子句(用于
    IllegalMonitorStateException
    中断异常
  • 如果希望一个线程在完成运行后等待另一个线程,则应使用
  • 在您的情况下,两个线程应该在
    Boolean aCanTalk上同步(注意大写字母
    B
    !)
  • 任何
    wait()
    正在同步的对象的状态更改
  • 更好的做法是不要使用
    notify()
    ,而只使用
    notifyAll()
    (尽管在这种特殊情况下这并不重要,因为只有两个线程)
  • 自从
    wait
    notify
    被引入以来,Java就得到了发展,而今天,对于大多数目的来说,您不必使用它们中的任何一个
  • 以下实现不使用
    wait
    notify
    ,但仍实现相同的执行同步:

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

    当你说它不起作用时,它在做什么?它打印出“我是一个”并停止。我确信有人已经在写一个很长很全面的答案了。这里的问题是:(1)t.aCanTalk上存在数据竞争,这是一个非易失性变量;(2)a和B彼此不同步,因为它们在两个不同的锁上同步。仅当两个线程在同一对象上同步时,“同步”才起作用。尝试同步(t)(您必须将t标记为final,这在您的情况下似乎不是问题)@ortusolis告诉我
    B.run
    在启动时如果
    t.aCanTalk
    为false将执行什么操作。如果您能在(false)时告诉
    ,则
    你自己解决问题是否已经走到了一半。我基本上试着让A做点什么,叫B,叫B做点什么,然后叫A等等。Sry,如果问题有点不明确,OP对wait和notify的使用是正确的。再读一遍
    a
    等待
    b
    并通知自己(
    a
    ),
    b
    等待
    a
    并通知自己(
    b
    )。这不好,但也不是天生的问题。@SRobertz只是补充一下你的答案,这里没有必要使
    aCanTalk
    易失性,因为你是从
    synchronized
    方法中访问它的,这使得
    aCanTalk
    更改对所有线程都立即可见。@Radiodef是的,我刚才看到了。因此,问题在于线程启动中存在一个争用条件:如果while循环中的条件为false,那么线程将简单地退出,而不会达到等待状态。意志edit@Magnamag它不是易变的,但我将其编辑为私有的,只是为了澄清它只应用于监视器操作。@SRobertz当然,这不是对您答案的更正,而是澄清,因为有人在某处评论过将
    aCanTalk
    设置为volatile。第二点是不正确的:您必须在要
    等待的对象上进行同步。等待释放锁。
    
    public void run() {
        while(true) {
            t.waitB();
            System.out.println("I am B");
            t.signalA();
        }
    }
    
    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)");
    
        }
    
    }