我试着理解线程是如何工作的,我写了一个简单的例子,我想创建并启动一个新的线程,在主线程中显示从1到1000的数字,恢复辅助线程,在辅助线程中显示从1到1000的数字。当我省略Thread.wait()/Thread.notify()时,它的行为与预期一样,两个线程一次都显示几个数字。当我在中添加这些函数时,由于某种原因,主线程号被打印到第二个而不是第一个。我做错了什么?
public class Main {
public class ExampleThread extends Thread {
public ExampleThread() {
System.out.println("ExampleThread's name is: " + this.getName());
}
@Override
public void run() {
for(int i = 1; i < 1000; i++) {
System.out.println(Thread.currentThread().getName());
System.out.println(i);
}
}
}
public static void main(String[] args) {
new Main().go();
}
public void go() {
Thread t = new ExampleThread();
t.start();
synchronized(t) {
try {
t.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
for(int i = 1; i < 1000; i++) {
System.out.println(Thread.currentThread().getName());
System.out.println(i);
}
synchronized(t) {
t.notify();
}
}
}发布于 2012-01-24 07:53:43
您误解了wait/notify的工作原理。wait 不会阻塞调用它的线程;它会阻塞当前线程,直到在同一对象上调用notify为止(因此,如果您有线程A和B,并且在线程A中调用了B.wait(),这将停止线程A和而不是线程B-只要B.notify()没有被调用)。
因此,在您的特定示例中,如果您希望主线程首先执行,则需要将wait()放入辅助线程中。如下所示:
public class Main {
public class ExampleThread extends Thread {
public ExampleThread() {
System.out.println("ExampleThread's name is: " + this.getName());
}
@Override
public void run() {
synchronized (this) {
try {
wait();
} catch (InterruptedException e) {
}
}
for(int i = 1; i < 1000; i++) {
System.out.println(Thread.currentThread().getName());
System.out.println(i);
}
}
}
public static void main(String[] args) {
new Main().go();
}
public void go() {
Thread t = new ExampleThread();
t.start();
for(int i = 1; i < 1000; i++) {
System.out.println(Thread.currentThread().getName());
System.out.println(i);
}
synchronized(t) {
t.notify();
}
}
}然而,即使是这段代码也可能不会像您想要的那样工作。在主线程在等待之前到达notify()部分的情况下,辅助线程有机会到达()部分(在您的情况下不太可能,但仍然有可能-如果您将Thread.sleep放在辅助线程的开头,则可以观察到这一点),辅助线程将永远不会被唤醒。因此,最安全的方法如下所示:
public class Main {
public class ExampleThread extends Thread {
public ExampleThread() {
System.out.println("ExampleThread's name is: " + this.getName());
}
@Override
public void run() {
synchronized (this) {
try {
notify();
wait();
} catch (InterruptedException e) {
}
}
for(int i = 1; i < 1000; i++) {
System.out.println(Thread.currentThread().getName());
System.out.println(i);
}
}
}
public static void main(String[] args) {
new Main().go();
}
public void go() {
Thread t = new ExampleThread();
synchronized (t) {
t.start();
try {
t.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
for(int i = 1; i < 1000; i++) {
System.out.println(Thread.currentThread().getName());
System.out.println(i);
}
synchronized(t) {
t.notify();
}
}
}在本例中,输出是完全确定的。下面是发生的事情:
t对象。t thread.t>D28>监视器,辅助线程无法继续,必须等待(因为它的第一条语句是D29,E130不是E231,因为它恰好是E132是E233对象-所有锁,通知和等待也可以在与两个线程中的任何线程完全无关的对象上进行,使用相同的result.t.wait()部件并暂停其执行,释放它同步了on.的t监视器
t t线程调用t.notify()的所有权,从而唤醒主线程。然而,主线程还不能继续,因为辅助线程仍然持有monitor.t监视器现在是monitor.t监视器的所有权,但是释放它的权利away.t.notify()的t线程的所有权,唤醒辅助线程。辅助线程还不能继续,因为主线程仍然持有monitor.t监视器,away.t监视器的所有权,但是释放了它,terminates.t正如您所看到的,即使在这样一个看似简单的场景中,也会发生很多事情。
发布于 2012-01-24 07:54:30
ExampleThread不是wait()或notify(),也不是synchronized。因此,它将在任何时候运行,而不需要与其他线程进行任何协调。
主线程正在等待一个从未到来的通知(这个通知应该由另一个线程发送)。我的猜测是,当ExampleThread终止时,主线程被“错误地”唤醒并完成。
应该等待另一个线程完成的线程必须在检查条件的循环中执行对wait()的调用:
class ExampleThread extends Thread {
private boolean ready = false;
synchronized void ready() {
ready = true;
notifyAll();
}
@Override
public void run() {
/* Wait to for readiness to be signaled. */
synchronized (this) {
while (!ready)
try {
wait();
} catch(InterruptedException ex) {
ex.printStackTrace();
return; /* Interruption means abort. */
}
}
/* Now do your work. */
...然后在你的主线程中:
ExampleThread t = new ExampleThread();
t.start();
/* Do your work. */
...
/* Then signal the other thread. */
t.ready();发布于 2012-01-24 07:54:38
你很幸运,你的程序完全终止了。
当您调用t.wait()时,您的主线程将停止并无限期地等待通知。
它永远不会得到它,但我相信当辅助线程完成时,它会被伪唤醒唤醒。(请阅读here关于什么是虚假唤醒的内容)。
https://stackoverflow.com/questions/8980240
复制相似问题