Java Wait()/notify()同步
我试图检查wait/notify在java中是如何工作的 代码:Java Wait()/notify()同步,java,multithreading,synchronization,Java,Multithreading,Synchronization,我试图检查wait/notify在java中是如何工作的 代码: public class Tester { public static void main(String[] args) { MyRunnable r = new MyRunnable(); Thread t = new Thread(r); t.start(); synchronized (t) { try {
public class Tester {
public static void main(String[] args) {
MyRunnable r = new MyRunnable();
Thread t = new Thread(r);
t.start();
synchronized (t) {
try {
System.out.println("wating for t to complete");
t.wait();
System.out.println("wait over");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
class MyRunnable implements Runnable {
public void run() {
System.out.println("entering run method");
synchronized (this) {
System.out.println("entering syncronised block");
notify();
try {
Thread.currentThread().sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("leaving syncronized block");
}
System.out.println("leaving run method");
}
}
返回的输出
wating for t to complete
entering run method
entering syncronised block
//sleep called
leaving syncronized block
leaving run method
wait over
我希望在执行notify()时等待将结束&
System.out.println(“等待结束”)代码>将被打印。但它似乎只有在t
完成其run()
对象监视器锁需要执行同一个锁的单个引用时才会被打印
在您的示例中,您正在等待线程的一个实例
,但使用可运行
中的通知
。相反,您应该使用单个公共锁对象…例如
public class Tester {
public static final Object LOCK = new Object();
public static void main(String[] args) {
MyRunnable r = new MyRunnable();
Thread t = new Thread(r);
t.start();
synchronized (LOCK) {
try {
System.out.println("wating for t to complete");
LOCK.wait();
System.out.println("wait over");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public static class MyRunnable implements Runnable {
public void run() {
System.out.println("entering run method");
synchronized (LOCK) {
System.out.println("entering syncronised block");
LOCK.notify();
try {
Thread.currentThread().sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("leaving syncronized block");
}
System.out.println("leaving run method");
}
}
}
输出…
wating for t to complete
entering run method
entering syncronised block
leaving syncronized block
wait over
leaving run method
等待
和离开运行方法
可能会根据线程调度更改位置
您可以尝试将睡眠置于synchronized
块之外。这将释放监视器锁,允许等待
部分继续运行(因为在释放锁之前它无法启动)
对更新代码的答复:
从javadoc:
导致当前正在执行的线程为
指定的毫秒数,取决于系统计时器的精度和准确性
和调度程序线程不会失去任何监视器的所有权
如果在同步块内调用Thread.sleep,其他线程将无法进入同步块。在同步块中,您永远不应该执行耗时的任务,以避免出现这种情况。请注意(正如其他人所指出的),您必须使用相同的对象来锁定/同步两个线程
如果希望在调用notify
后立即继续主线程,则必须暂时放弃锁定。否则,只有在次线程离开synchronized
块后,才会调用wait
。在长时间运行的计算中保持一个锁从来都不是一个好主意
一种方法是在锁上使用wait(int)
而不是sleep
,因为wait
会临时释放同步锁:
public class Tester {
private static final Object lock = new Object();
public static void main(String[] args) {
Thread t = new Thread(new MyRunnable());
t.start();
synchronized (lock) {
try {
System.out.println("wating for t to complete");
lock.wait();
System.out.println("wait over");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
static class MyRunnable implements Runnable {
public void run() {
System.out.println("entering run method");
synchronized (lock) {
System.out.println("entering syncronised block");
lock.notify();
try {
lock.wait(1000); // relinquish the lock temporarily
} catch (InterruptedException ex) {
System.out.println("got interrupted");
}
System.out.println("leaving syncronized block");
}
System.out.println("leaving run method");
}
}
}
然而,使用这些低级原语可能非常容易出错,我不鼓励使用它们。相反,我建议您为此使用Java的高级原语。例如,您可以使用CountDownLatch
,它让一个线程等待其他线程倒计时到零:
import java.util.concurrent.*;
public class TesterC {
private static final CountDownLatch latch = new CountDownLatch(1);
public static void main(String[] args) {
Thread t = new Thread(new MyRunnable());
t.start();
System.out.println("wating for t to complete");
try {
latch.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("wait over");
}
static class MyRunnable implements Runnable {
public void run() {
System.out.println("entering run method");
try {
latch.countDown();
Thread.sleep(1000);
} catch (InterruptedException ex) {
System.out.println("got interrupted");
}
System.out.println("leaving run method");
}
}
}
在这里,您无需同步任何内容,闩锁为您完成所有操作。您还可以使用许多其他原语-信号量、交换器、线程安全队列等。Explorer是java.util.concurrent
包
也许更好的解决方案是使用更高级别的API,如提供的API。在这里,您可以使用或,它可以很容易地组合,并避免大多数并发问题。您没有在同一个对象上同步MyRunnable。this==r!=t@raul8编辑问题并粘贴答案会使正确答案无效。最好再加一个问题。我知道你正在研究等待
/通知
的工作原理。但无论如何,我强烈建议您在代码中使用Java。在低级并发代码中很容易出现难以发现的错误(正如您在本例中所看到的)。谢谢…但我尝试了您的代码。。但它仍然不起作用。有问题的代码updatedFYIThread.sleep
(两种形式)是一种静态方法,总是将调用线程置于睡眠状态;因此Thread.currentThread().sleep(1000)
在语义上是冗余的,并且可能会产生误导(例如,调用t.sleep(1000)
会使调用线程进入睡眠状态,而不是t)。
import java.util.concurrent.*;
public class TesterC {
private static final CountDownLatch latch = new CountDownLatch(1);
public static void main(String[] args) {
Thread t = new Thread(new MyRunnable());
t.start();
System.out.println("wating for t to complete");
try {
latch.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("wait over");
}
static class MyRunnable implements Runnable {
public void run() {
System.out.println("entering run method");
try {
latch.countDown();
Thread.sleep(1000);
} catch (InterruptedException ex) {
System.out.println("got interrupted");
}
System.out.println("leaving run method");
}
}
}