JUC系列线程池基础使用
Posted 顧棟
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JUC系列线程池基础使用相关的知识,希望对你有一定的参考价值。
线程池基础使用
文章目录
一、核心组件和核心类
4个核心组件
- 线程池管理器 用于创建和管理线程
- 工作线程 线程池中执行具体任务的线程
- 任务接口 用户定义工作线程的调度和执行策略,只有线程实现了该接口,线程的任务才能够被线程池调度。
- 任务队列 存放待处理的任务,新的任务加入队列,执行完成的任务会被队列移除。
java中的线程池通过Executor框架实现的核心类如下:
Executor、Executors 、ExecutorService、ThreadPoolExcutor、Callable、Future、 FutureTask
创建线程池的核心类ThreadPoolExcutor的核心方法
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler)
...
参数说明
-
corePoolSize:线程池中的核心线程数量
-
maximumPoolSize:线程池中最大线程数量
-
keepAliveTime:当线程数超过corePoolSize时,线程空闲存活时长
-
unit keepAliveTime:的时间单位
-
workQueue:任务队列,被提交但是尚未执行的任务的存放处
-
threadFactory:线程工厂,用户创建线程,一般默认
-
handler:拒绝策略,任务过多或者其他原因导致线程池无法处理任务的拒绝策略。
二、线程池的工作流程
核心线程池和非核心线程池
核心线程不会被销毁 而非核心线在空闲后超过keepaliveTime之后会被销毁。
三、线程池的拒绝策略
当线程池的任务缓存队列已满并且线程池中的线程数目达到maximumPoolSize时,如果还有任务到来就会采取任务拒绝策略。JDK内置的拒绝策略有4种。
ThreadPoolExecutor.AbortPolicy //默认,丢弃任务并抛出RejectedExecutionException异常。
ThreadPoolExecutor.DiscardPolicy //丢弃任务,但是不抛出异常。
ThreadPoolExecutor.DiscardOldestPolicy //尝试丢弃队列最前面的任务,然后重新提交被当前的任务
ThreadPoolExecutor.CallerRunsPolicy //由调用线程(提交任务的线程)处理该任务 如果调用线程未关闭的话
自定义拒绝策略
以上的拒绝策略都实现了RejectedExecutionHandler接口,说明可以自己通过实现RejectedExecutionHandler来编写自己的拒绝策略。
四、6种常用的线程池
- newCachedThreadPool 缓存线程池
在创建新线程时,如果有空闲的线程就重用它们。 使用场景在执行时间短的大量任务是可以使用。
- newFixedThreadPool
创建一个固定线程数的线程池,并形成队列循环使用。
- newScheduledThreadPool
可定时调度的线程池,在延迟时间后执行或者定期执行某个线程任务。
- newSingleThreadExecutor
线程池中只有1个线程执行任务,在该线程出现停止或异常时,会启动一个新的线程进行工作。
- newSingleScheduleThreadPool
此线程有点结合的意思,是一个只有一个线程的线程池,可用定时任务。
- newWorkStealingPool
创建一个具有抢占式操作的线程池,stealing 翻译为抢断、窃取的意思,它实现的一个线程池和上面4种都不一样,用的是 ForkJoinPool 类。它是一个并行的线程池,参数中传入的是一个线程并发的数量,这里和之前就有很明显的区别,前面4种线程池都有核心线程数、最大线程数等等,而这就使用了一个并发线程数解决问题。从介绍中,还说明这个线程池不会保证任务的顺序执行,也就是 WorkStealing 的意思,抢占式的工作。
五、线程池的使用
线程池的创建
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
5,
10,
3,
TimeUnit.SECONDS,
new ArrayBlockingQueue<>(3),
new ThreadPoolExecutor.AbortPolicy());
向线程池提交任务
threadPoolExecutor.execute(new WorkTask(task));
关闭线程池
threadPoolExecutor.shutdown();
ThreadPoolExecutorDemo示例
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
public class ThreadPoolExecutorDemo
public static void main(String[] args) throws InterruptedException
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
5,
10,
3,
TimeUnit.SECONDS,
new ArrayBlockingQueue<>(3),
new ThreadPoolExecutor.AbortPolicy());
for (int i = 1; i <= 10; i++)
String task = "task-" + i;
System.out.println("[" + new SimpleDateFormat("HH:mm:ss").format(new Date()) + "--" + Thread.currentThread().getName() + "] submit " + task);
threadPoolExecutor.execute(new WorkTask(task));
threadPoolExecutor.shutdown();
static class WorkTask implements Runnable
private final Object name;
WorkTask(String taskName)
this.name = taskName;
@Override
public void run()
System.out.println("[" + new SimpleDateFormat("HH:mm:ss").format(new Date()) + "--" + Thread.currentThread().getName() + "] start .." + name);
try
Thread.sleep(2000);
System.out.println("[" + new SimpleDateFormat("HH:mm:ss").format(new Date()) + "--" + Thread.currentThread().getName() + "] end .." + name);
catch (Exception e)
e.printStackTrace();
执行结果
[17:45:34--main] submit task-1
[17:45:34--main] submit task-2
[17:45:34--main] submit task-3
[17:45:34--main] submit task-4
[17:45:34--main] submit task-5
[17:45:34--main] submit task-6
[17:45:34--main] submit task-7
[17:45:34--main] submit task-8
[17:45:34--main] submit task-9
[17:45:34--main] submit task-10
[17:45:34--pool-1-thread-1] start ..task-1
[17:45:34--pool-1-thread-3] start ..task-3
[17:45:34--pool-1-thread-2] start ..task-2
[17:45:34--pool-1-thread-4] start ..task-4
[17:45:34--pool-1-thread-5] start ..task-5
[17:45:34--pool-1-thread-6] start ..task-9
[17:45:34--pool-1-thread-7] start ..task-10
[17:45:36--pool-1-thread-3] end ..task-3
[17:45:36--pool-1-thread-2] end ..task-2
[17:45:36--pool-1-thread-1] end ..task-1
[17:45:36--pool-1-thread-2] start ..task-6
[17:45:36--pool-1-thread-4] end ..task-4
[17:45:36--pool-1-thread-1] start ..task-7
[17:45:36--pool-1-thread-6] end ..task-9
[17:45:36--pool-1-thread-5] end ..task-5
[17:45:36--pool-1-thread-7] end ..task-10
[17:45:36--pool-1-thread-3] start ..task-8
[17:45:38--pool-1-thread-2] end ..task-6
[17:45:38--pool-1-thread-3] end ..task-8
[17:45:38--pool-1-thread-1] end ..task-7
以上是关于JUC系列线程池基础使用的主要内容,如果未能解决你的问题,请参考以下文章
JUC并发编程 共享模式之工具 ThreadPoolExecutor 多线程设计模式 -- 异步模式之工作线程(定义饥饿 & 解决饥饿 & 线程池创建多少线程数目合适)