线程池
1. 对比
new Thead 弊端
- 每次 new Thread 新建对象,性能差
- 线程缺乏统一管理,可能无限制的新建线程,相互竞争,有可能占用过多系统资源导致死机或OOM
- 缺乏更多功能,如更多执行,定期执行,线程中断
线程池的好处
- 重用存在的线程,减少对象创建,消亡的开销,性能佳
- 可有效控制最大并发线程数,提供系统资源利用率,同时可以避免过多资源竞争,避免阻塞。
- 可以提供定时执行,定期执行,单线程,并发数控制等功能
1.2 ThreadPoolExecutor
- corePoolSize:核心线程数量
- maximumPoolSize:线程最大线程数
- workQueue:阻塞队列,存储等待执行的任务,很重要,会对线程池运行过程产生重大影响
如果线程池中的线程数小于corePoolSize,直接创建新线程来处理任务,即使线程池的其他线程时空闲的,如果线程池中的线程数大于等于 corePoolSize 小于maximumPoolSize,则只有当workQueue满的时候才会去创建新的线程执行任务。
如果我们设置的corePoolSize和maximumPoolSize相同的话,则创建的线程池大小是固定的,如果有新的任务提交,如果workQueue没慢的话,则入队,等到线程池中有空的线程再执行。
- keepAliveTime:线程没有任务执行时最多保持多久时间终止
- unit:keepAliveTime的时间单位
- threadFactory:线程工厂,用来创建线程
- rejectHandler:当拒绝处理任务时的策略
- 抛出异常
- 抛弃前面的任务,执行新的
- 直接抛弃
- 用调用者线程执行
1.3 线程池状态
- Running:能接受新提交的任务,也能处理阻塞队列中的任务
- Shutdown:关闭状态,不能接受新提交的任务,可以处理阻塞队列中保存的任务。
- Stop:不接受新任务,也不处理队列中的任务,会中断正在处理任务的线程。
- Tidying:如果所有任务都终止了。
- Terminated:调用了terminated()方法。
ThreadPoolExecutor提供的基础方法
- execute():提交任务,交给线程池执行。
- submit():提交任务,能够返回执行结果 execute+Future
- shutdown():关闭线程池,等待任务都执行完
- shutdownNow():关闭线程池,不等待任务执行完
常用于监控的方法
- getTaskCount():线程池已执行和未执行的任务总数
- getCompletedTaskCount():已完成的任务数量
- getPoolSize():线程池当前的线程数量
- getActiveCount():当前线程池中正在执行任务的线程数量
1.4 Executor框架接口
- Executors.newCachedThreadPool:创建可缓存的线程池,如果线程池长度超过处理需要,可以回收,如果么有回收的,则新建线程
- Executors.newFixedThreadPool:定长的线程池,可以控制并发的线程数,超出的线程再队列中等待
- Executors.newScheduledThreadPool:创建定长的线程池,支持定时以及周期性的任务执行
- Executors.newSingleThreadExecutor:创建的是一个单线程化的线程池,只用唯一一个工作线程执行任务,指定按照某种顺序执行。
import lombok.extern.slf4j.Slf4j;
import java.util.Date;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
/** * Created By liuyao on 2018/4/23 17:21. */
@Slf4j
public class ThreadPoolExample4 {
public static void main(String[] args) {
ScheduledExecutorService scheduledExecutorService=Executors.newScheduledThreadPool(5);
scheduledExecutorService.schedule(new Runnable() {
@Override
public void run() {
log.info("schedual run");
}
},3, TimeUnit.SECONDS);
scheduledExecutorService.scheduleAtFixedRate(new Runnable() {
@Override
public void run() {
log.info("schedual run");
}
},1,3,TimeUnit.SECONDS); //在线程池创建后1秒每隔3秒去执行任务
// scheduledExecutorService.shutdown();
Timer timer=new Timer();
timer.schedule(new TimerTask() {
@Override
public void run() {
log.info("timer run");
}
},new Date(),3*1000); //定时3秒继续执行任务
}
}
上面利用了newScheduledThreadPool
创建定时执行的任务和利用Timer也可以定时执行任务。
2. 线程池的配置
- CPU密集型任务,就需要尽量压榨CPU,参考值可以设为
NCPU+1
- IO密集型任务,参考值可以设为
2*NCPU