5.Java面试题之线程池如何知道一个线程的任务已经执行完成?

线程池通过多种机制来判断一个线程的任务是否已经执行完成。让我们深入探讨这个问题:

  1. Runnable 接口

当使用 Runnable 接口时,线程池通过 run() 方法的执行完成来判断任务是否结束。

ExecutorService executor = Executors.newFixedThreadPool(2);
executor.execute(new Runnable() {
    @Override
    public void run() {
        // 任务逻辑
        System.out.println("Task completed");
    }
});

在这种情况下,当 run() 方法执行完毕,线程池就认为任务已经完成。

  1. Callable 接口和 Future 对象

使用 Callable 接口时,线程池可以通过 Future 对象来判断任务是否完成。

ExecutorService executor = Executors.newFixedThreadPool(2);
Future<String> future = executor.submit(new Callable<String>() {
    @Override
    public String call() throws Exception {
        // 任务逻辑
        return "Task result";
    }
});

// 检查任务是否完成
if (future.isDone()) {
    System.out.println("Task is completed");
}
  1. 任务完成回调

使用 CompletableFuture 可以设置任务完成的回调。

CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
    // 任务逻辑
    return "Task result";
}, executor);

future.thenAccept(result -> {
    System.out.println("Task completed with result: " + result);
});
  1. 线程池内部机制

线程池内部使用工作线程(Worker)来执行任务。每个 Worker 在执行完一个任务后,会尝试从任务队列中获取下一个任务。如果没有新任务,Worker 会进入等待状态。

// ThreadPoolExecutor 内部的 Worker 类(简化版)
private final class Worker implements Runnable {
    public void run() {
        try {
            while (task != null || (task = getTask()) != null) {
                runTask(task);
            }
        } finally {
            workerDone(this);
        }
    }
}
  1. 任务计数

ThreadPoolExecutor 维护了一个 completedTaskCount,用于记录已完成的任务数。

public class ThreadPoolExecutor extends AbstractExecutorService {
    private long completedTaskCount;

    // 当任务完成时,会调用这个方法
    void afterExecute(Runnable r, Throwable t) { 
        completedTaskCount++;
    }
}
  1. 自定义 ThreadFactory

可以通过自定义 ThreadFactory 来创建能够报告任务完成状态的线程。

class CustomThreadFactory implements ThreadFactory {
    @Override
    public Thread newThread(Runnable r) {
        return new Thread(r) {
            @Override
            public void run() {
                super.run();
                System.out.println("Task in thread " + getName() + " completed");
            }
        };
    }
}

ExecutorService executor = Executors.newFixedThreadPool(2, new CustomThreadFactory());
  1. 使用 CountDownLatch 或 CyclicBarrier

对于需要等待多个任务完成的场景,可以使用 CountDownLatch 或 CyclicBarrier。

int taskCount = 3;
CountDownLatch latch = new CountDownLatch(taskCount);

for (int i = 0; i < taskCount; i++) {
    executor.execute(() -> {
        // 任务逻辑
        latch.countDown();
    });
}

latch.await(); // 等待所有任务完成
System.out.println("All tasks completed");
  1. 定期检查活跃线程数

可以定期检查线程池的活跃线程数来判断是否所有任务都已完成。

ThreadPoolExecutor executor = (ThreadPoolExecutor) Executors.newFixedThreadPool(2);

while (executor.getActiveCount() > 0) {
    Thread.sleep(100); // 等待 100 毫秒
}
System.out.println("All tasks completed");

总结:
线程池通过多种机制来跟踪任务的完成状态:

  1. Runnable 的 run() 方法执行完毕
  2. Callable 和 Future 的状态
  3. CompletableFuture 的回调
  4. 线程池内部的 Worker 机制
  5. 任务计数器
  6. 自定义 ThreadFactory
  7. 同步工具类(如 CountDownLatch)
  8. 活跃线程数检查

选择哪种方法取决于具体的应用场景和需求。在实际应用中,可能需要结合多种方法来准确跟踪任务的完成状态。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

至真源

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值