在 Java 中,线程池的工作流程主要包括以下几个阶段:
一、线程池的创建
- 初始化参数:
- 在创建线程池时,可以指定一些参数,如核心线程数、最大线程数、线程空闲时间、任务队列等。
- 例如,使用
ThreadPoolExecutor
的构造函数可以进行如下配置:
int corePoolSize = 5; int maximumPoolSize = 10; long keepAliveTime = 1000; TimeUnit unit = TimeUnit.MILLISECONDS; BlockingQueue<Runnable> workQueue = new LinkedBlockingQueue<>(); ThreadPoolExecutor threadPool = new ThreadPoolExecutor(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue);
二、任务提交
- 提交任务到线程池:
- 当有任务需要执行时,可以通过
execute
方法或submit
方法将任务提交给线程池。 - 例如:
threadPool.execute(new Runnable() { @Override public void run() { // 任务逻辑 } });
- 当有任务需要执行时,可以通过
三、线程分配与执行任务
-
核心线程执行任务:
- 如果当前线程池中线程数量小于核心线程数,新提交的任务会创建一个新的线程来执行任务。
- 这些核心线程会一直存活,即使它们处于空闲状态,除非设置了允许核心线程超时的参数。
-
任务加入队列等待:
- 如果线程池中线程数量达到了核心线程数,新提交的任务会被放入任务队列中等待执行。
- 常见的任务队列有
LinkedBlockingQueue
、ArrayBlockingQueue
等。
-
非核心线程创建与执行任务:
- 如果任务队列已满,并且线程池中线程数量小于最大线程数,线程池会创建新的非核心线程来执行任务。
-
拒绝策略:
- 如果任务队列已满,并且线程池中线程数量也达到了最大线程数,此时再提交任务,会根据拒绝策略来处理。
- Java 提供了几种拒绝策略,如
AbortPolicy
(直接抛出RejectedExecutionException
异常)、CallerRunsPolicy
(在调用者线程中执行任务)、DiscardPolicy
(直接丢弃任务)、DiscardOldestPolicy
(丢弃队列中最旧的任务,然后重新尝试执行当前任务)。
四、线程回收
-
线程空闲超时回收:
- 如果线程数量超过了核心线程数,并且有线程处于空闲状态的时间超过了指定的空闲时间,那么这个线程会被回收,直到线程数量等于核心线程数。
- 可以通过设置
keepAliveTime
参数来控制线程的空闲超时时间。
-
线程池关闭回收:
- 当调用线程池的
shutdown
或shutdownNow
方法关闭线程池时,会尝试停止正在执行的任务,并回收所有的线程。 shutdown
方法会等待所有任务执行完毕后再关闭线程池,而shutdownNow
方法会尝试立即停止所有正在执行的任务,并返回未执行的任务列表。
- 当调用线程池的
总之,Java 线程池通过合理地管理线程的创建、分配和回收,提高了线程的复用率,减少了线程创建和销毁的开销,从而提高了系统的性能和稳定性。