java中wait和join区别

»jdk

wait

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