关于Java线程Thread类的join方法的解释

Thread类的join方法,Java官方文档的解释是:Waits for this thread to die.(等待线程死亡)。也就是程序会等待调用join方法的线程运行完,再执行当前线程,但不影响除这2个线程之外的线程的运行。这样简单的解释可能很多同学并不是很理解,下面将详细地解释一些join方法。

首先我们先看一下join方法的代码实现(JDK8):

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;
            }
        }
}

我们平时调用的无参的join方法最终会调用到这个带一个参数的join方法,参数是0。看关键的第一个while循环的代码,while会判断调用此方法的线程是否是alive状态(如果线程没有运行完都是alive状态,包括运行和阻塞),如果线程已经运行完,则方法结束,什么也不做。如果线程没有运行完,则调用调用此join方法线程的wait方法。这里需要着重注意,此join方法是synchronized方法,也就是调用此方法的时,会在调用此方法的对象上加锁。假设在B线程中调用的A线程对象的join方法,那么就会在A线程对象上加锁,这时调用wait方法时,注意这里是在B线程中调用的A线程对象的wait方法,因此当前线程(B线程)就会处于等待状态,并释放A线程对象上的这把锁。问题在于,我们在学习线程时知道,调用wait方法等待的线程需要等待其他线程调用notify或notifyAll方法并再此获得这把锁才能继续运行,那为什么B线程wait以后,A线程执行完,B线程就又可以继续执行了呢?原因在于,我们的锁是加在A线程对象上的,当A线程运行结束之后,notify方法会被线程子系统调用(The notify() for this is handled by the Thread subsystem.),也就是说当线程运行结束后,线程对象上的notify方法会被调用。因此当A线程执行完,A线程对象就会调用notify方法,此时B线程就会被唤醒从而继续运行。

下面我们通过具体的代码来看一下:

public class Main {
    public static void main(String[] args) {

        final Thread threadA = new Thread(() -> {
            for (int i = 0; i < 1000; i++) {
                System.out.println(Thread.currentThread().getName() + " is running..." + i);
            }
        }, "A");
        threadA.start();


        final Thread threadB = new Thread(() -> {
            for (int i = 0; i < 1000; i++) {
                System.out.println(Thread.currentThread().getName() + " is running..." + i);
                if (i == 500) {
                    try {
                        threadA.join();     //调用threadA的join方法,相当于执行了下面注释的代码
                        // synchronized (threadA) {
                        //     while (threadA.isAlive()) {
                        //         threadA.wait(0);
                        //     }
                        // }
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }, "B");
        threadB.start();

    }

}
我们创建并启动了A和B两个线程,在每个线程中分别打印当前线程的名字和循环次数,在B线程循环到500次时,调用A线程的join方法,注意,此时相当于相当于执行了join下面的注释的代码,然后B线程会等待,直到A线程运行结束以后,B线程才会继续运行。但由于join方法是在B线程中调用的,因此它并不会影响除A、B线程之外的其他线程的运行。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章