线程池简单讲解

183 阅读8分钟

核心目标

  • 降低资源消耗。通过重复利用已创建的线程降低线程创建和销毁造成的消耗。
  • 提高响应速度。当任务到达时,任务可以不需要等到线程创建就能立即执行。
  • 提高线程的可管理性。线程是稀缺资源,如果无限制的创建,不仅会消耗系统资源,还会降低系统的稳定性,使用线程池可以进行统一的分配,调优和监控。

关键参数

  • corePoolSize (核心线程数):线程池中始终保持的线程数量,即使这些线程处于空闲状态(未执行任务),除非设置了allowCoreThreadTimeOut(允许核心线程超时)参数。

  • maximumPoolSize (最大线程数):线程池允许创建的最大线程数量,是线程池能容纳的线程上限。

  • keepAliveTime + unit (空闲线程存活时间 + 时间单位):非核心线程空闲多久被回收;开启 allowCoreThreadTimeOut(true) 后核心也会回收。

  • workQueue (任务队列):用于在任务执行前暂存任务的队列,该队列仅存放通过execute()方法提交的Runnable类型任务,决定“排队 vs 扩容”的策略。

    • SynchronousQueue:同步队列,不存储,直接移交。

    • LinkedBlockingQueue(默认无界):“先排队,后扩容”;风险是无界等待,吞吐高、延迟可变。

    • ArrayBlockingQueue(有界):常用于生产,配合 maximumPoolSize 和拒绝策略。

    • PriorityBlockingQueue:按优先级执行任务。

  • threadFactory (线程工厂):线程池创建新线程时所使用的 “工厂类”,用于统一定义线程的名称、优先级、是否为守护线程(daemon thread)等属性。

  • handler (拒绝策略):当线程池的线程数已达到maximumPoolSize(最大线程数),且任务队列(workQueue)也已装满时,新提交的任务会被 “拒绝”,此时将由该处理器定义拒绝任务的处理方式。

    • AbortPolicy(默认):直接抛出RejectedExecutionException异常,中断任务提交;
    • CallerRunsPolicy:由提交任务的 “调用线程”(如主线程)自行执行该任务,减缓任务提交速度;
    • DiscardPolicy:默默丢弃新任务,不抛出异常也不处理;
    • DiscardOldestPolicy:丢弃任务队列中 “最旧” 的未处理任务,然后尝试提交新任务。

运行状态

核心状态共有 5 个:RUNNING、SHUTDOWN、STOP、TIDYING、TERMINATED。

  • RUNNING:接受新任务,处理队列任务。

  • SHUTDOWN(shutdown() 触发):不再接收新任务,但会执行队列中的任务,已有工作线程正常退出。

  • STOP(shutdownNow() 触发):不再接收任务,丢弃队列任务,中断正在运行的任务。尽力打断阻塞/等待状态,但不能强杀CPU密集循环或忽略中断的代码。

  • TIDYING:所有任务终止,线程数为 0,准备进入 TERMINATED

  • TERMINATED:terminated() 执行完毕,彻底终止,生命周期闭合态。

状态迁移,只会向前

  • RUNNING —(shutdown)→ SHUTDOWN —(清空且无 worker)→ TIDYING → TERMINATED
  • RUNNING/SHUTDOWN —(shutdownNow)→ STOP —(无 worker)→ TIDYING → TERMINATED

线程状态

  • NEW:新建状态,线程对象刚被创建,线程池通常看不到,线程池一旦创建线程就会start()
  • RUNNABLE:线程正在执行任务,或者准备执行任务。
  • BLOCKED:线程尝试获取一个对象锁(synchronized),但锁被其他线程占用。
  • WAITING:无限期等待,直到被其他线程显式唤醒(notify()/signal())。
    • 核心线程在等待任务时通常处于次状态。
  • TIMED_WAITING:有时限的等待。
    • 非核心线程会在此状态等待任务
    • 如果核心线程设置了过期时间,也会在此状态等待任务
  • TERMINATED:线程执行完毕,生命周期结束。在线程池中,非核心线程超时回收,或线程池关闭后,线程会进入 TERMINATED

运行流程

image.png

简单使用

构建自定义线程池

import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;

ThreadFactory namedFactory = new ThreadFactory() {
    private final AtomicInteger idx = new AtomicInteger(1);
    @Override public Thread newThread(Runnable r) {
        Thread t = Executors.defaultThreadFactory().newThread(r);
        t.setName("biz-pool-" + idx.getAndIncrement());
        t.setDaemon(false);
        t.setUncaughtExceptionHandler((th, ex) ->
                System.err.println("Uncaught in " + th.getName() + ": " + ex));
        return t;
    }
};

RejectedExecutionHandler reject = new ThreadPoolExecutor.CallerRunsPolicy(); // 退化到调用线程执行

ThreadPoolExecutor pool = new ThreadPoolExecutor(
        4,                       // core
        8,                       // max
        60, TimeUnit.SECONDS,    // keepAlive
        new ArrayBlockingQueue<>(200), // 有界队列
        namedFactory,
        reject
);
pool.allowCoreThreadTimeOut(true); // 核心线程池也可回收
pool.prestartAllCoreThreads(); //预启动核心线程

