Java 中 Thread 的 join 方法
Java juc 面试 大约 5248 字介绍
Waits for this thread to die.
join()
方法上的注释是等待该线程销毁。
t1.join()
表示等待t1
线程执行完成,继续执行后续代码。
假设调用t1.join()
的地方在主线程,那么主线程就会等待t1
线程执行完后,继续执行主线程中的后续代码。
示例代码
public class ThreadJoinDemo {
public static void main(String[] args) {
Thread t1 = new Thread(() -> {
System.out.println(LocalDateTime.now() + " t1 is running, group#" + Thread.currentThread().getThreadGroup());
try {
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException e) {
e.printStackTrace();
}
}, "t1");
Thread t2 = new Thread(() -> {
try {
//t1调用join方法, t2会等待t1运行完之后才会开始执行后续代码
t1.join();
System.out.println(LocalDateTime.now() + " t2 is running, group#" + Thread.currentThread().getThreadGroup());
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}, "t2");
Thread t3 = new Thread(() -> {
try {
//t2调用join方法, t3会等待t2运行完之后才会开始执行后续代码
t2.join();
System.out.println(LocalDateTime.now() + " t3 is running, group#" + Thread.currentThread().getThreadGroup());
} catch (InterruptedException e) {
e.printStackTrace();
}
}, "t3");
//依次启动3个线程
t1.start();
t2.start();
t3.start();
}
}
输出:
2021-04-06T16:09:06.087 t1 is running, group#java.lang.ThreadGroup[name=main,maxpri=10]
2021-04-06T16:09:09.102 t2 is running, group#java.lang.ThreadGroup[name=main,maxpri=10]
2021-04-06T16:09:10.103 t3 is running, group#java.lang.ThreadGroup[name=main,maxpri=10]
源码分析
join()
在调用时wait()
等待线程执行完成后,底层C++
代码在线程结束后自动调用JavaThread::exit
方法,唤醒线程。
public class Thread implements Runnable {
public Thread(Runnable target) {
init(null, target, "Thread-" + nextThreadNum(), 0);
}
private void init(ThreadGroup g, Runnable target, String name, long stackSize) {
init(g, target, name, stackSize, null, true);
}
private void init(ThreadGroup g, Runnable target, String name, long stackSize, AccessControlContext acc, boolean inheritThreadLocals) {
...
Thread parent = currentThread(); // new 该线程的线程,案例中是 main 线程
SecurityManager security = System.getSecurityManager();
if (g == null) {
// security 为 null
if (security != null) {
g = security.getThreadGroup();
}
// main 线程的用户组是 main
if (g == null) {
g = parent.getThreadGroup();
}
}
...
}
// 阻塞直到线程运行结束
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); // Object 的 wait 方法,阻塞在此
}
} else {
while (isAlive()) {
long delay = millis - now;
if (delay <= 0) {
break;
}
wait(delay);
now = System.currentTimeMillis() - base;
}
}
}
/**
* Tests if this thread is alive. A thread is alive if it has
* been started and has not yet died.
*
* 测试线程是否还存活。线程如果已启动或者未结束退出则还是存活状态。
*/
public final native boolean isAlive();
// 线程所属的组
private ThreadGroup group;
/**
* This method is called by the system to give a Thread
* a chance to clean up before it actually exits.
*
* 此方法是系统调用,在线程真正退出前给它一个机会去做清理工作
*/
private void exit() {
if (group != null) {
group.threadTerminated(this);
group = null;
}
target = null;
// 主动置为 null 加快内存释放
threadLocals = null;
inheritableThreadLocals = null;
inheritedAccessControlContext = null;
blocker = null;
uncaughtExceptionHandler = null;
}
}
public class ThreadGroup implements Thread.UncaughtExceptionHandler {
void threadTerminated(Thread t) {
synchronized (this) {
remove(t);
// 如果线程组中的线程为 0,则 notifyAll 唤醒所有线程
if (nthreads == 0) {
notifyAll();
}
if (daemon && (nthreads == 0) &&
(nUnstartedThreads == 0) && (ngroups == 0))
{
destroy();
}
}
}
}
线程在结束运行退出时,底层C++
调用线程notify_all
唤醒该线程上wait
的对象。
源码路径:openjdk\hotspot\src\share\vm\runtime\thread.cpp
。
#thread.cpp
//线程结束,调用该方法
void JavaThread::exit(bool destroy_vm, ExitType exit_type) {
...
ensure_join(this);
...
}
static void ensure_join(JavaThread* thread) {
...
ObjectLocker lock(threadObj, thread);
...
//唤醒等待在thread对象上的线程
lock.notify_all(thread);
...
}
#ObjectSynchronizer.hpp
void notify_all(TRAPS) { ObjectSynchronizer::notifyall(_obj, CHECK); }
阅读 2018 · 发布于 2021-04-12
————        END        ————
Give me a Star, Thanks:)
https://github.com/fendoudebb扫描下方二维码关注公众号和小程序↓↓↓

昵称:
随便看看
换一批
-
MySQL 视图阅读 2143
-
wget ERROR The certificate was signed using an insecure algorithm阅读 2556
-
数据结构:栈-数组实现阅读 1095
-
Java 并发编程之 Semaphore阅读 1857
-
Windows 删除服务阅读 1373
-
Prometheus+Grafana+redis_exporter 监控 Redis 服务阅读 1251
-
IDEA Debug 时对象莫名其妙被修改了阅读 849
-
SQL 优化阅读 882
-
PostgreSQL 使用 \copy 命令时报 character with byte sequence 0xc3 0xa5 in encoding "UTF8" has no equivalent in encoding "GBK"阅读 9915
-
JavaScript 屏幕旋转后获取浏览器宽高阅读 1597