当我尝试在Java中对 notify()进行一些测试时,我发现了一些困惑。
这里我有两个线程b1和b2,它们引用另一个线程a。在b1和b2中,它们将调用wait()。在线程a中,它将调用notify()。据我所知,它将再次调用b1或b2。当我用Runnable意识到这一点时,确实如此。但是当我使用Thread意识到这一点时,b1和b2都重新启动。任何人都能解释一下吗?
这是代码。
使用Runnable实现:
主题A:
public class threada implements Runnable{
@Override
public void run() {
// TODO Auto-generated method stub
String name = Thread.currentThread().getName();
System.out.println(name+" started");
synchronized(this){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(name + "end");
notify();
}
}
}
主题B:
public class threadb implements Runnable{
private threada ta;
public threadb(threada a){
ta = a;
}
@Override
public void run() {
// TODO Auto-generated method stub
String name = Thread.currentThread().getName();
System.out.println(name + " started");
synchronized(ta){
try {
ta.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(name + "end");
}
}
}
主:
public class threadmain {
public static void main(String...args){
threada a = new threada();
threadb b1 = new threadb(a);
threadb b2 = new threadb(a);
new Thread(b1, "b1").start();
new Thread(b2, "b2").start();
new Thread(a, "a").start();
}
}
结果:
b1 started
a started
b2 started
aend
b1end
使用Thread实现:
主题A:
public class ThreadA extends Thread{
@Override
public void run() {
String name = Thread.currentThread().getName();
System.out.println(name+" started");
synchronized(this){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(name + "end");
notify();
}
}
}
主题B:
public class ThreadB extends Thread{
private ThreadA ta;
public ThreadB(ThreadA a){
ta = a;
}
@Override
public void run() {
// TODO Auto-generated method stub
// super.run();
String name = Thread.currentThread().getName();
System.out.println(name + " started");
synchronized(ta){
try {
ta.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(name + "end");
}
}
}
主要:
public class ThreadMain {
public static void main(String... args) throws InterruptedException {
ThreadA a = new ThreadA();
ThreadB b1 = new ThreadB(a);
ThreadB b2 = new ThreadB(a);
b1.setName("b1");
b2.setName("b2");
b1.start();
b2.start();
Thread.sleep(10);
a.setName("a");
a.start();
}
}
结果:
b1 started
b2 started
a started
aend
b1end
b2end
答案 0 :(得分:1)
有趣的是,Thread.join()
记录了您的问题的解决方案当一个线程终止时,调用this.notifyAll方法
所以你的一个线程被notify()
调用唤醒,而另一个线程被线程A结束唤醒,从而在自身上发送notifyAll()
。因此,每当线程死亡时,等待它的一切都会被唤醒。
Runnable
版本没有发生这种情况,因为等待链接到Runnable
对象而非线程。
答案 1 :(得分:-1)
无论如何,你必须以一种方式实现你的线程,如果调用notifyAll(),那么你的代码中就没有竞争条件或任何问题,比如死锁
并且根据经验,使用notifyAll()而不是notify()。
答案 2 :(得分:-1)
您的ThreadB
没有对ThreadA
实例的引用 - 您永远不会对其进行初始化。您必须将ThreadA
实例传递给ThreadB
实例,或者如果主代码具有该字段的可见性,您可以直接设置它。
另外,根据javadocs:
notify()
通知一个随机选择的服务员notifyAll()
通知所有服务员您似乎应该致电notifyAll()
。
答案 3 :(得分:-1)
notify
是Object上的一个方法,它在所有对象上通常是相同的。您可以使用普通Object
或String
或List
或byte[]
,它会做同样的事情。注意:如果您打算使用notify,通常使用wait()而不是sleep(),因此通知会执行某些操作。