Java线程池

Executor 接口

Executor 接口是线程池的基类,基本上所有的线程池类都直接或间接继承此类。

接口定义

public interface Executor {
    void execute(Runnable command);
}

ExecutorService 接口

接口定义

ExecutorService 接口继承自 Executor 接口。

public interface ExecutorService extends Executor, AutoCloseable {
	// 优雅关闭和立即关闭
	void shutdown();
    List<Runnable> shutdownNow();

	// 是否已经调用了 shutdown() 或 shutdownNow()
    boolean isShutdown();
    // 检查线程池是否已经完全终止
    boolean isTerminated();
    // 与 shutdown() 配合使用
    boolean awaitTermination(long timeout, TimeUnit unit) throws InterruptedException;

	// 提交一个任务并返回一个 Future 用于获取任务执行的结果
    <T> Future<T> submit(Callable<T> task);
    <T> Future<T> submit(Runnable task, T result);
    Future<?> submit(Runnable task);
	
	// 提交多个任务
    List<Future<?>> invokeAll(Collection<? extends Callable<?>> tasks) throws InterruptedException;
    <T> T invokeAny(Collection<? extends Callable<T>> tasks) throws InterruptedException, ExecutionException;

shutdown

shutdown() 方法会通知线程池优雅关闭,然后 shutdown 方法立即返回,不会等待。
优雅关闭:线程池中提交过的所有任务都会执行,但是不会再接受新的任务。

如果线程池已经关闭,再次调用该方法不会产生任何额外的效果。

executorService.shutdown();

awaitTermination

awaitTermination() 方法会阻塞当前线程,直到以下三种情况之一发生:

  • 线程池中的存量任务全部执行完成
  • 超过了指定的等待时间
  • 当前等待的线程被中断
executorService.shutdown();

try {
    // 等待线程池中的任务完成,最多等待 5 秒
    if (!executorService.awaitTermination(5, TimeUnit.SECONDS)) {
        System.out.println("Timeout reached before tasks were completed");
    } else {
        System.out.println("All tasks completed successfully");
    }
} catch (InterruptedException e) {
    Thread.currentThread().interrupt();
}

shutdownNow

  • 停止接收新任务:与 shutdown() 相同,调用 shutdownNow() 会停止线程池接收新的任务。

  • 中断正在执行的任务:与 shutdown() 不同,shutdownNow() 会尝试中断当前正在执行的任务,但它并不能保证任务一定会被中断(如果任务没有响应中断或者是阻塞任务,可能会继续运行)。

  • 返回尚未执行的任务:shutdownNow() 会返回一个 未执行的任务列表,即当前队列中还没有执行的任务。

// 调用 shutdownNow,尝试立即停止任务并返回未执行的任务
List<Runnable> pendingTasks = executorService.shutdownNow();
System.out.println("Pending tasks: " + pendingTasks.size());

ThreadPoolExecutor

ThreadPoolExecutor 间接继承 ExecutorService 接口,提供了更丰富的线程池功能。

线程池七大参数

ThreadPoolExecutor 提供了 7 个关键参数来控制线程池的行为,这些参数允许开发者精细化管理线程池的性能、任务调度以及资源使用。下面是这 7 个参数的详细说明:

参数 定义 描述 常见示例
corePoolSize 核心线程池大小 线程池中始终保持活动的线程数。即使没有任务,线程池也会保持这些线程。 int corePoolSize = 2;
maximumPoolSize 最大线程池大小 线程池中允许的最大线程数。如果任务数超过 corePoolSize,且队列已满,线程池会增加线程,直到达到此最大值。 int maximumPoolSize = 4;
keepAliveTime 线程空闲时间 非核心线程在空闲时存活的最大时间,超出这个时间会被回收。 long keepAliveTime = 60L;
TimeUnit unit = TimeUnit.SECONDS;
unit 时间单位 keepAliveTime 的时间单位。可以是秒、毫秒等单位。 TimeUnit unit = TimeUnit.SECONDS;
workQueue 任务队列 存放待执行任务的队列,影响任务调度方式。常见队列有 LinkedBlockingQueueArrayBlockingQueueSynchronousQueue 等。 BlockingQueue workQueue = new LinkedBlockingQueue<>(10);
handler 拒绝策略 当线程池和队列都满时,任务如何处理的策略。常见的拒绝策略有 AbortPolicyCallerRunsPolicyDiscardPolicy 等。 RejectedExecutionHandler handler = new ThreadPoolExecutor.AbortPolicy();
threadFactory 线程工厂 用于创建新线程的工厂,可以定制线程的名称、优先级等属性。 ThreadFactory threadFactory = Executors.defaultThreadFactory();

重要的方法

方法 返回值 说明
execute(Runnable command) void 提交一个任务,立即执行。如果线程池有空闲线程,会立即执行。
submit(Callable task) Future 提交一个任务并返回一个 Future 对象,用于获取任务的结果。
submit(Runnable task) Future 提交一个 Runnable 任务并返回 Future,用于获取执行状态。
invokeAll(Collection> tasks) List> 提交一批任务并等待所有任务完成,返回每个任务的结果。
invokeAny(Collection> tasks) T 提交一批任务,返回第一个完成的任务的结果。
shutdown() void 启动线程池的关闭过程,不再接受新任务,等待已提交任务执行完毕后关闭。
shutdownNow() List 立即停止线程池,尝试中断所有正在执行的任务,返回未执行的任务列表。
prestartAllCoreThreads() void 启动线程池中的所有核心线程。
getCorePoolSize() int 获取线程池的核心线程数。
setCorePoolSize(int corePoolSize) void 设置新的核心线程数。
getMaximumPoolSize() int 获取线程池的最大线程数。
setMaximumPoolSize(int maxPoolSize) void 设置新的最大线程数。
getPoolSize() int 获取当前线程池中的总共线程数量。
getQueue() BlockingQueue 获取存储待执行任务的队列。
getActiveCount() int 获取线程池中正在执行任务的线程数。
getCompletedTaskCount() long 获取已完成的任务数。
getTaskCount() long 获取任务总数,包括正在执行的任务、队列中的任务和已完成的任务。

停止已经启动的线程

Java 中并没有提供一个直接的 API 来强制停止线程,因为这样做可能会导致资源泄漏、数据不一致等问题。

设置标志位 volatile

最常见的做法是通过标志位(例如 volatile 变量)来通知线程结束。线程本身会定期检查这个标志位,如果发现标志位被设置为 true,就安全地停止线程。

public class StoppableThread extends Thread {
    private volatile boolean running = true;

    @Override
    public void run() {
        while (running) {
            try {
                // 模拟任务
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        }
    }

    public void stopThread() {
        running = false;
    }

    public static void main(String[] args) throws InterruptedException {
        StoppableThread thread = new StoppableThread();
        thread.start();
        Thread.sleep(5000);
        thread.stopThread();  // 停止线程
    }
}

中断线程 interrupt

Java 提供了 Thread.interrupt() 方法来中断线程。这种方法不直接停止线程,而是通过向线程发送一个中断信号,告诉线程停止执行。线程需要在合适的地方检查中断状态,并决定是否退出。

public class InterruptibleThread extends Thread {
    @Override
    public void run() {
        while (!isInterrupted()) {
            try {
                // 模拟任务
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                break;  // 捕获中断异常并退出
            }
        }
    }

    public static void main(String[] args) throws InterruptedException {
        InterruptibleThread thread = new InterruptibleThread();
        thread.start();
        Thread.sleep(5000);
        thread.interrupt();  // 中断线程
    }
}

你可能感兴趣的:(Java线程池)