调用内部启动线程的Java方法会阻塞等待线程执行完吗?
核心结论
两种写法并不等价,Java中不存在「调用内部启动新线程的方法时,会隐式等待内部线程执行完毕才返回」的机制。Thread.start()本身是异步方法,调用后会立刻返回,不会阻塞发起调用的线程。
第一种写法的执行逻辑
你的第一版代码实际执行顺序如下:
// things A method(); // things B public void method(){ new Thread(() -> { // slow stuff (慢文件写入逻辑) }).start(); }
- 当前调用线程先执行
things A的全部逻辑 - 进入
method()方法,完成线程对象创建、调用start()通知JVM为新线程分配栈内存、初始化线程上下文、纳入系统调度 start()调用完成后立刻退出method(),回到调用点- 当前线程马上开始执行
things B,和新启动的子线程完全并行,互不阻塞
你观察到的「执行完things A后等待一段时间才执行things B」,本质是线程创建本身的固定开销导致的,并不是在等待子线程的慢写入任务跑完:JVM向操作系统申请线程资源、初始化线程上下文、第一次触发文件IO时的类加载、文件句柄申请都有少量耗时,刚好落在method()调用的时间窗口里,才给你造成了阻塞等待慢任务的错觉。实际上method()返回的时间点远早于子线程慢写入任务完成的时间点,things B不需要等慢写入跑完就会执行。
第二种写法的执行逻辑
第二版代码的执行顺序如下:
// things A new Thread(() -> { method(); }).start(); // things B public void method(){ // slow stuff (慢文件写入逻辑) }
- 当前调用线程先执行
things A的全部逻辑 - 创建包装了
method()调用的线程对象,调用start()触发线程初始化,这一步完成后立刻返回 - 当前线程马上开始执行
things B - 新启动的子线程独立执行
method()里的慢写入逻辑,和当前线程并行
两种写法的核心差异
- 第一版中,线程创建、初始化的动作是在原调用线程中执行的,这部分固定开销会占用原线程的执行时间,开销结束后原线程才会运行
things B - 第二版中,线程对象创建、
method()调用、慢写入执行的全流程都在新线程中完成,原线程仅需要执行极少量的线程对象构造、start()调用逻辑就会立刻往下走,触发things B的延迟会比第一版更低 - 两版写法的慢写入任务都不会阻塞原线程执行
things B。如果需要显式等待子线程任务执行完成再往下走,必须手动调用Thread.join()、Future.get()这类阻塞等待方法,否则Java不会自动做跨线程的等待。
如果你实际测试时发现第一版的
things B确实是在慢写入任务完全结束后才开始执行,需要排查代码里的隐式同步逻辑:比如慢写入任务和things B争抢同一把锁、用了同步IO触发了系统级的资源阻塞、或者写入逻辑里调用了阻塞原线程的方法,和「方法内部启动线程」这个写法本身没有关系。
内容的提问来源于stack exchange,提问作者Ángel Fas
相关产品推荐
相关产品推荐

