本人邮箱: <kco1989@qq.com>
欢迎转载,转载请注明网址 http://blog.csdn.net/tianshi_kco
github: https://github.com/kco1989/kco
代码已经所有托管github有须要的同窗自行下载java
在以前的例子,咱们要建立多个线程处理一批任务的时候.我是经过建立线程数组,或者使用线程集合来管理的.可是这样作不太好,由于这些线程没有被重复利用.因此这里要引入线程池,今天咱们就讲线程池执行器ThreadPoolExecutor
.git
首先咱们来看一下它的构造器:ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler)
这个是ThreadPoolExecutor
完整的构造器,其余的构造器其实也是在内部调用这个.github
corePoolSize
核心线程数,线程池保留线程的数量,即便这些线程是空闲.除非设置了allowCoreThreadTimeOut
数组
maximumPoolSize
线程池最大容许的线程数.微信
keepAliveTime
当当前的线程数大于核心线程数,那么这些多余的空闲的线程在被终止以前能等待新任务的时间.app
unit
keepAliveTime
时间的单位ide
workQueue
这个是用来保留将要执行的工做队列.spa
threadFactory
用于建立新线程的工厂.net
handler
若是工做队列(workQueue
)满了,那么这个handler是将会被执行.线程
ThreadPoolExecutor
还有几个可不带threadFactory
或handler
惨的构造器,说明java提供了一些默认的配置,让咱们看一下.
若是构造不带threadFactory
,那么默认使用java.util.concurrent.Executors.DefaultThreadFactory
建立出一个新的工厂对象.经过阅读源代码,主要是在建立新的线程的时候修改了线程名为pool-全局线程池递增数编号-thread-当前线程池线程递增编号
,让线程改成非守护线程,并设置线程的优先级为NORM_PRIORITY
.
ok,再看一下handler
有什么默认值.
java.util.concurrent.ThreadPoolExecutor.AbortPolicy
这个是默认使用的拒绝策略,若是有要执行的任务队列已满,且还有任务提交,则直接抛出异常信息
java.util.concurrent.ThreadPoolExecutor.DiscardPolicy
这个是忽略策略,若是有要执行的任务队列已满,且还有任务提交,则直接忽略掉这个任务,即不抛出异常也不作任何处理.
java.util.concurrent.ThreadPoolExecutor.DiscardOldestPolicy
忽略最先提交的任务.若是有要执行的任务队列已满,此时若还有任务提交且线程池尚未中止,则把队列中最先提交的任务抛弃掉,而后把当前任务加入队列中.
java.util.concurrent.ThreadPoolExecutor.CallerRunsPolicy
这个是来着不拒策略.若是有要执行的任务队列已满,此时若还有任务提交且线程池尚未中止,则直接运行任务的run
方法.
AbortPolicy
public class Demo1 { public static void main(String[] args) { BlockingQueue<Runnable> queue = new ArrayBlockingQueue<Runnable>(10); RejectedExecutionHandler handler = new ThreadPoolExecutor.AbortPolicy(); ThreadPoolExecutor pool = new ThreadPoolExecutor(3, 3, 0, TimeUnit.SECONDS, queue, handler); for (int i = 0; i < 20; i ++){ final int temp = i; pool.execute(() -> { System.out.println("客户" + temp + "来了......."); try { Thread.sleep(10); } catch (InterruptedException e) { e.printStackTrace(); } }); } pool.shutdown(); } }
Exception in thread "main" java.util.concurrent.RejectedExecutionException: Task com.kco.test17.demo1.Demo1$$Lambda$1/15497079@ca494b rejected from java.util.concurrent.ThreadPoolExecutor@1a4f24f[Running, pool size = 5, active threads = 5, queued tasks = 10, completed tasks = 0]
at java.util.concurrent.ThreadPoolExecutor$AbortPolicy.rejectedExecution(ThreadPoolExecutor.java:2047)
at java.util.concurrent.ThreadPoolExecutor.reject(ThreadPoolExecutor.java:823)
at java.util.concurrent.ThreadPoolExecutor.execute(ThreadPoolExecutor.java:1369)
at com.kco.test17.demo1.Demo1.main(Demo1.java:16)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:497)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:140)
pool-1-thread-1客户0来了.......
pool-1-thread-2客户1来了.......
pool-1-thread-3客户2来了.......
pool-1-thread-5客户14来了.......
pool-1-thread-4客户13来了.......
pool-1-thread-2客户3来了.......
pool-1-thread-1客户4来了.......
pool-1-thread-5客户5来了.......
pool-1-thread-3客户6来了.......
pool-1-thread-4客户7来了.......
pool-1-thread-2客户9来了.......
pool-1-thread-1客户8来了.......
pool-1-thread-3客户10来了.......
pool-1-thread-5客户11来了.......
pool-1-thread-4客户12来了.......
从结果看出来,能够看出线程是重复被使用的,并且当执行的任务超过工做队列的容量时,线程确实抛出了异常.
DiscardPolicy
将RejectedExecutionHandler handler = new ThreadPoolExecutor.AbortPolicy();
改成 RejectedExecutionHandler handler = new ThreadPoolExecutor.DiscardPolicy();
运行结果以下:
pool-1-thread-1客户0来了.......
pool-1-thread-3客户2来了.......
pool-1-thread-4客户13来了.......
pool-1-thread-5客户14来了.......
pool-1-thread-3客户3来了.......
pool-1-thread-4客户4来了.......
pool-1-thread-1客户5来了.......
pool-1-thread-5客户6来了.......
pool-1-thread-2客户1来了.......
pool-1-thread-3客户7来了.......
pool-1-thread-4客户8来了.......
pool-1-thread-5客户9来了.......
pool-1-thread-1客户10来了.......
pool-1-thread-2客户11来了.......
pool-1-thread-4客户12来了.......
如今线程池正确退出了,并且也不抛出异常了,可是超过工做队列容量的任务所有被忽略了.
DiscardOldestPolicy
RejectedExecutionHandler
改成RejectedExecutionHandler handler = new ThreadPoolExecutor.DiscardOldestPolicy();
pool-1-thread-1客户0来了.......
pool-1-thread-2客户1来了.......
pool-1-thread-3客户2来了.......
pool-1-thread-5客户14来了.......
pool-1-thread-4客户13来了.......
pool-1-thread-4客户8来了.......
pool-1-thread-1客户11来了.......
pool-1-thread-5客户10来了.......
pool-1-thread-3客户9来了.......
pool-1-thread-2客户12来了.......
pool-1-thread-1客户15来了.......
pool-1-thread-4客户16来了.......
pool-1-thread-5客户17来了.......
pool-1-thread-2客户19来了.......
pool-1-thread-3客户18来了.......
从以上结果,咱们能够看出除了客户0到客户2恰好是3个核心线程被执行后,客户3到客户7直接被忽略掉了.
CallerRunsPolicy
一样讲拒绝策略改成RejectedExecutionHandler handler = new ThreadPoolExecutor.CallerRunsPolicy();
运行程序,结果以下:
pool-1-thread-1客户0来了.......
pool-1-thread-2客户1来了.......
pool-1-thread-3客户2来了.......
pool-1-thread-4客户13来了.......
main客户15来了.......
pool-1-thread-5客户14来了.......
pool-1-thread-2客户3来了.......
pool-1-thread-1客户4来了.......
main客户18来了.......
pool-1-thread-3客户5来了.......
pool-1-thread-4客户7来了.......
pool-1-thread-5客户6来了.......
pool-1-thread-5客户8来了.......
pool-1-thread-1客户9来了.......
pool-1-thread-4客户10来了.......
pool-1-thread-3客户12来了.......
pool-1-thread-2客户11来了.......
pool-1-thread-1客户16来了.......
pool-1-thread-5客户19来了.......
pool-1-thread-3客户17来了.......
结果,咱们能够发现全部的任务都被执行,并且居然还有两个是在主线程执行的.如今明白我以前说的则直接运行任务的run
方法的意思了吧,没错是直接调用run
方法,而不是开启线程去执行任务.
如今咱们本身写一个拒绝策略,要求全部的任务都必须被线程池执行,并且都要在线程池中执行.
public class Demo5 { public static void main(String[] args) { BlockingQueue<Runnable> queue = new ArrayBlockingQueue<Runnable>(10); RejectedExecutionHandler handler = new RejectedExecutionHandler() { @Override public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) { if (!executor.isShutdown()){ try { executor.getQueue().put(r); } catch (InterruptedException e) { e.printStackTrace(); } } } }; ThreadPoolExecutor pool = new ThreadPoolExecutor(3, 5, 0, TimeUnit.SECONDS, queue, handler); for (int i = 0; i < 20; i ++){ final int temp = i; pool.execute(() -> { String name = Thread.currentThread().getName(); System.out.println(name + "客户" + temp + "来了......."); try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } }); } pool.shutdown(); } }
运行结果:
pool-1-thread-1客户0来了.......
pool-1-thread-3客户2来了.......
pool-1-thread-5客户14来了.......
pool-1-thread-4客户13来了.......
pool-1-thread-2客户1来了.......
pool-1-thread-1客户3来了.......
pool-1-thread-3客户4来了.......
pool-1-thread-5客户5来了.......
pool-1-thread-2客户6来了.......
pool-1-thread-4客户7来了.......
pool-1-thread-1客户8来了.......
pool-1-thread-3客户9来了.......
pool-1-thread-5客户10来了.......
pool-1-thread-4客户11来了.......
pool-1-thread-2客户12来了.......
pool-1-thread-1客户15来了.......
pool-1-thread-3客户16来了.......
pool-1-thread-5客户17来了.......
pool-1-thread-4客户19来了.......
pool-1-thread-2客户18来了.......
ok.全部任务都被线程池执行了.并且咱们自定义的拒绝策略也很简单,就是让工做队列调用put
让其一直等待,直到有可用的容量存听任务.
若是以为个人文章写的还过得去的话,有钱就捧个钱场,没钱给我捧我的场(帮我点赞或推荐一下)