使用 execut 与 submit 提交任务

// execute:仅提交
pool.execute(() -> 任务());

// submit:返回 Future,可拿结果/异常/取消
Future<Integer> future = pool.submit(() -> 任务());
try {
    Integer v = future.get(2, TimeUnit.SECONDS); // 超时避免无限阻塞
    System.out.println("result = " + v);
} catch (TimeoutException te) {
    future.cancel(true); // 可中断取消
} catch (ExecutionException ee) {
    // 任务内部异常在这里抛出,ee.getCause() 是真实异常
}
  • execute()
    • 没有返回值
    • 只可以提交 Runnable 任务
    • 提交的任务如果抛出未检查异常,会直接抛出并可能导致线程终止
  • submit()
    • 会返回一个 Future 对象
    • 可以提交 RunnableCallable 类型的任务
    • 提交的任务如果抛出异常,会被封装在 Future 对象中,只有当调用 Future.get() 时才会抛出

使用 CompletableFuture 处理任务

创建异步任务

  • runAsync(Runnable runnable, Executor executor):无返回值
  • supplyAsync(Supplier<U> supplier, Executor executor):有返回值
CompletableFuture.runAsync(() -> 任务());
CompletableFuture<String> f = CompletableFuture.supplyAsync(() -> 任务());

完成后回调

  • thenAccept(Consumer<? super T> action):接收任务结果并消费(无返回值)
  • thenApply(Function<? super T,? extends U> fn):接收任务结果并处理(有返回值,生成新的 CompletableFuture
  • thenRun(Runnable action):任务完成后执行,不关心结果(无返回值)
CompletableFuture<String> supplyFuture = CompletableFuture.supplyAsync(() -> 任务());

// 1. 消费结果(无返回值)
supplyFuture.thenAccept(result -> System.out.println("消费结果:" + result));

// 2. 处理结果(有返回值)
CompletableFuture<Integer> applyFuture = supplyFuture.thenApply(result -> result.length());
System.out.println("处理后的结果:" + applyFuture.get());

// 3. 任务完成后执行(不关心结果)
supplyFuture.thenRun(() -> System.out.println("任务完成,执行后续操作"));

组合任务

  • thenCompose(Function<? super T, ? extends CompletionStage<U>> fn):串行执行

    CompletableFuture<String> f1 = CompletableFuture.supplyAsync(() -> 任务1());
    
    CompletableFuture<String> f2 = f1.thenCompose(result -> 
        CompletableFuture.supplyAsync(() -> 任务2())
    );
    
  • allOf(CompletableFuture<?>... cfs):等待所有任务完成

    CompletableFuture<Void> all = CompletableFuture.allOf(f1, f2, f3);
    all.thenRun(() -> { f1.join(); f2.join(); f3.join(); });
    
  • anyOf(CompletableFuture<?>... cfs):获取第一个完成的任务结果

    CompletableFuture<String> f1 = CompletableFuture.supplyAsync(() -> {
        try { Thread.sleep(300); } catch (InterruptedException e) {}
        return "f1";
    });
    
    CompletableFuture<String> taskB = CompletableFuture.supplyAsync(() -> {
        try { Thread.sleep(200); } catch (InterruptedException e) {}
        return "f2";
    });
    
    // 取第一个完成的任务结果
    CompletableFuture<Object> firstCompleted = CompletableFuture.anyOf(f1, f2);
    System.out.println(firstCompleted.get()); // 输出:来自f2的结果
    

异常处理

  • exceptionally(Function<Throwable, ? extends T> fn):任务异常时执行,返回默认值

    CompletableFuture<Integer> f1 = CompletableFuture.supplyAsync(() -> {
        if (true) throw new RuntimeException("任务出错了");
        return 100;
    }).exceptionally(ex -> {
        System.out.println("捕获异常:" + ex.getMessage());
        return -1; // 异常时返回默认值
    });
    System.out.println(f1.get()); // 输出:-1
    
  • handle(BiFunction<? super T, Throwable, ? extends U> fn):无论成功或失败都执行,可处理结果或异常

    CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> 任务())
        .handle((result, ex) -> {
            if (ex != null) {
                return "error";
            } else {
                return result;
            }
        });
    

源码解读

  • AtomicInteger ctl: 主线程池控制状态,高位表示线程池运行状态,低位表示“工作线程数”。
    • runState「高 3 位」:表示线程池状态(如运行中、关闭中等)
    • workerCount「低 29 位」:表示有效线程数
  • class Worker extends AbstractQueuedSynchronizer implements Runnable: 主要维护运行任务的线程的中断控制状态。继承 AQS,以简化每次任务执行时锁的获取与释放。这样做可以防止那些原本用于唤醒等待任务的工作线程的中断,反而错误地中断了正在运行任务的线程。

任务提交:execute(Runnable command)

