java线程池知识整理
参考,欢迎点击原文:https://www.jianshu.com/p/246021d04310(java多线程那点事)
https://blog.csdn.net/fanrenxiang/article/details/79855992(线程池整理,很大篇幅)
科普:
1、Juc (java util concurrent) : java并发包
2、并发编程本质:充分利用cpu资源
池的特点: 线程复用,可以控制最大并发数,管理线程
降低资源消耗,提高响应速度,方便管理
这两天整理和java多线程,随即也看了java的线程池,线程池大致流程如下图
Executors的四种线程池类型:
-
newFixedThreadPool:核心线程数=最大线程数,无界队列,可能大量请求导致oom
-
newSingleThreadExector:核心线程数=最大线程数,单线程,无界队列,可能大量请求导致oom(FIFO)
-
newCachedThreadPool:遇强则强,同步移交队列,没有常驻线程,自动回收,可能大量线程导致oom(适用处理生存期较短的异步任务)
-
newScheduledThreadPool:周期性检查,延迟执行,可能大量线程导致oom
四种线程池特点:
-
newFixedThreadPool:固定线程池,超过要排队
-
newSingleThreadExector:单线程线程池,串型执行
-
newCachedThreadPool:可缓存线程池,灵活回收,灵活新建
-
newScheduledThreadPool:定长线程池,周期性执行
线程池里手动创建,ThreadPoolExecutor参数:
- corePoolSize:核心线程数,属常驻线程
- maximumPoolSize:最大线程数
- keepAliveTime:非核心线程空闲被回收时间
- unit:时间单位
- workQueue:保存任务的队列,1无界,2有界,3同步移交
- threadFactory:创建线程的工厂类,也比如guava
- handler:饱和策略
非核心线程: 通过poll拿队列中的任务,会被回收
核心线程: 通过task拿队列中的任务,唤醒其他阻塞线程
可使用的两个类:
Runnable:没有返回值,不能通过throw抛异常,效率更低
Callable:有返回值,能抛异常,new FutureTask(thread)适配类
tip:
- Future.get可以阻塞获得任务返回结果
- new Thread创建的是守护进程 ,ThreadFactory创建的是非守护进程
- ThreadLocal:存线程自身的变量副本
- StringBuffer为啥是线程安全的:因为多个操作都是在一个对象上进行操作的,且这个类里面很多方法都是用synchronized修饰
设置多少个线程:
cpu密集型:和cpu核心数一样的数量
io密集型:长时间io,cpu两倍
中断:
Shutdown:中断所有没有正在执行的线程
ShutdownNow:中断所有线程
唤醒其他等待线程执行
CyclicBarrier :只能唤起一个任务,可重用;
CountDownLatch(倒计时计算器): 协调多个线程之间的同步,或者说起到线程之间的通信,可以唤起多个任务。不可重用
【原理:countDownLatch是个计数器,减到了0,wait就会被唤醒,执行了,如下图】
线程通信方式:
1消息传递,
2共享内存
【 wait/notify/notifyAll、await/signal/signalAll ,阻塞队列 BlockingQueue 】
Wait需要配合synchronized使用
ABA问题: A->B->A,但是cas没有发现变化,可以使用版本号来避免
使用volatile关键字: 多个线程监听一个变量,读取到volatile修饰的变量都是最新的,禁止指令重排序
实践应用: 看lms的LessonJsonTaskHelper类