如何你直接想使用线程池请滑到最后
线程池的体系结构
一、线程池的创建
线程池的创建分为两种
1、使用Executors
2、使用ThreadPoolExecutor
使用Executor
- Executors.newFixedThreadPool:创建⼀个固定⼤⼩的线程池,可控制并发的线程数,超出的线程会在队列中等待
- Executors.newCachedThreadPool:创建⼀个可缓存的线程池,若线程数超过处理所需,缓存⼀段时间后会回收,若线程数不够,则新建线程;
- Executors.newSingleThreadExecutor:创建单个线程数的线程池,它可以保证先进先出的执⾏顺序;
- Executors.newScheduledThreadPool:创建⼀个可以执⾏延迟任务的线程池;
- Executors.newSingleThreadScheduledExecutor:创建⼀个单线程的可以执⾏延迟任务的线程池;
- Executors.newWorkStealingPool:创建⼀个抢占式执⾏的线程池(任务执⾏顺序不确定)【JDK1.8 添加】。
实际上面6终创建线程的方法差不多都是使用ThreadPoolExecutor,原理也大差不差。
使用ThreadPoolExecutor
1.new ThreadPoolExecutor(…);
二、ThreadPoolExecutor参数说明
- corePoolSize:核心线程数
核心线程会一直存活,及时没有任务需要执行。当线程数小于核心线程数时,即使有线程空闲,线程池也会优先创建新线程处理。设置allowCoreThreadTimeout=true(默认false)时,核心线程会超时关闭 - maximumPoolSize:最大线程数
当线程数>=corePoolSize,且任务队列已满时。线程池会创建新线程来处理任务。当线程数=maxPoolSize,且任务队列已满时,线程池会拒绝处理任务而抛出异常 - keepAliveTime:线程空闲时间
当线程空闲时间达keepAliveTime时,线程会退出,直到线程数量=corePoolSize。如果allowCoreThreadTimeout=true,则会直到线程数量=0 - unit:线程空闲时间的时间单位
- workQueue:任务队列容量(阻塞队列)
当核心线程数达到最大时,新任务会放在队列中排队等待执行 - threadFactory:线程创建创建工厂
根据次接口来进行Thread的创建和参数的设置 - rejectedExecutionHandler:任务拒绝处理器
两种情况会拒绝处理任务;
1、当线程数已经达到maxPoolSize,切队列已满,会拒绝新任。
2、当线程池被调用shutdown()后,会等待线程池里的任务执行完毕,再shutdown。如果在调用shutdown()和线程池真正shutdown之间提交任务,会拒绝新任务。
线程池会调用rejectedExecutionHandler来处理这个任务。如果没有设置默认是AbortPolicy,会抛出异常;
ThreadPoolExecutor类有几个内部实现类来处理这类情况;
1、AbortPolicy 丢弃任务,抛运行时异常
2、CallerRunsPolicy 执行任务
3、DiscardPolicy 忽视,什么都不会发生
4、DiscardOldestPolicy 从队列中踢出最先进入队列(最后一个执行)的任务
5、实现RejectedExecutionHandler接口,可自定义处理器 - allowCoreThreadTimeout:允许核心线程超时
三、ThreadPoolExecutor的使用
private static final ThreadGroup group = Thread.currentThread().getThreadGroup();;
private static final AtomicInteger threadNumber = new AtomicInteger(1);
List<Runnable> overflowList = new ArrayList<>();
// 创建一个线程池 参数都不是必须的、可以根据需要填写
ExecutorService pool = new ThreadPoolExecutor(
3, // 核心线程数
6, // 最大线程数
500, // 空闲线程空闲多久回收的时间
TimeUnit.MILLISECONDS, // 空闲线程空闲多久回收的时间的时间的单位
new LinkedBlockingQueue<>(10), // 任务队列
new ThreadFactory() { // 创建线程的方法定义
@Override
public Thread newThread(@NotNull Runnable r) {
Thread thread = new Thread(group, r, "Thread_pool_" + threadNumber.getAndIncrement(), 0);
return thread;
}
},
new RejectedExecutionHandler() { // 线程池线程不够、且队列也没空余的拒绝策略
@Override
public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
System.out.println("涌入工作太多了," + executor.getPoolSize());
overflowList.add(r);
}
}
);
// 执行一个普通任务
pool.execute(() -> {
System.out.println("当前线程任务" + Thread.currentThread().getName());
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
});
// 执行一个带返回值的任务
Future<Integer> future = pool.submit(() -> {
Thread.sleep(1200);
return 1234;
});
System.out.println("返回值:"+future.get());