主要控制运行的线程的数量,处理过程中将任务放入队列中
,然后在线程创建后启动这些任务,如果线程的数量超过了最大数量的线程排队等候
,等其他线程执行完毕,再从队列中取出任务来执行。
ThreadPoolExecutor类
ThreadPoolExecutor类
ThreadPoolExecutor类
ExecutorService,Executors
重要的事情说三遍!!!
五种从线程池创建线程方式(1,2了解3,4,5掌握)
通过分别调用Executors类的方法实现不同类型功能的线程池,但是底层仍然是调用了ThreadPoolExecutor
ScheduledExecutorService executor = Executors.newScheduledThreadPool(10);
ExecutorService executor = Executors.newWorkStealingPool();
ExecutorService executor = Executors.newFixedThreadPool(5);
ExecutorService executor = Executors.newSingleThreadExecutor();
ExecutorService executor = Executors.newCachedThreadPool();
**Executors.newScheduledThreadPool(常驻核心线程数):**创建一个定长线程池,支持定时及周期性任务执行。延迟执行
Executors.newWorkStealingPool();java8新特性
: 创建一个具有抢占式操作的线程池 ForkJoinPool 类
Executors.newFixedThreadPool(线程数): 创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。
Executors.newSingleThreadExecutor(): 创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。
Executors.newCachedThreadPool(): 创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。
public class ThreadPoolExecutorDemo {
/*10个人在银行办事,银行有五个工作人员*/
public static void main(String[] args) {
// ExecutorService executor = Executors.newFixedThreadPool(5);
// ExecutorService executor = Executors.newSingleThreadExecutor();
ExecutorService executor = Executors.newCachedThreadPool();
try {
for (int i = 1; i <= 10; i++) {
int finalI = i;
executor.execute(() -> {
System.out.println(Thread.currentThread().getName() + "\t" + finalI);
});
}
}
finally {
executor.shutdown();
}
}
}
结果:不唯一
一个都不用,生产中我们只使用自己定义的
为什么不用JDK帮助我们已经写好的Executor类的new方法?
生产实践与知识教育并不能一概而论
例如在linkedblockingQueue中的长度为INT_MAX大约21亿,然而现实生活中没有哪个服务器可以支撑那么多数据而安然无恙
阻塞队列BlockingQueue接口-类似食品柜
public class MyselfThreadPool {
public static void main(String[] args) {
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
2,
5,
1l,
TimeUnit.SECONDS,
new LinkedBlockingDeque<>(3),
Executors.defaultThreadFactory(),
new ThreadPoolExecutor.AbortPolicy());
try {
for (int i = 1; i <= 8; i++) {
threadPoolExecutor.execute(() -> {
System.out.println("线程"+Thread.currentThread().getName() + "\t办理业务");
});
}
}
catch (Exception e){
e.printStackTrace();
}
finally {
threadPoolExecutor.shutdown();
}
}
}
结果
当创建线程到最大线程数后,非核心线程数优先处理不在阻塞队列中的任务。
线程池可处理的任务数=最大线程数+阻塞队列长度
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler) {
······ }
当线程池的任务缓存队列已满并且线程池中的线程数目达到maximumPoolSize时,如果还有任务到来就会采取任务拒绝策略,通常有以下四种策略:
项目 | 作用 |
---|---|
ThreadPoolExecutor.AbortPolicy | 丢弃任务并抛出RejectedExecutionException异常 |
ThreadPoolExecutor.CallerRunsPolicy | 由调用线程(提交任务的线程)处理该任务 |
ThreadPoolExecutor.DiscardOldestPolicy | 丢弃队列等待最久的的任务,然后重新提交当前任务 |
ThreadPoolExecutor.DiscardPolicy | 丢弃任务,但是不抛出异常 |
1.当正在运行的线程数小于常驻核心线程数时,那么会立即创建线程执行任务;
2.当正在运行的线程数大于或者等于核心线程数,那么将这个任务放入队列中;
3.当队列已满且正在运行的线程数小于最大线程数,那么还是要创建非核心线程立刻运行非队列中的任务;
4.当队列满了,且运行线程数大于或者等于最大线程数,那么就启用饱和拒绝策略来执行
System.out.println(Runtime.getRuntime().availableProcessors());//我的是4核心数,一般商务本配置
也就是说,我应该设置最大线程数为4+1=5
也就是说,我可以设置最大线程数为4*2=8或者4/1-0.9=40