Java 线程池
什么是线程池, 为什么要用线程池
线程池是最常见的并发框架, 好处是:
原来线程需要 T1:创建 T2:运行 T3:销毁, 有了线程池以后, 可以直接让另一个线程运行. 这么做的好处则是
1.降低资源消耗,不需要再去创建其他新的线程了.
2.提高响应速度, 不需要在T1和T3步骤上花时间.
3.提高线程可管理性,
线程池的实现
Executer接口框架
接口——>抽象类——>实现类
(上课一笔带过,具体不考)
面试必考
threadPool 初始化.
各个参数含义:
CorePoolSize():线程的数量
MaximumPoolSize():最大线程数量
KeepAliveTime 线程空闲的存活时间
TimeUnit Unit:线程空闲存活时间的单位
BlockingQueue<Runnable> workQueue(): 阻塞队列
1.传入一个任务, 新建一个线程,直到达到CorePoolSize()
2.当达到CorePoolSiz()的时候, 传入到阻塞队列
3.当阻塞队列满的时候,创建线程, 但不能超过MaximumPoolSize().
4.如果超过了MaximumPoolSize(), 则调用RejectionExecutionHandler(接口), 其中有四个实现方法:
a.删掉最老的等待线程
b.抛出异常
c.提交任务者执行任务(主线程提交任务, 主线程去执行)
d.自定义执行任务,比如可以把任务扔到数据库里面去。
线程池中的线程工厂(Executer.defaultThreadFactory, ThreadFactory也是接口)
重要用于给线程命名,比如说pool+序列号+thread, 并且会把所有的线程设置为守护线程,当主线程退出的时候,守护线程不论如何都会退出。如果不设置成守护线程的话,那要等每一个线程都退出才能退出,没有办法强制关闭.
如果想要在线程开始和结束打印话,则可以使用beforeExecutor和AfterExecutor来打印, 是两个没有实现的方法, 以及terminated(), 在线程池结束后的方法.
如果传入的是callable()实现的线程, 那么如下, 可以开一个future并通过submit函数来实现返回值.
Execute(提交没有返回值的任务), submit(提交有返回值的任务)
线程池的关闭
shutDown() && shutDownNow()
shutDown(): 遍历每一个线程,Call一遍Interrupt, 改了Interrupt的标志位.
ShutDownNow(): 强行中断,任务不一定执行完.
如何合理配置线程池
合理配置线程池需要知道任务的特性:
1.CPU密集型, 不断从内存中获取数据 2.IO密集型, 总是和磁盘与网络 3.混合型
CPU密集型: 配置线程数不超过当前机器上的CPU数
IO密集型:经验取值, CPU数X2(如果CPU还是很闲, X3或X4)
混合型: 拆分成两个线程池, 如果两个任务时间相差不大的话(如果大的话, 则不用拆分,因为没有太大改善)
BlockingQueue<>的选择
BlockingQueue一定要是有界队列,如果是无界的话,就会无线扩充,一旦OOM导致的话有可能导致线程池停止。