java并发之线程池
在并发场景下,几乎所有的异步操作和任务执行都可以使用线程池,线程池具有如下优点
- 降低资源消耗
- 提高响应速度
- 提高线程的可管理性
实现原理
从图中可以看出,提交一个新任务到线程池的处理流程如下:
- 判断线程池里的核心线程是否都在执行任务,如果不是则创建一个新的工作线程执行任务,如果是则进入下个流程(corepoolsize是否已满)
- 判断线程池的工作队列是否已满,如果工作队列没有满,则将新提交的任务存储进工作队列里,如果工作队列已经满了,进入下个流程
- 判断线程池的所有线程是否都在工作状态。如果没有,则创建新的工作线程执行任务,如果已经满了,交给饱和策略来处理这个任务(maxpoolsize是否已满)
Executor框架
java采用Executor将任务分解到不同的线程,然后操作系统内核将这些线程映射到处理器的两级调用框架。其中,Executor的核心接口是Executor和其子接口ExecutorService,两个核心实现类是ThreadPoolExecutor和ScheduledThreadPoolExecutor。
ThreadPoolExecutor的execute方法
public void execute(Runnable command) {
//传入继承Runable接口的任务,不能为null
if (command == null)
throw new NullPointerException();
int c = ctl.get();
//判断当前工作线程的数量是否小于核心线程数量
if (workerCountOf(c) < corePoolSize) {
//创建线程运行该任务,允许失败
if (addWorker(command, true))
return;
c = ctl.get();
}
//如果当前运行线程数大于核心线程数或创建失败,将任务添加到工作队列
if (isRunning(c) && workQueue.offer(command)) {
int recheck = ctl.get();
if (! isRunning(recheck) && remove(command))
reject(command);
else if (workerCountOf(recheck) == 0)
addWorker(null, false);
}
//如果队列已满且不允许新建线程则执行饱和策略
else if (!addWorker(command, false))
reject(command);
}
2、线程池使用
线程池创建
ThreadPoolExecutor初始化
ThreadPoolExecutor(int corePoolSize,//核心线程数量
int maximumPoolSize,//最大线程数量
long keepAliveTime,//空闲线程存活时间
TimeUnit unit,//时间单位
BlockingQueue<Runnable> workQueue,//任务队列,保存等待任务的阻塞队列
ThreadFactory threadFactory,//创建线程的工厂类
RejectedExecutionHandler handler)//饱和策略
提交任务
ThreadPoolExecutor有两个方法可以提交任务execute()和submit()。其中submit()方法提交的任务可以返回一个future对象来接收返回值。
中止线程池
可以调用shutdown()或者shutdownnow()方法来关闭线程池,两个方法都是遍历所有线程然后调用interrupt方法来实现,不同之处在于shutdown将线程池设置为shutdown状态然后关闭所有没有正在执行的线程,shutdownnow方法将线程池置为stop状态然后关闭所有线程。