java中wait和join区别
»jdkwait
wait是Object的方法,方法内部很简单,使用native方法实现
public final void wait() throws InterruptedException {
wait(0);
}
public final native void wait(long timeout) throws InterruptedException;
使用过程中需要获取监视器,才能使用,否则会抛uncheck异常
public static void main(String[] args) throws InterruptedException {
Object o = new Object();
o.wait();
}
输出:
Exception in thread "main" java.lang.IllegalMonitorStateException
at java.lang.Object.wait(Native Method)
at java.lang.Object.wait(Object.java:502)
at Solution.main(Solution.java:45)
同时,并不是只要获取监视器就能执行,还必须是获取调用wait方法的对象的监视器,像下面这种代码也是会抛IllegalMonitorStateException异常
public static void main(String[] args) throws InterruptedException {
Object o1 = new Object();
Object o2 = new Object();
synchronized (o2){
o1.wait();
}
调用wait之后,当前线程会被挂起,释放当前对象的监视器,并将当前线程挂起,直到有线程调用这个对象上的notify/notifyAll方法
public static void main(String[] args) throws InterruptedException {
Object o = new Object();
synchronized (o){
o.wait();
}
join
join是thread的方法,当在当前线程中调用另一个线程的join时,当前线程会挂起,等到另一个线程执行完毕之后才能继续向下执行
那么问题来了,如果在当前线程中调用当前线程的join方法会怎么样?
public static void main(String[] args) throws InterruptedException {
Thread.currentThread().join();
}
会将当前线程挂起,同时一直不会结束。
原因是因为join方法是通过调用wait方法实现的。
public final void join() throws InterruptedException {
join(0);
}
public final synchronized void join(long millis)
throws InterruptedException {
long base = System.currentTimeMillis();
long now = 0;
if (millis < 0) {
throw new IllegalArgumentException("timeout value is negative");
}
if (millis == 0) {
while (isAlive()) {
wait(0);
}
} else {
while (isAlive()) {
long delay = millis - now;
if (delay <= 0) {
break;
}
wait(delay);
now = System.currentTimeMillis() - base;
}
}
}
当你在A线程调用B线程的join方法,其实就是在A线程中调B的wait方法.
但是,当我们在A线程中调B线程的join方法时,并没有在B线程中调notify,但是B线程执行完,A线程会被唤醒。原因是因为当一个线程执行完毕之后会自动调用这个线程对象的notify方法,将所有在这个线程对象上 等待的线程都唤醒。
public static void main(String[] args) throws InterruptedException {
final Thread thread = new Thread(() -> {
try {
Thread.sleep(3000);
System.out.println("thread notify");
} catch (InterruptedException e) {
e.printStackTrace();
}
});
thread.start();
synchronized (thread) {
thread.wait();
}
System.out.println("main end");
}
上面的代码,在main中建线程thread,然后将main线程等待thread,同时并没有调用thread.notify去唤醒main线程,讲道理的话,main会被一直挂起,但是并没有,因为thread执行完毕之后,就会自动唤醒在thread上等待的线程。 所以上面的thread.wait 等价于 thread.join