ThreadPoll线程池
为什么要用线程池
线程池做的工作主要是控制运行的数量,处理过程中将任务放到队列,然后在线程创建后启动这些任务,如果线程数量超过了最大数量,超出数量的线程排队等候,等到其他线程执行完毕,再从队列中取出任务来执行。
主要特点:线程复用,控制最大并发数,管理线程
优势:
- 降低资源消耗,重复利用已经创建好的线程
- 提高响应速度,当任务到达时,任务不需要创建线程就可以立刻执行
- 提高线程可管理性:线程池可以进行统一的分配,调优,和监控
连接池同理
线程池如何使用
public class PoolDemo {
public static void main(String[] args) {
//建立线程池,有各种实现类,不同的实现类有不同的特性
ExecutorService threadPool = Executors.newFixedThreadPool(3);//银行有n个窗口,1池n线程,线程数不会变
ExecutorService threadPool2 = Executors.newSingleThreadExecutor();//银行有1个窗口,1池1线程,线程数不会变
ExecutorService threadPool3 = Executors.newCachedThreadPool();//银行有可扩展窗口
try {
for (int i = 0; i < 3000; i++) {
threadPool3.execute(() -> {
System.out.println(Thread.currentThread().getName() + "\t号业务员办理业务");
}); }
} catch (Exception e) {
e.printStackTrace();
} finally {
threadPool3.shutdown();//关闭线程池
}
}
}
线程池的底层原理
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
}
public static ExecutorService newCachedThreadPool(ThreadFactory threadFactory) {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>(),
threadFactory);
}
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler) {
创建线程池都是返回ThreadPoolExecutor对象,并且设置一些参数:
- corePoolSize:线程池里面常驻的线程数,银行里面日常开放的柜台,惰性加载
- maximumPoolSize:最大线程数,当银行来人多的话,柜台就开的多
- keepAliveTime:空闲线程存活时间,没有任务时,不需要坐班的人,需要留着的时间,时间到就下班。值班的还在。
- TimeUnit unit:时间单位
- workQueue:任务队列,提交还没有执行的任务
- threadFactory:线程工厂
- handler:拒绝策略,银行人太多了,把顾客拒绝到门外
工作原理:
- 当线程池初始化完成时,实际上一个线程都没有。
- 当开始执行时,先判断有没有核心线程,没有的话就直接创建,有的话就分配任务
- 当核心线程全部被分配时,任务先放入任务队列中等待,直到任务队列存满,则在不超过最大线程的前提下,扩充线程,但是这个时候创建的新的线程会处理新来的任务,而不是队列中等候的任务。
- 当出现线程空闲时,达到时间后,销毁多出来的线程
- 当高峰时,线程全部占满,队列占满,则开始拒绝任务
拒绝策略
当线程最大数量达到了,队列也满了,就需要拒绝策略了
jdk内置策略:
- AbortPoilcy:默认策略,直接异常
- callerRunPoilcy:哪里来的回到哪里去,返回到调用者
- DiscardOldestPoily:抛弃队列里面最久的任务,给新任务让出位置
- DiscardPoily:默默丢弃无法处理的任务,不处理,不异常。
一般不使用Excutor去创建,而是通过ThreadPoolExecutor来创建,避免资源耗尽的风险
阿里巴巴开发手册
最好手写线程池,将参数自己设置
public class PoolDemo {
public static void main(String[] args) {
//建立线程池,有各种实现类,不同的实现类有不同的特性
// ExecutorService threadPool = Executors.newFixedThreadPool(3);//银行有n个窗口,1池n线程,线程数不会变
// ExecutorService threadPool2 = Executors.newSingleThreadExecutor();//银行有1个窗口,1池1线程,线程数不会变
// ExecutorService threadPool3 = Executors.newCachedThreadPool();//银行有可扩展窗口
ExecutorService threadPool3 = new ThreadPoolExecutor(2,5,3L,TimeUnit.SECONDS,
new ArrayBlockingQueue<Runnable>(3),
Executors.defaultThreadFactory(),
new ThreadPoolExecutor.CallerRunsPolicy());
try {
for (int i = 0; i < 30; i++) {
threadPool3.execute(() -> {
System.out.println(Thread.currentThread().getName() + "\t号业务员办理业务");
}); }
} catch (Exception e) {
e.printStackTrace();
} finally {
threadPool3.shutdown();//关闭线程池
}
}
}