You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何实现ExecutorService中两个线程的Join等待?

如何让ExecutorService中的任务实现顺序执行(第二个任务等待第一个完成)

我来帮你拆解下问题的核心,以及给出正确的实现方案。

你的代码里join()完全不生效的原因很关键:你把自己创建的Thread对象传给ExecutorService.submit()时,这个Thread根本没被真正启动。ExecutorService会把它当作一个普通的Runnable,用线程池里的工作线程去执行它的run()方法,而你创建的Thread-1实例本身的状态始终是NEW——调用一个未启动的Thread的join()会直接返回,自然不会等待任务完成。

正确的实现思路:用Future跟踪任务状态

在ExecutorService的场景下,我们应该用submit()方法返回的Future对象来跟踪任务的完成状态,调用Future.get()方法会阻塞当前线程,直到目标任务执行完成,这才是线程池环境下等待任务结束的标准姿势。

修改后的代码实现

第一步:修改CURD类,传递Future而非Thread

import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import org.springframework.beans.factory.annotation.Autowired;

public class CURD { 
    public static ExecutorService executorService = Executors.newCachedThreadPool(); 
    @Autowired 
    private Logging logging; 

    public void Update(List<? extends HBase> save, List<? extends HBase> delete) { 
        // 直接定义任务逻辑,不需要手动包装成Thread
        Runnable mainTask = () -> { 
            System.out.println("Started Main Task..."); 
            try { 
                Thread.sleep(1500); 
            } catch (InterruptedException e) { 
                e.printStackTrace(); 
            } 
            System.out.println("End Main Task..."); 
        }; 
        // 提交任务并获取Future对象,用来跟踪任务状态
        Future<?> mainTaskFuture = executorService.submit(mainTask);
        // 将Future传给Logging,代替原来的Thread
        logging.setPredecessorFuture(mainTaskFuture);
    } 
}

第二步:修改Logging类,用Future.get()等待任务完成

import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Future;
import static com.demo.CURD.executorService; 

public class Logging { 
    private Future<?> predecessorFuture; 

    // 改为接收Future对象
    public void setPredecessorFuture(Future<?> future) { 
        this.predecessorFuture = future; 
    } 

    private void loggingInfo() { 
        Runnable logTask = () ->{ 
            try { 
                if (predecessorFuture != null) { 
                    System.out.println(Thread.currentThread().getName() + " Started"); 
                    // 调用get()阻塞,直到前置任务完成
                    predecessorFuture.get(); 
                    System.out.println(Thread.currentThread().getName() + " Finished"); 
                } 
            } catch (Exception e) { 
                // 统一捕获中断、任务执行异常
                e.printStackTrace(); 
            } 
        }; 
        addTask(logTask); 
    } 

    public void addTask(Runnable run) { 
        System.out.println("Runnable Thread logAround....."); 
        CompletableFuture.runAsync(run, executorService)
            .exceptionally(ex -> { 
                System.out.println("exception occurred " + ex); 
                return null; 
            }); 
    } 
}

更简洁的方案:用CompletableFuture链式调用

如果你的需求就是“第二个任务必须在第一个任务完成后执行”,可以直接用CompletableFuture的链式调用,不需要手动传递Future,代码更简洁:

public void Update(List<? extends HBase> save, List<? extends HBase> delete) { 
    Runnable mainTask = () -> { 
        System.out.println("Started Main Task..."); 
        try { 
            Thread.sleep(1500); 
        } catch (InterruptedException e) { 
            e.printStackTrace(); 
        } 
        System.out.println("End Main Task..."); 
    }; 

    Runnable logTask = () -> {
        System.out.println(Thread.currentThread().getName() + " Started"); 
        System.out.println(Thread.currentThread().getName() + " Finished"); 
    };

    // 链式调用,logTask会自动在mainTask完成后执行
    CompletableFuture.runAsync(mainTask, executorService)
        .thenRunAsync(logTask, executorService)
        .exceptionally(ex -> {
            System.out.println("exception occurred " + ex);
            return null;
        });
}

关键注意点

  • 不要在ExecutorService中传递自己创建的Thread对象,线程池的核心就是统一管理线程,手动创建Thread会破坏线程池的设计,还会导致状态混乱。
  • Future.get()会抛出检查异常,需要统一捕获处理(比如中断异常、任务执行时的异常)。
  • 如果需要更复杂的任务依赖关系,CompletableFuture提供了非常丰富的API(比如thenApply、thenCombine等),可以满足大部分异步编排需求。

内容的提问来源于stack exchange,提问作者Java Carzy

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.11 08:14:31