Java 调用wait和notify的两个线程
我编写的代码没有像我预期的那样工作Java 调用wait和notify的两个线程,java,multithreading,wait,Java,Multithreading,Wait,我编写的代码没有像我预期的那样工作 static Integer sync = 1; static void m() throws Exception { synchronized (sync) { System.err.println("First"); sync.notify(); sync.wait(1000L); System.err.println("Second"
static Integer sync = 1;
static void m() throws Exception {
synchronized (sync) {
System.err.println("First");
sync.notify();
sync.wait(1000L);
System.err.println("Second");
System.err.println("Third");
}
}
public static void main(String[] args) throws Exception {
Runnable r = new Runnable() {
@Override
public void run() {
try {
m();
} catch (Exception ex) {
Logger.getLogger(IO.class.getName()).log(Level.SEVERE, null, ex);
}
}
};
Runnable t = new Runnable() {
@Override
public void run() {
try {
m();
} catch (Exception ex) {
Logger.getLogger(IO.class.getName()).log(Level.SEVERE, null, ex);
}
}
};
Thread th1 = new Thread(r);
Thread th2 = new Thread(t);
th1.run();
th2.run();
}
我们有两个线程执行m()
的syncjronized语句。当第一个线程执行一个线程并遇到wait()
时,它将被添加到等待集中。在此之后,第二个线程开始执行synchronized语句,并执行notify()。因为输出必须是
First
First
....
但实际上是这样
First
Second
Third
First
Second
Third
为什么?首先,您的程序没有创建任何线程。必须调用th1.start()和th2.start()来创建线程 t、 start()是库提供的方法,当您想要启动线程时,可以调用代码。run()是为库提供的在新线程中调用的方法。run()方法定义线程将执行的操作。在我看来,run()确实是一个误导性的名字 其次,notify()和wait()不要做你认为他们会做的事情。特别是,如果当前没有其他线程处于sync.wait()状态,sync.notify()将不会执行任何操作 使用notify()和wait()的正确方法是,一个线程执行以下操作:
synchronized(lock) {
while (! someCondition()) {
lock.wait()
}
doSomethingThatRequiresSomeConditionToBeTrue();
}
另一个线程执行此操作
synchronized(lock) {
doSomethingThatMakesSomeConditionTrue();
lock.notify();
}
使用此模式时,除了从同步(锁定)块内部更改someCondition()的结果外,任何线程都不应更改该结果。首先,您的程序不会创建任何线程。必须调用th1.start()和th2.start()来创建线程 t、 start()是库提供的方法,当您想要启动线程时,可以调用代码。run()是为库提供的在新线程中调用的方法。run()方法定义线程将执行的操作。在我看来,run()确实是一个误导性的名字 其次,notify()和wait()不要做你认为他们会做的事情。特别是,如果当前没有其他线程处于sync.wait()状态,sync.notify()将不会执行任何操作 使用notify()和wait()的正确方法是,一个线程执行以下操作:
synchronized(lock) {
while (! someCondition()) {
lock.wait()
}
doSomethingThatRequiresSomeConditionToBeTrue();
}
另一个线程执行此操作
synchronized(lock) {
doSomethingThatMakesSomeConditionTrue();
lock.notify();
}
使用此模式时,除了从同步(锁定)块内部更改someCondition()的结果外,任何线程都不应更改该结果。首先,要实际创建新线程,请使用 th1.start() th2.start() 代替run(),它只是线程对象上的常规方法调用 其次,第二个线程“th2”可能在1000毫秒之前没有开始运行,因此第一个线程完成等待(1000)并执行剩余的代码行 如果您希望这样输出:
first
first
second
third
second
third
然后删除wait()的时间间隔,这将使线程等待通知。
例如:
首先,要实际创建新线程,请使用 th1.start() th2.start() 代替run(),它只是线程对象上的常规方法调用 其次,第二个线程“th2”可能在1000毫秒之前没有开始运行,因此第一个线程完成等待(1000)并执行剩余的代码行 如果您希望这样输出:
first
first
second
third
second
third
然后删除wait()的时间间隔,这将使线程等待通知。
例如:
.start()
而不是run()
将可运行项添加到队列中,而不是立即运行它们等待等待此对象上的任何通知或超时。在您的情况下,当一个接一个地执行可运行文件时,它会:
- r:首先
- r:等待1000毫秒并尝试获取锁
- r:它已经有了锁定对象的访问权限(正是这个代码被锁定了),所以继续吗
- r:第二
- r:第三
- t:首先,等等
run()
而不设置timeout将导致t的等待出现死锁,因为它已经有了对象,但不会被通知
希望这有帮助
.start()
而不是run()
将可运行项添加到队列中,而不是立即运行它们等待等待此对象上的任何通知或超时。在您的情况下,当一个接一个地执行可运行文件时,它会:
- r:首先
- r:等待1000毫秒并尝试获取锁
- r:它已经有了锁定对象的访问权限(正是这个代码被锁定了),所以继续吗
- r:第二
- r:第三
- t:首先,等等
run()
而不设置timeout将导致t的等待出现死锁,因为它已经有了对象,但不会被通知
希望这有帮助。首先,您调用的是
Thread.run()
,而不是Thread.start()
,因此您的代码实际上是单线程的。如果您在sync
@JeanLogeart上进行同步,请不要期望首先看到它。您能解释一下原因吗?我真的不明白(尽管我已经从JLS中读到了相应的子句)。不要在Integer
1对象上同步。它们被有效地隔离,因此执行相同操作的无关代码片段将在同一对象上同步。使用new Object()
。首先,您调用的是Thread.run()
,而不是Thread.start()
,因此您的代码实际上是单线程的。如果您在sync
@JeanLogeart上进行同步,请不要期望首先看到?我真的不明白(尽管我已经从JLS中读到了相应的子句)。不要在Integer
1对象上同步。它们被有效地隔离,因此执行相同操作的无关代码片段将在同一对象上同步。改用newobject()
。