线程池如何知道任务执行完成
                           
天天向上
发布: 2025-07-12 12:50:49

原创
125 人浏览过

在 Java 中,**线程池(ThreadPoolExecutor)是通过回调机制和任务状态监控来判断一个线程的任务是否已经执行完成的。**具体原理、机制和扩展点如下:


1、线程池如何知道任务执行完成?

线程池在执行任务时,依赖以下机制判断任务是否完成:

1.1 使用 RunnableCallable

  • 当线程执行完 Runnable.run()Callable.call() 方法后,表示任务正常完成
  • ThreadPoolExecutor 内部会在任务执行后回调钩子方法,如 afterExecute(),来处理后续逻辑。

1.2 任务执行完成标志:线程从 worker.run() 返回

每个线程池工作线程运行的核心逻辑在:

// Worker.java 内部逻辑
public void run() {
    try {
        while ((task = getTask()) != null) {
            task.run();
            // 到这里任务执行完成
        }
    } finally {
        processWorkerExit();
    }
}

二、执行完成后的通知方式

2.1 提交任务的返回值:Future

Future<?> future = executor.submit(() -> {
    // 任务逻辑
});

future.isDone();       // 是否完成
future.get();          // 阻塞等待结果(任务执行完成后返回)

线程池通过 Future 对象来查询任务是否完成或抛出异常。


2.2 回调钩子:afterExecute(Runnable r, Throwable t)

ThreadPoolExecutor 提供 protected 方法钩子,用于在任务完成后扩展处理:

@Override
protected void afterExecute(Runnable r, Throwable t) {
    super.afterExecute(r, t);
    // 此处任务执行完毕,可记录日志、监控耗时、处理异常等
}

📌 t != null 表示任务执行中抛出了异常。


2.3 Worker 线程退出控制:processWorkerExit()

当任务完成、线程终止时,线程池会调用:

void processWorkerExit(Worker w, boolean completedAbruptly)
  • 维护线程数量、工作状态
  • 若核心线程执行完毕但不够,线程池可重新创建线程

三、任务异常或中断的处理

✅ 正常完成

Runnable.run() / Callable.call() 返回无异常 → 任务完成

❌ 异常完成

  • 抛出 RuntimeException → afterExecute 捕获
  • 对于 submit() 提交的任务,异常会包装进 Future.get() 抛出:
Future<?> f = executor.submit(() -> {
    throw new RuntimeException("Boom!");
});
f.get(); // ExecutionException

四、实战案例:统计每个任务是否完成

public class MyExecutor extends ThreadPoolExecutor {
    public MyExecutor(int corePoolSize, int maxPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> queue) {
        super(corePoolSize, maxPoolSize, keepAliveTime, unit, queue);
    }

    @Override
    protected void afterExecute(Runnable r, Throwable t) {
        super.afterExecute(r, t);
        if (t != null) {
            System.out.println("任务异常:" + t.getMessage());
        } else {
            System.out.println("任务执行完成!");
        }
    }
}

使用:

MyExecutor executor = new MyExecutor(2, 4, 60, TimeUnit.SECONDS, new LinkedBlockingQueue<>());
executor.submit(() -> {
    System.out.println("Task running...");
});

五、扩展:判断任务完成的多种方式

方法是否阻塞可检测异常推荐用法
Future.isDone()轮询判断是否完成
Future.get()✅ 是✅ 是获取任务结果或异常
重写 afterExecute()✅ 是任务完成统一处理、打日志
结合 CountDownLatch并发控制、等待所有任务完成
CompletionService✅ 是高效获取已完成任务结果

六、官方源码入口和文档


更多详细内容请关注其他相关文章!

发表回复 0

Your email address will not be published. Required fields are marked *