更多精彩请关注公众号xhJaver,京东java工程师和你一块儿成长
咱们知道,在计算机中建立一个线程和销毁一个线程都是十分耗费资源的操做,有一种思想叫作,池化思想,就是说咱们建立个池子,把耗费资源的操做都提早作好,后面你们一块儿用建立好的东西,最后统一销毁。省去了用一次建立一次,销毁一次,这种耗费资源的操做。java
线程池就是这种思想,他的基本工做流程以下图所示数组
那么他的核心线程,任务队列,这些又是什么呢?怎么设置呢?安全
这些就要从代码入手了,咱们先来看下线程池构造方法的代码ide
public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler) { if (corePoolSize < 0 || maximumPoolSize <= 0 || maximumPoolSize < corePoolSize || keepAliveTime < 0) throw new IllegalArgumentException(); if (workQueue == null || threadFactory == null || handler == null) throw new NullPointerException(); this.acc = System.getSecurityManager() == null ? null : AccessController.getContext(); this.corePoolSize = corePoolSize; this.maximumPoolSize = maximumPoolSize; this.workQueue = workQueue; this.keepAliveTime = unit.toNanos(keepAliveTime); this.threadFactory = threadFactory; this.handler = handler; }
其实ThreadPoolExecutor有四种构造方法,不过底层都是用这个7个参数的构造方法,因此咱们弄懂这一个就行了,如下是其余构造方法的底层实现测试
public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, RejectedExecutionHandler handler) { this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, Executors.defaultThreadFactory(), handler); }
public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue) { this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, Executors.defaultThreadFactory(), defaultHandler); }
public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory) { this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory, defaultHandler); }
其中默认的拒绝策略是this
private static final RejectedExecutionHandler defaultHandler = new AbortPolicy();
这些构造方法中的atom
this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory, defaultHandler);
就是那七个参数的构造方法spa
有点懵?不要紧,接下来咱们一个个的解析这七个参数的意思线程
public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler) { if (corePoolSize < 0 || maximumPoolSize <= 0 || maximumPoolSize < corePoolSize || keepAliveTime < 0) throw new IllegalArgumentException(); if (workQueue == null || threadFactory == null || handler == null) throw new NullPointerException(); this.acc = System.getSecurityManager() == null ? null : AccessController.getContext(); this.corePoolSize = corePoolSize; this.maximumPoolSize = maximumPoolSize; this.workQueue = workQueue; this.keepAliveTime = unit.toNanos(keepAliveTime); this.threadFactory = threadFactory; this.handler = handler; }
1. 第一个参数 corePoolSize 表明这个线程池的核心线程数日志
2. 第二个参数 maximumPoolSize 表明这个线程池的最大线程数 (核心线程数 +非核心线程数)
3. 第三个参数 keepAliveTime 表明这个线程池的非核心线程的空闲时的存活时间
4. 第四个参数 unit 表明这个线程池的非核心线程的空闲存活时间的单位
5. 第五个参数 workQueue 表明这个线程池的任务阻塞队列,jdk中有几种常见的阻塞队列
建议:建议使用有界队列,要是无界队列的话,任务太多的话可能会致使OOM
6. 第六个参数 threadFactory(能够自定义) 表明这个线程池的建立线程的工厂,有两种
7. 第七个参数 handler(能够自定义) 表明这个线程池的拒绝处理任务的饱和策略,jdk默认提供了四种
基础概念也都看了,下面来看个使用线程池处理任务的小例子
首先,咱们先建立个任务类
public class Task implements Runnable { private String taskName; public Task(String taskName) { this.taskName = taskName; } @Override public void run() { try { //模拟每一个任务的耗时 Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } String name = Thread.currentThread().getName(); System.out.println("这里是xhJaver,线程池系列 当前线程名字是 " + name+" 处理了 "+ taskName+" 任务"); } }
咱们再来看测试类
public class Demo1 { public static void main(String[] args) { //阻塞队列,设置阻塞任务最多为10个 BlockingQueue<Runnable> blockingQueue = new ArrayBlockingQueue<Runnable> (10); //线程工厂 ThreadFactory threadFactory = Executors.defaultThreadFactory(); //拒绝策略 当线程池的最大工做线程跑满以及阻塞队列满了的话,会由拒绝策略处理剩下的任务 ThreadPoolExecutor.AbortPolicy abortPolicy = new ThreadPoolExecutor.AbortPolicy(); //建立线程池 核心线程数为5 最大线程数为10 非核心线程空闲存活时间为60s ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(5, 10, 60L, TimeUnit.SECONDS, blockingQueue, threadFactory, abortPolicy ); for (int i=0;i<10;i++){ //建立10个任务,若是要是建立>20个任务,则20之外的任务会交由拒绝策略处理 Task task = new Task("task" + i); //让咱们自定义的线程池去跑这些任务 threadPoolExecutor.execute(task); } //记得要关闭线程池 threadPoolExecutor.shutdown(); } }
输出结果是
这里是xhJaver,线程池系列 当前线程名字是 pool-1-thread-1 处理了 task0 任务 这里是xhJaver,线程池系列 当前线程名字是 pool-1-thread-2 处理了 task1 任务 这里是xhJaver,线程池系列 当前线程名字是 pool-1-thread-3 处理了 task2 任务 这里是xhJaver,线程池系列 当前线程名字是 pool-1-thread-4 处理了 task3 任务 这里是xhJaver,线程池系列 当前线程名字是 pool-1-thread-5 处理了 task4 任务 这里是xhJaver,线程池系列 当前线程名字是 pool-1-thread-1 处理了 task5 任务 这里是xhJaver,线程池系列 当前线程名字是 pool-1-thread-2 处理了 task6 任务 这里是xhJaver,线程池系列 当前线程名字是 pool-1-thread-5 处理了 task9 任务 这里是xhJaver,线程池系列 当前线程名字是 pool-1-thread-4 处理了 task8 任务 这里是xhJaver,线程池系列 当前线程名字是 pool-1-thread-3 处理了 task7 任务
文中一直说线程工厂线程工厂,这线程工场究竟是干吗的呢? 固然是建立线程的工厂啦,建立线程,线程固然得有个名字咯,就像刚才的小例子输出的同样,线程的名字是pool-1-thread-3等等,我如今不想叫这个名字了,那就叫thread-xhJaver吧,这是自定义的名字,那怎么自定义呢?
首先,要实现ThreadFactory接口中的Thread newThread(Runnable r)方法, 传入一个任务,返回一个自定义线程,以下面的代码同样
public class DIYThreadFactory implements ThreadFactory { private AtomicInteger atomicInteger; public DIYThreadFactory( AtomicInteger atomicInteger){ this.atomicInteger = atomicInteger; } @Override public Thread newThread(Runnable r) { Thread thread = new Thread(r); thread.setName("xhJaver-thread-"+atomicInteger.getAndIncrement()); return thread; } }
而后在使用时传入这个自定义的线程工厂
public static void main(String[] args) { //阻塞队列,设置阻塞任务最多为10个 BlockingQueue<Runnable> blockingQueue = new ArrayBlockingQueue<Runnable> (10); //建立线程安全的计数器 AtomicInteger atomicInteger = new AtomicInteger(); //自定义线程工厂 ThreadFactory threadFactory = new DIYThreadFactory(atomicInteger); //拒绝策略 当线程池的最大工做线程跑满以及阻塞队列满了的话,会由拒绝策略处理剩下的任务 ThreadPoolExecutor.AbortPolicy abortPolicy = new ThreadPoolExecutor.AbortPolicy(); //建立线程池 核心线程数为5 最大线程数为10 非核心线程空闲存活时间为60s ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(5, 10, 60L, TimeUnit.SECONDS, blockingQueue, threadFactory, abortPolicy ); for (int i=0;i<10;i++){ //建立10个任务,若是要是建立>20个任务,则20之外的任务会交由拒绝策略处理 Task task = new Task("task" + i); //让咱们自定义的线程池去跑这些任务 threadPoolExecutor.execute(task); } //记得要关闭线程池 threadPoolExecutor.shutdown(); }
输出结果是
这里是xhJaver,线程池系列 当前线程名字是 xhJaver-thread-0 处理了 task0 任务 这里是xhJaver,线程池系列 当前线程名字是 xhJaver-thread-1 处理了 task1 任务 这里是xhJaver,线程池系列 当前线程名字是 xhJaver-thread-4 处理了 task4 任务 这里是xhJaver,线程池系列 当前线程名字是 xhJaver-thread-3 处理了 task3 任务 这里是xhJaver,线程池系列 当前线程名字是 xhJaver-thread-2 处理了 task2 任务 这里是xhJaver,线程池系列 当前线程名字是 xhJaver-thread-0 处理了 task5 任务 这里是xhJaver,线程池系列 当前线程名字是 xhJaver-thread-1 处理了 task6 任务 这里是xhJaver,线程池系列 当前线程名字是 xhJaver-thread-2 处理了 task9 任务 这里是xhJaver,线程池系列 当前线程名字是 xhJaver-thread-3 处理了 task8 任务 这里是xhJaver,线程池系列 当前线程名字是 xhJaver-thread-4 处理了 task7 任务
我也学会了自定义线程工厂了,可自定义名字到底有用呢,固然是排查问题啊!把线程名字定义为和本身业务有关的名字,到时候报错的时候就方便排查了。
线程工厂能够自定义,那拒绝策略能够自定义吗?固然能够啦 方法以下,首先也要实现一个RejectedExecutionHandler接口,重写rejectedExecution 这个方法
public class DIYRejectedHandler implements RejectedExecutionHandler { @Override public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) { //记录日志等操做 System.out.println("这是xhJaver没法处理的任务 "+r.toString()+" 当前线程名字是 "+Thread.currentThread().getName()); } }
而后在使用时传入这个自定义的拒绝策略
public static void main(String[] args) { //阻塞队列,设置阻塞任务最多为10个 BlockingQueue<Runnable> blockingQueue = new ArrayBlockingQueue<Runnable> (10); //建立线程安全的计数器 AtomicInteger atomicInteger = new AtomicInteger(); //自定义线程工厂 ThreadFactory threadFactory = new DIYThreadFactory(atomicInteger); //自定义拒绝策略 当线程池的最大工做线程跑满以及阻塞队列满了的话,会由拒绝策略处理剩下的任务 DIYRejectedHandler diyRejectedHandler = new DIYRejectedHandler(); //建立线程池 核心线程数为5 最大线程数为10 非核心线程空闲存活时间为60s ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(5, 10, 60L, TimeUnit.SECONDS, blockingQueue, threadFactory, diyRejectedHandler ); for (int i=0;i<30;i++){ //建立10个任务,若是要是建立>20个任务,则20之外的任务会交由拒绝策略处理 Task task = new Task("task" + i); //让咱们自定义的线程池去跑这些任务 threadPoolExecutor.execute(task); } //记得要关闭线程池 threadPoolExecutor.shutdown(); }
输出结果是
这是xhJaver没法处理的任务 Task{taskName='task20'} 当前线程名字是 main 这是xhJaver没法处理的任务 Task{taskName='task21'} 当前线程名字是 main 这是xhJaver没法处理的任务 Task{taskName='task22'} 当前线程名字是 main 这是xhJaver没法处理的任务 Task{taskName='task23'} 当前线程名字是 main 这是xhJaver没法处理的任务 Task{taskName='task24'} 当前线程名字是 main 这是xhJaver没法处理的任务 Task{taskName='task25'} 当前线程名字是 main 这是xhJaver没法处理的任务 Task{taskName='task26'} 当前线程名字是 main 这是xhJaver没法处理的任务 Task{taskName='task27'} 当前线程名字是 main 这是xhJaver没法处理的任务 Task{taskName='task28'} 当前线程名字是 main 这是xhJaver没法处理的任务 Task{taskName='task29'} 当前线程名字是 main 这里是xhJaver,线程池系列 当前线程名字是 xhJaver-thread-5 处理了 task15 任务 这里是xhJaver,线程池系列 当前线程名字是 xhJaver-thread-4 处理了 task4 任务 这里是xhJaver,线程池系列 当前线程名字是 xhJaver-thread-3 处理了 task3 任务 这里是xhJaver,线程池系列 当前线程名字是 xhJaver-thread-2 处理了 task2 任务 这里是xhJaver,线程池系列 当前线程名字是 xhJaver-thread-1 处理了 task1 任务 这里是xhJaver,线程池系列 当前线程名字是 xhJaver-thread-0 处理了 task0 任务 这里是xhJaver,线程池系列 当前线程名字是 xhJaver-thread-9 处理了 task19 任务 这里是xhJaver,线程池系列 当前线程名字是 xhJaver-thread-8 处理了 task18 任务 这里是xhJaver,线程池系列 当前线程名字是 xhJaver-thread-7 处理了 task17 任务 这里是xhJaver,线程池系列 当前线程名字是 xhJaver-thread-6 处理了 task16 任务 这里是xhJaver,线程池系列 当前线程名字是 xhJaver-thread-4 处理了 task6 任务 这里是xhJaver,线程池系列 当前线程名字是 xhJaver-thread-5 处理了 task5 任务 这里是xhJaver,线程池系列 当前线程名字是 xhJaver-thread-3 处理了 task7 任务 这里是xhJaver,线程池系列 当前线程名字是 xhJaver-thread-2 处理了 task8 任务 这里是xhJaver,线程池系列 当前线程名字是 xhJaver-thread-1 处理了 task9 任务 这里是xhJaver,线程池系列 当前线程名字是 xhJaver-thread-0 处理了 task10 任务 这里是xhJaver,线程池系列 当前线程名字是 xhJaver-thread-9 处理了 task11 任务 这里是xhJaver,线程池系列 当前线程名字是 xhJaver-thread-8 处理了 task12 任务 这里是xhJaver,线程池系列 当前线程名字是 xhJaver-thread-7 处理了 task13 任务 这里是xhJaver,线程池系列 当前线程名字是 xhJaver-thread-6 处理了 task14 任务
由于阻塞队列的知识太多了,后续咱们会单独开篇来说这个阻塞队列,先介绍几个经常使用的
1.ArrayBlockingQueue 基于数组的有界队列
2.LinkedBlockingQueue 基于链表的无界队列
3.SynchronousQueue
它内部只有一个元素,插入时若是发现内部有元素未被取走则阻塞,取元素时若队列没有元素则被阻 塞,直到有元素插入进来。
搭配线程池使用以下 ,先建立任务类
public class Task implements Runnable { private String taskName; public Task(String taskName) { this.taskName = taskName; } @Override public String toString() { return "Task{" + "taskName='" + taskName + ''' + '}'; } @Override public void run() { try { //模拟每一个任务的耗时 Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } String name = Thread.currentThread().getName(); System.out.println("这里是xhJaver,线程池系列 当前线程名字是 " + name+" 处理了 "+ taskName+" 任务"); } }
再使用阻塞队列
public static void main(String[] args) { ExecutorService executorService = Executors.newCachedThreadPool(); for (int i=0;i<10;i++){ //建立十个任务 Task task = new Task("task" + i); //去跑任务 executorService.execute(task); } //记得要关闭线程池 executorService.shutdown(); }
其中newCachedThreadPool底层就使用的是SynchronousQueue
public static ExecutorService newCachedThreadPool() { return new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS, new SynchronousQueue<Runnable>()); }
输出结果是
这里是xhJaver,线程池系列 当前线程名字是 pool-1-thread-1 处理了 task0 任务 这里是xhJaver,线程池系列 当前线程名字是 pool-1-thread-2 处理了 task1 任务 这里是xhJaver,线程池系列 当前线程名字是 pool-1-thread-5 处理了 task4 任务 这里是xhJaver,线程池系列 当前线程名字是 pool-1-thread-4 处理了 task3 任务 这里是xhJaver,线程池系列 当前线程名字是 pool-1-thread-3 处理了 task2 任务 这里是xhJaver,线程池系列 当前线程名字是 pool-1-thread-6 处理了 task5 任务 这里是xhJaver,线程池系列 当前线程名字是 pool-1-thread-7 处理了 task6 任务 这里是xhJaver,线程池系列 当前线程名字是 pool-1-thread-10 处理了 task9 任务 这里是xhJaver,线程池系列 当前线程名字是 pool-1-thread-9 处理了 task8 任务 这里是xhJaver,线程池系列 当前线程名字是 pool-1-thread-8 处理了 task7 任务
因而可知,线程池分别建立了十个线程来处理这十个任务,为何呢? 这是由于,我每一个任务的模拟处理时间是1s,当再来的任务发现阻塞队列中有任务还没被取走,就建立非核心线程处理刚来的这个任务,不断的来任务,不断的建立线程,因此用这个阻塞队列再搭配线程池的总线程数等参数设置可能会由于不断的建立线程而致使OOM。
4.PriorityBlockingQueue 优先级队列 进入队列的元素会按照任务的优先级排序。而且必须实现Comparable接口。
参数:priorityTask - 要比较的对象。 返回:负整数、零或正整数, 根据此对象是小于、等于仍是大于指定对象(要比较的对象)。
先建立一个带有优先级的任务
public class PriorityTask implements Runnable , Comparable<PriorityTask>{ private String taskName; // 优先级,根据这个数进行排序 private Integer priority; public PriorityTask(Integer priority,String taskName) { this.priority = priority; this.taskName = taskName; } //这个compareTo方法的返回值若是是-1的话,则排序会认为传过来的任务比此任务的大,降序排列 //这个compareTo方法的返回值若是是1的话,则排序会认为传过来的任务比此任务的小,升序排列 @Override public int compareTo(PriorityTask priorityTask) { //Integer.compare返回 -1表明 传过来的任务的priority 比次任务的priority要小 // Integer.compare 0 传过来的任务的priority 比次任务的priority同样大 //Integer.compare 1 传过来的任务的priority 比次任务的priority要大 return Integer.compare(priorityTask.priority,this.priority); } @Override public void run() { try { //模拟每一个任务的耗时 Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } String name = Thread.currentThread().getName(); System.out.println("这里是xhJaver,线程池系列 当前线程名字是 " + name+" 处理了 "+ taskName+" 任务"); } @Override public String toString() { return "Task{" + "taskName='" + taskName + ''' + '}'; } }
Integer.compare 的 比较大小代码
java public static int compare(int x, int y) { return (x < y) ? -1 : ((x == y) ? 0 : 1); }
测试代码
public static void main(String[] args) { ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(1, 1, 60L, TimeUnit.SECONDS, new PriorityBlockingQueue()); for (int i=0;i<5;i++){ //建立十个任务 PriorityTask priorityTask = new PriorityTask(i,"task" + i); //去跑任务 threadPoolExecutor.execute(priorityTask); } for (int i=100;i>=95;i--){ //建立十个任务 PriorityTask priorityTask = new PriorityTask(i,"task" + i); //去跑任务 threadPoolExecutor.execute(priorityTask); } //记得要关闭线程池 threadPoolExecutor.shutdown(); }
输出结果是
这里是xhJaver,线程池系列 当前线程名字是 pool-1-thread-1 处理了 task0 任务 这里是xhJaver,线程池系列 当前线程名字是 pool-1-thread-1 处理了 task100 任务 这里是xhJaver,线程池系列 当前线程名字是 pool-1-thread-1 处理了 task99 任务 这里是xhJaver,线程池系列 当前线程名字是 pool-1-thread-1 处理了 task98 任务 这里是xhJaver,线程池系列 当前线程名字是 pool-1-thread-1 处理了 task97 任务 这里是xhJaver,线程池系列 当前线程名字是 pool-1-thread-1 处理了 task96 任务 这里是xhJaver,线程池系列 当前线程名字是 pool-1-thread-1 处理了 task95 任务 这里是xhJaver,线程池系列 当前线程名字是 pool-1-thread-1 处理了 task4 任务 这里是xhJaver,线程池系列 当前线程名字是 pool-1-thread-1 处理了 task3 任务 这里是xhJaver,线程池系列 当前线程名字是 pool-1-thread-1 处理了 task2 任务 这里是xhJaver,线程池系列 当前线程名字是 pool-1-thread-1 处理了 task1 任务
由输出结果可见,除了第一个之外,处理任务的顺序会按照优先级大小先处理
他们分别是如下几种
1.newFixedThreadPool
public static ExecutorService newFixedThreadPool(int nThreads) { return new ThreadPoolExecutor(nThreads, nThreads, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>()); }
有此可见,这个FixedThreadPool线程池的核心线程数和最大线程数同样,因此就没有非核心线程数,存活时间这个参数也就是无效的了,它底层用的是LinkedBlockingQueue这个阻塞队列,这个队列是个无界队列,能够点进去源码看它默认的容量是Integer.MAX_VALUE
public LinkedBlockingQueue() { this(Integer.MAX_VALUE); }
因此这会致使一个什么问题呢?就会致使,当核心线程都跑满的时候,再来新任务的话就会不断的添加至这个阻塞队列里面,一直加一直加,可是内存是有限的,因此有可能会出现 OOM(OutOfMemory) 的问题
public static ExecutorService newFixedThreadPool(int nThreads, ThreadFactory threadFactory) { return new ThreadPoolExecutor(nThreads, nThreads, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>(), threadFactory); }
2.newCachedThreadPool
public static ExecutorService newCachedThreadPool() { return new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS, new SynchronousQueue<Runnable>()); }
因而可知,它的核心线程数默认是0,线程池总线程容量是Integer.MAX_VALUE,阻塞队列用的是SynchronousQueue同步队列,非核心线程数的空闲存活时间为60s,这会致使一个什么问题呢?只要来了一个任务,若是没有线程的话就建立一个非核心线程去跑这个任务,若是跑着的过程当中又来了一个任务,就会继续建立线程去跑,以此类推,内存是有限的,不断的建立线程的话也会触发OOM问题
public static ExecutorService newCachedThreadPool(ThreadFactory threadFactory) { return new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS, new SynchronousQueue<Runnable>(), threadFactory); }
3.newSingleThreadExecutor
public static ExecutorService newSingleThreadExecutor() { return new FinalizableDelegatedExecutorService (new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>())); }
咱们能够看出,它的核心线程数是一个,总线程数也是一个。底层用的是LinkedBlockingQueue阻塞队列 当来任务的时候线程池若是没有线程的话,则建立一个也是惟一一个线程来执行任务,剩下的任务都会被塞进无界阻塞队列里面,也是会有可能产生OOM问题。
public static ExecutorService newSingleThreadExecutor(ThreadFactory threadFactory) { return new FinalizableDelegatedExecutorService (new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>(), threadFactory)); }
什么?线程池还能够拓展?!是的,若是我想记录下每一个任务的执行开始状况,结束状况,线程池关闭状况就要拓展啦,ThreadPoolExecutor它内部是提供了几个方法给咱们拓展,其中beforeExecute、afterExecute、terminated,这三个分别对应任务开始,任务结束,线程池关闭的三种状况,因此咱们就要重写他们啦,话很少说,看下代码
public static void main(String[] args) { //阻塞队列,设置阻塞任务最多为10个 BlockingQueue<Runnable> blockingQueue = new ArrayBlockingQueue<Runnable> (10); //建立线程安全的计数器 AtomicInteger atomicInteger = new AtomicInteger(); //自定义线程工厂 ThreadFactory threadFactory = new DIYThreadFactory(atomicInteger); //自定义拒绝策略 当线程池的最大工做线程跑满以及阻塞队列满了的话,会由拒绝策略处理剩下的任务 DIYRejectedHandler diyRejectedHandler = new DIYRejectedHandler(); //建立线程池 核心线程数为5 最大线程数为10 非核心线程空闲存活时间为60s ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(5, 10, 60L, TimeUnit.SECONDS, blockingQueue, threadFactory, diyRejectedHandler ){ @Override protected void beforeExecute(Thread t, Runnable r) { System.out.println("xhJaver 当前线程是"+t.getName()+"开始处理任务:"+r.toString()); } @Override protected void afterExecute(Runnable r, Throwable t) { if(t!=null){ System.out.println("xhJaver 当前线程是"+Thread.currentThread().getName() +"处理任务结束:"+r.toString()+" 错误是 "+ t); } System.out.println("xhJaver 当前线程是"+Thread.currentThread().getName() +"处理任务结束:"+r.toString()+" 没有错误 "); } @Override protected void terminated() { System.out.println("xhJaver 当前线程是"+Thread.currentThread().getName() +"关闭线程池"); } }; for (int i=0;i<21;i++){ //建立10个任务,若是要是建立>20个任务,则20之外的任务会交由拒绝策略处理 Task task = new Task("task" + i); //让咱们自定义的线程池去跑这些任务 threadPoolExecutor.execute(task); } //记得要关闭线程池 threadPoolExecutor.shutdown(); }
输出结果是
这是xhJaver没法处理的任务 Task{taskName='task20'} 当前线程名字是 main xhJaver 当前线程是xhJaver-thread-7开始处理任务:Task{taskName='task17'} xhJaver 当前线程是xhJaver-thread-6开始处理任务:Task{taskName='task16'} xhJaver 当前线程是xhJaver-thread-9开始处理任务:Task{taskName='task19'} xhJaver 当前线程是xhJaver-thread-4开始处理任务:Task{taskName='task4'} xhJaver 当前线程是xhJaver-thread-8开始处理任务:Task{taskName='task18'} xhJaver 当前线程是xhJaver-thread-2开始处理任务:Task{taskName='task2'} xhJaver 当前线程是xhJaver-thread-3开始处理任务:Task{taskName='task3'} xhJaver 当前线程是xhJaver-thread-5开始处理任务:Task{taskName='task15'} xhJaver 当前线程是xhJaver-thread-0开始处理任务:Task{taskName='task0'} xhJaver 当前线程是xhJaver-thread-1开始处理任务:Task{taskName='task1'} 这里是xhJaver,线程池系列 当前线程名字是 xhJaver-thread-4 处理了 task4 任务 xhJaver 当前线程是xhJaver-thread-4处理任务结束:Task{taskName='task4'} 没有错误 xhJaver 当前线程是xhJaver-thread-4开始处理任务:Task{taskName='task5'} 这里是xhJaver,线程池系列 当前线程名字是 xhJaver-thread-9 处理了 task19 任务 xhJaver 当前线程是xhJaver-thread-9处理任务结束:Task{taskName='task19'} 没有错误 这里是xhJaver,线程池系列 当前线程名字是 xhJaver-thread-6 处理了 task16 任务 xhJaver 当前线程是xhJaver-thread-6处理任务结束:Task{taskName='task16'} 没有错误 xhJaver 当前线程是xhJaver-thread-9开始处理任务:Task{taskName='task6'} 这里是xhJaver,线程池系列 当前线程名字是 xhJaver-thread-7 处理了 task17 任务 xhJaver 当前线程是xhJaver-thread-7处理任务结束:Task{taskName='task17'} 没有错误 xhJaver 当前线程是xhJaver-thread-7开始处理任务:Task{taskName='task8'} xhJaver 当前线程是xhJaver-thread-6开始处理任务:Task{taskName='task7'} 这里是xhJaver,线程池系列 当前线程名字是 xhJaver-thread-1 处理了 task1 任务 这里是xhJaver,线程池系列 当前线程名字是 xhJaver-thread-8 处理了 task18 任务 xhJaver 当前线程是xhJaver-thread-8处理任务结束:Task{taskName='task18'} 没有错误 xhJaver 当前线程是xhJaver-thread-8开始处理任务:Task{taskName='task9'} 这里是xhJaver,线程池系列 当前线程名字是 xhJaver-thread-2 处理了 task2 任务 xhJaver 当前线程是xhJaver-thread-2处理任务结束:Task{taskName='task2'} 没有错误 xhJaver 当前线程是xhJaver-thread-2开始处理任务:Task{taskName='task10'} 这里是xhJaver,线程池系列 当前线程名字是 xhJaver-thread-3 处理了 task3 任务 xhJaver 当前线程是xhJaver-thread-3处理任务结束:Task{taskName='task3'} 没有错误 这里是xhJaver,线程池系列 当前线程名字是 xhJaver-thread-5 处理了 task15 任务 xhJaver 当前线程是xhJaver-thread-5处理任务结束:Task{taskName='task15'} 没有错误 xhJaver 当前线程是xhJaver-thread-5开始处理任务:Task{taskName='task12'} xhJaver 当前线程是xhJaver-thread-1处理任务结束:Task{taskName='task1'} 没有错误 xhJaver 当前线程是xhJaver-thread-1开始处理任务:Task{taskName='task13'} 这里是xhJaver,线程池系列 当前线程名字是 xhJaver-thread-0 处理了 task0 任务 xhJaver 当前线程是xhJaver-thread-3开始处理任务:Task{taskName='task11'} xhJaver 当前线程是xhJaver-thread-0处理任务结束:Task{taskName='task0'} 没有错误 xhJaver 当前线程是xhJaver-thread-0开始处理任务:Task{taskName='task14'} 这里是xhJaver,线程池系列 当前线程名字是 xhJaver-thread-4 处理了 task5 任务 xhJaver 当前线程是xhJaver-thread-4处理任务结束:Task{taskName='task5'} 没有错误 这里是xhJaver,线程池系列 当前线程名字是 xhJaver-thread-6 处理了 task7 任务 xhJaver 当前线程是xhJaver-thread-6处理任务结束:Task{taskName='task7'} 没有错误 这里是xhJaver,线程池系列 当前线程名字是 xhJaver-thread-9 处理了 task6 任务 xhJaver 当前线程是xhJaver-thread-9处理任务结束:Task{taskName='task6'} 没有错误 这里是xhJaver,线程池系列 当前线程名字是 xhJaver-thread-7 处理了 task8 任务 xhJaver 当前线程是xhJaver-thread-7处理任务结束:Task{taskName='task8'} 没有错误 这里是xhJaver,线程池系列 当前线程名字是 xhJaver-thread-2 处理了 task10 任务 xhJaver 当前线程是xhJaver-thread-2处理任务结束:Task{taskName='task10'} 没有错误 这里是xhJaver,线程池系列 当前线程名字是 xhJaver-thread-8 处理了 task9 任务 xhJaver 当前线程是xhJaver-thread-8处理任务结束:Task{taskName='task9'} 没有错误 这里是xhJaver,线程池系列 当前线程名字是 xhJaver-thread-5 处理了 task12 任务 xhJaver 当前线程是xhJaver-thread-5处理任务结束:Task{taskName='task12'} 没有错误 这里是xhJaver,线程池系列 当前线程名字是 xhJaver-thread-0 处理了 task14 任务 xhJaver 当前线程是xhJaver-thread-0处理任务结束:Task{taskName='task14'} 没有错误 这里是xhJaver,线程池系列 当前线程名字是 xhJaver-thread-3 处理了 task11 任务 xhJaver 当前线程是xhJaver-thread-3处理任务结束:Task{taskName='task11'} 没有错误 这里是xhJaver,线程池系列 当前线程名字是 xhJaver-thread-1 处理了 task13 任务 xhJaver 当前线程是xhJaver-thread-1处理任务结束:Task{taskName='task13'} 没有错误 xhJaver 当前线程是xhJaver-thread-1关闭线程池
更多精彩请关注公众号xhJaver,京东java工程师和你一块儿成长