Java线程池
目录
创建线程的方法
- 实现Runnable接口
- 实现Callable接口
- 继承Thread类
为什么要使用线程池
- 降低资源消耗,减少创建线程的开销
- 提高响应速度,新任务可以由空闲线程立刻执行
- 可管理性,线程池统一管理
创建线程池的方法
Executors类提供了几个静态方法用于创建线程池
- newSingleThreadExecutor(),核心池大小为1,LinkedBlockingQueue(最大)
- newFixedThreadPool(n),指定核心池大小为
- newCachedThreadPool(),
- newScheduledThreadPool(),定时任务,有多线程实现和单线程实现
不建议使用Executors提供的几种线程池而要使用ThreadPoolExecutor的构造方法指定参数
防止OOM,Executors提供的几种线程池的等待队列没有设置大小限制(最大),可能会造成OOM,所以一般使用ThreadPoolExecutor的构造方法创建线程池:
public class ThreadPoolExecutor extends AbstractExecutorService {
.....
public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit,
BlockingQueue<Runnable> workQueue);
public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit,
BlockingQueue<Runnable> workQueue,ThreadFactory threadFactory);
public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit,
BlockingQueue<Runnable> workQueue,RejectedExecutionHandler handler);
public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit,
BlockingQueue<Runnable> workQueue,ThreadFactory threadFactory,RejectedExecutionHandler handler);
...
}
线程池的参数
- corePoolSize:核心池大小
- maximumPoolSize:最大线程数
- keepAliveTime:线程的空闲时间
- unit:空闲时间的单位(时分秒毫秒)
- workQueue:等待队列/阻塞队列,有多种类型
- threadFactory:线程工厂,用来创建线程
- handler:拒绝策略,多种类型
线程池的状态
running=0
shutdown=1
stop=2
terminated=3
调用ThreadPoolExecutor的shutdown方法后,处于shutdown状态;
调用shutdownNow方法后,处于stop状态
所有工作线程已经销毁并且缓存队列清空,处于terminated状态
任务提交发生了什么
通过ThreadPoolExecutor.execute()方法提交任务,
如果线程数小于核心线程数,则创建线程执行任务;
否则,如果线程数小于最大线程数,则尝试将任务放进等待队列;
如果等待队列已满,并且线程数小于最大线程数,则新建线程执行该任务;
如果已达最大线程数,则采取拒绝策略。
关于keepAliveTime,当核心池已满时,会对核心池线程的空闲时间进行判断并回收,直至线程数不大于核心线程数。
如果还设置了allowCoreThreadTimeOut,那么在线程数小于等于核心线程数的时候也会回收
等待队列的类型
- ArrayBlockingQueue,必须指定大小
- LinkedBlockingQueue,默认大小为最大
- SynchronousQueue,新建线程执行任务
拒绝策略
- ThreadPoolExecutor.AbortPolicy:丢弃任务,抛出RejectedExecutionException异常
- ThreadPoolExecutor.DiscardPolicy:丢弃任务,不抛出异常
- ThreadPoolExecutor.DiscardOldestPolicy:丢弃队列最前端的任务
- ThreadPoolExecutor.CallerRunsPolicy:调用者处理该任务
线程池的关闭
- shutdown():不再接受新任务,等待已有任务完成
- shutdownNow():不再接受新任务,尝试中断正在执行的任务并清空等待队列(通过调用每个线程的interrupt方法)
合理配置线程池大小
- cpu密集型:cpu+1
- IO密集型:2*cpu
线程池使用示例
public class ThreadTest {
public static void main(String[] args) {
ThreadPoolExecutor executor=new ThreadPoolExecutor(
1000,2000,1000, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<>(1000));
for(int i=0;i<999;i++){
MyTask myTask = new MyTask(i);
executor.execute(myTask);
System.out.println("核心池线程数: "+executor.getCorePoolSize()
+"等待队列: "+executor.getQueue().size()
+"已完成任务数"+executor.getCompletedTaskCount());
}
executor.shutdown();
}
}
class MyTask implements Runnable{
private int taskNum;
public MyTask(int taskNum) {
this.taskNum = taskNum;
}
@Override
public void run() {
System.out.println("开始task "+taskNum);
try {
Thread.currentThread().sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("结束task "+taskNum);
}
}