https://snailclimb.gitee.io/javaguide/#/./docs/java/Multithread/java%E7%BA%BF%E7%A8%8B%E6%B1%A0%E5%AD%A6%E4%B9%A0%E6%80%BB%E7%BB%93?id=%e4%ba%8c-executor-%e6%a1%86%e6%9e%b6
优点:
- 降低资源消耗。通过重复利用已创建的线程降低线程创建和销毁造成的消耗。
- 提高响应速度。当任务到达时,任务可以不需要的等到线程创建就能立即执行。
- 提高线程的可管理性。
池化技术相比大家已经屡见不鲜了,线程池、数据库连接池、Http 连接池等等都是对这个思想的应用。池化技术的思想主要是为了减少每次获取资源的消耗,提高对资源的利用率。
Executor
Executor框架是 Java5 之后引进的,在 Java 5 之后,通过 Executor 来启动线程比使用 Thread 的 start 方法更好,除了更易管理,效率更好(用线程池实现,节约开销)外,还有关键的一点:有助于避免 this 逃逸问题
Executor 框架不仅包括了线程池的管理,还提供了线程工厂、队列以及拒绝策略等,Executor 框架让并发编程变得更加简单。
任务(Runnable /Callable)
执行任务需要实现的 Runnable 接口 或 Callable接口。Runnable 接口或 Callable 接口 实现类都可以被 ThreadPoolExecutor 或 ScheduledThreadPoolExecutor 执行。
任务的执行(Executor)
任务执行机制的核心接口 Executor ,以及继承自 Executor 接口的 ExecutorService 接口。ThreadPoolExecutor 和 ScheduledThreadPoolExecutor 这两个关键类实现了 ExecutorService 接口。
这里提了很多底层的类关系,但是,实际上我们需要更多关注的是 ThreadPoolExecutor 这个类,这个类在我们实际使用线程池的过程中,使用频率还是非常高的。
线程池,Executor,Executors,ExecutorService,CompletionService,Future,Callable等。
创建线程池
一. ThreadPoolExecutor构造函数
ThreadPoolExecutor 类分析
/**
* 用给定的初始参数创建一个新的ThreadPoolExecutor。
*/
public ThreadPoolExecutor(int corePoolSize,//线程池的核心线程数量
int maximumPoolSize,//线程池的最大线程数
long keepAliveTime,//当线程数大于核心线程数时,多余的空闲线程存活的最长时间
TimeUnit unit,//时间单位
BlockingQueue<Runnable> workQueue,//任务队列,用来储存等待执行任务的队列
ThreadFactory threadFactory,//线程工厂,用来创建线程,一般默认即可
RejectedExecutionHandler handler//拒绝策略,当提交的任务过多而不能及时处理时,我们可以定制策略来处理任务
) {
.execute()方法调用流程
public void execute(Runnable command) {
if (command == null)
throw new NullPointerException();
//获得当前线程池
int c = ctl.get();
//判断线程数是否否有空余的
if (workerCountOf(c) < corePoolSize) {
//创建内部工作类,执行command
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);
}
addWorker创建内部Worker类,其中调用getThreadFactory().newThread(this)来创建执行自己的线程,之后在addWorker中start该线程
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5FQCgNDB-1590499690932)(D99AC9E3EBEA45478B44451CD4E91275)]
二. 通过 Executor 框架的工具类 Executors 来实现 我们可以创建三种类型的 ThreadPoolExecutor
- newCachedThreadPool: 创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。
- newFixedThreadPool: 创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。
- newSingleThreadExecutor: 创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行
返回的是 “ExecutorService”;
- newScheduledThreadPool: 创建一个定长线程池,支持定时及周期性任务执行。
返回的是 “ScheduledExecutorService”;
public class NewScheduledThreadPool {
/**
* 我们获取四次次线程,观察4个线程地址
* @param args
*/
public static void main(String[]args)
{
ScheduledExecutorService newScheduledThreadPool = Executors.newScheduledThreadPool(2);
System.out.println("****************************newFixedThreadPool*******************************");
for(int i=0;i<4;i++)
{
final int index=i;
//延迟三秒执行
newScheduledThreadPool.schedule(new ThreadForpools(index),3, TimeUnit.SECONDS);
}
}
}