public void execute(Runnable command) {
        if (command == null)
            throw new NullPointerException();
        int c = ctl.get();
  			// 如果运行的线程数少于 corePoolSize,就尝试启动一个新线程,并将给定的任务作为它的第一个任务。
  			// 调用 addWorker 会以原子方式检查 runState 和 workerCount,从而避免错误地增加线程(在不该增加时),通过返回 false 来阻止。
        if (workerCountOf(c) < corePoolSize) {
            if (addWorker(command, true))
                return;
            c = ctl.get();
        }
        if (isRunning(c) && workQueue.offer(command)) {
            int recheck = ctl.get();
          	// 任务成功加入队列,需要再次检查是否需要增加线程。可能存在上次检查之后,线程池已经关闭,或者有线程关闭的情况
            if (! isRunning(recheck) && remove(command))
                reject(command);
          	// 线程池没有线程在运行,则启动一个新线程
            else if (workerCountOf(recheck) == 0)
                addWorker(null, false);
        }
  			// 如果任务无法入队,那么就尝试增加一个新线程。如果失败了,就可以确定线程池已经关闭或已饱和,因此拒绝该任务。
        else if (!addWorker(command, false))
            reject(command);
    }

新增工作线程:addWorker(Runnable firstTask, boolean core)

private boolean addWorker(Runnable firstTask, boolean core) {
        // 阶段一:状态/容量快速判断 + CAS 增量(外层 retry + 内层自旋)
  			retry:
        for (int c = ctl.get();;) {
            // Check if queue empty only if necessary.
            if (runStateAtLeast(c, SHUTDOWN)
                && (runStateAtLeast(c, STOP)
                    || firstTask != null
                    || workQueue.isEmpty()))
                return false;

            for (;;) {
              	// 判断工作线程,是否大于核心线程数或者最大线程数
                if (workerCountOf(c)
                    >= ((core ? corePoolSize : maximumPoolSize) & COUNT_MASK))
                    return false;
              	// CAS 增加 workerCount,成功跳出两层循环,失败重新获取状态,失败原因是SHUTDOWN还是计数竞争
                if (compareAndIncrementWorkerCount(c))
                    break retry;
                c = ctl.get();  // Re-read ctl
                if (runStateAtLeast(c, SHUTDOWN))
                    continue retry;
                // else CAS failed due to workerCount change; retry inner loop
            }
        }

        boolean workerStarted = false;
        boolean workerAdded = false;
        Worker w = null;
  			// 阶段二:构造 Worker 并在互斥下注册
        try {
            w = new Worker(firstTask);
            final Thread t = w.thread;
            if (t != null) {
              	// 加锁
                final ReentrantLock mainLock = this.mainLock;
                mainLock.lock();
                try {
                    // Recheck while holding lock.
                    // Back out on ThreadFactory failure or if
                    // shut down before lock acquired.
                    int c = ctl.get();

                  	// 仍然是 Running 状态,或者 STOP,没有新任务(清空队列,补线程)
                    if (isRunning(c) ||
                        (runStateLessThan(c, STOP) && firstTask == null)) {
                      	// 防止重复启动
                        if (t.getState() != Thread.State.NEW)
                            throw new IllegalThreadStateException();
                      	// worker 添加,更新最大线程数
                        workers.add(w);
                        workerAdded = true;
                        int s = workers.size();
                        if (s > largestPoolSize)
                            largestPoolSize = s;
                    }
                } finally {
                    mainLock.unlock();
                }
                if (workerAdded) {
                    t.start();
                    workerStarted = true;
                }
            }
        } finally {
          	// 如果未启动成功,失败处理
            if (! workerStarted)
                addWorkerFailed(w);
        }
        return workerStarted;
    }

线程主循环:runWorker(Worker w)

final void runWorker(Worker w) {
        Thread wt = Thread.currentThread();
        Runnable task = w.firstTask;
        w.firstTask = null;
        w.unlock(); // allow interrupts
        boolean completedAbruptly = true;
        try {
          	// 可能一开始就带有一个初始任务,此时不需要再去获取第一个任务。否则,只要线程池处于运行状态,就会通过 getTask 获取任务。
            while (task != null || (task = getTask()) != null) {
                w.lock();
								
              	// 在运行任何任务之前,会先获取锁,以防止线程在任务执行期间被其他线程池中断。然后会确保只要线程池没有停止,当前线程就不会被设置为中断状态。
                if ((runStateAtLeast(ctl.get(), STOP) ||
                     (Thread.interrupted() &&
                      runStateAtLeast(ctl.get(), STOP))) &&
                    !wt.isInterrupted())
                    wt.interrupt();
                try {
                    beforeExecute(wt, task);
                    try {
                      	// 运行任务
                        task.run();
                        afterExecute(task, null);
                    } catch (Throwable ex) {
                        afterExecute(task, ex);
                        throw ex;
                    }
                } finally {
                    task = null;
                    w.completedTasks++;
                    w.unlock();
                }
            }
            completedAbruptly = false;
        } finally {
            processWorkerExit(w, completedAbruptly);
        }
    }