Java里面Join(),为什么等待的是主线程,而不是当前子线程?

1689 2026-07-17 02:41:51
1.问题描述​ 当我们想要一个线程插队执行的时候,我们可能会使用到thread.join();。这个会让子线程先于主线程执行完毕,然后才开始执行子线

1.问题描述​ 当我们想要一个线程插队执行的时候,我们可能会使用到thread.join();。这个会让子线程先于主线程执行完毕,然后才开始执行子线程。但是仔细一想,发现这个明明调用的是子线程的join()方法,按道理应该子线程等待执行才是,为什么反而是主线程等待了呢?相关的示例代码如下:

代码语言:javascript复制public static void main(String[] args) throws InterruptedException {

Thread thread = new Thread(() -> {

try {

Thread.sleep(2000L);

} catch (InterruptedException e) {

e.printStackTrace();

}

System.out.println("子线程开始执行...");

});

thread.start();

thread.join();

System.out.println("主线程执行...");

}输出:

代码语言:javascript复制子线程开始执行...

主线程执行...2.查看源码说明带着这个主线程等待执行的疑惑来一起看下join的源码,如下所示:

代码语言:javascript复制/**

* Waits for this thread to die.

*

*

An invocation of this method behaves in exactly the same

* way as the invocation

*

*

* {@linkplain #join(long) join}{@code (0)}

*

*

* @throws InterruptedException

* if any thread has interrupted the current thread. The

* interrupted status of the current thread is

* cleared when this exception is thrown.

*/

public final void join() throws InterruptedException {

join(0);

}谁等待谁终止?源码中注释说明的是等待这个线程终止,那就是等待调用Join()的线程终止,再继续往下看:

代码语言:javascript复制 /**

* Waits at most {@code millis} milliseconds for this thread to

* die. A timeout of {@code 0} means to wait forever.

*

*

This implementation uses a loop of {@code this.wait} calls

* conditioned on {@code this.isAlive}. As a thread terminates the

* {@code this.notifyAll} method is invoked. It is recommended that

* applications not use {@code wait}, {@code notify}, or

* {@code notifyAll} on {@code Thread} instances.

*

* @param millis

* the time to wait in milliseconds

*

* @throws IllegalArgumentException

* if the value of {@code millis} is negative

*

* @throws InterruptedException

* if any thread has interrupted the current thread. The

* interrupted status of the current thread is

* cleared when this exception is thrown.

*/

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的源码中,我们可以看到它使用了while (isAlive()) 循环判断线程的存活状态,满足就调用wait方法,当有设置时长的时候会根据时长来进行等待。注意按照程序的执行顺序,我们这里是主线程调用的Thread的Join方法,所以是判断子线程的存活状态,满足则让子线程执行,主线程来等待。

wait 等待方法是让线程进入等待队列,使用方法是 obj.wait(); 这样当前线程就会暂停运行,并且进入obj的等待队列中,称作“线程正在obj上等待”。可以把子线程t理解为一个普通的obj对象,调用t的wait()方法,实际上就是主线程(main线程)在childThread对象的队列上等待,可以转换为如下写法进一步理解:

代码语言:javascript复制/**

* 主线程

*/

public class MainTest {

public static void main(String[] args) throws InterruptedException {

System.out.println("主线程开始执行...");

Thread childThread = new ChildThread();

childThread.start();

while (childThread.isAlive()) {

synchronized (childThread) {

// 此时主线程进行等待并释放锁资源 使子线程有得以运行的机会

childThread.wait();

}

}

System.out.println("主线程执行结束...");

}

}

/**

* 子线程

*/

class ChildThread extends Thread {

public ChildThread() {

}

@Override

public void run() {

System.out.println("子线程开始执行...");

try {

Thread.sleep(1000);

} catch (InterruptedException e) {

e.printStackTrace();

}

System.out.println("子线程执行结束...");

synchronized (this) {

// 唤醒等待的主线程

this.notifyAll();

}

}

}输出:

代码语言:javascript复制主线程开始执行...

主线程执行结束...

子线程开始执行...

子线程执行结束...另外需要强调的一点:使用Join方法让主线程等待后,调用完wait方法后,JVM底层会隐式的调用notifyAll方法来唤醒主线程,使其得以继续往下执行。

终于有人把RS485说清楚了|《小姐》:权力与欲望交织的视觉之旅,冷艳背后隐藏的秘密与情感