[英]Is there any difference between thread and runnable when using notify in Java?
When I try to do some test about notify() in Java, I found some confusion. 当我尝试对Java中的notify()进行测试时,发现有些困惑。
Here I have two thread b1 and b2, they have the reference to another thread a. 在这里,我有两个线程b1和b2,它们引用了另一个线程a。 In b1 and b2, they will call wait().
在b1和b2中,它们将调用wait()。 And in thread a, it will call notify().
在线程a中,它将调用notify()。 As I know, it will call b1 or b2 to start again.
据我所知,它将调用b1或b2重新开始。 It is true when I realize this using Runnable.
当我使用Runnable实现这一点时,确实如此。 But when I realize this using Thread, b1 and b2 both start again.
但是当我使用Thread意识到这一点时,b1和b2都重新开始。 Can any one explain this?
有人可以解释吗?
Here is the code. 这是代码。
Realized using Runnable: 使用Runnable实现:
Thread A: 线程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();
}
}
}
Thread B: 线程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");
}
}
}
Main: 主要:
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();
}
}
The Result: 结果:
b1 started
a started
b2 started
aend
b1end
Realized using Thread: 使用线程实现:
Thread A: 线程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();
}
}
}
Thread B: 线程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");
}
}
}
Main : 主要:
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();
}
}
The result: 结果:
b1 started
b2 started
a started
aend
b1end
b2end
Interestingly the the solution to your question is documented for Thread.join() 有趣的是,您的问题的解决方案记录在Thread.join()中。
As a thread terminates the this.notifyAll method is invoked
当线程终止时,this.notifyAll方法被调用
So one of your threads was awoken by the notify()
call and the other by the thread A ending and thus sending a notifyAll()
on itself. 因此,您的一个线程被
notify()
调用唤醒,另一个线程被线程A结尾唤醒,因此自身发送了notifyAll()
。 So every time a thread dies everything waiting on it will awaken. 因此,每次线程死亡时,等待它的所有事物都会唤醒。
This didn't happen for the Runnable
version as the wait was linked to the Runnable
objects and not the Thread. 对于
Runnable
版本,这没有发生,因为等待已链接到Runnable
对象而不是Thread。
At any rate, you have to implement your threads in a way where if notifyAll() get called then there will be no race condition or any problems in your code such as deadlock 无论如何,您必须以某种方式实现线程,如果调用notifyAll(),则不会出现竞争状况或代码中的任何问题(例如死锁)
and as a rule of thumb, use notifyAll() instead of notify(). 根据经验,请使用notifyAll()而不是notify()。
Your ThreadB
does not have a reference to the ThreadA
instance - you never initialize it. 您的
ThreadB
没有对ThreadA
实例的引用-您永远不会初始化它。 You must pass the ThreadA
instance to the ThreadB
instances, or if the main code has visibility of the field, you can set it directly. 您必须将
ThreadA
实例传递给ThreadB
实例,或者如果主代码具有该字段的可见性,则可以直接对其进行设置。
Also, as per the javadocs: 另外,按照javadocs:
notify()
notifies one randomly chosen waiter notify()
通知一个随机选择的服务员 notifyAll()
notifies all waiters notifyAll()
通知所有服务员 It seems you should be calling notifyAll()
. 看来您应该调用
notifyAll()
。
notify
is a method on Object which is generally the same on all objects. notify
是Object上的一种方法,通常在所有对象上都是相同的。 You could use a plain Object
or a String
or List
or byte[]
and it would do the same thing. 您可以使用一个普通的
Object
或String
或List
或byte[]
,它会做同样的事情。 Note: if you are going to use notify, you generally use wait() instead of sleep() so the notify does something. 注意:如果要使用notify,则通常使用wait()而不是sleep(),因此notify会执行某些操作。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.