jdk-ThreadPoolExecutor(二)---内部参数和拒绝策略
来源:互联网 发布:复杂网络可视化软件 编辑:程序博客网 时间:2024/06/11 15:21
承继上一篇,上一篇主要分析了下ThreadPoolExecutor中的大概执行逻辑,这一篇主要分析一下内部参数的写一写测试程序。
首先来看里面的最终的默认构造方法,分析其参数,以及其流程
//Executors中的四个构造方法最终调用的是下面一个初始化方法 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.corePoolSize = corePoolSize; this.maximumPoolSize = maximumPoolSize; this.workQueue = workQueue; this.keepAliveTime = unit.toNanos(keepAliveTime); this.threadFactory = threadFactory; this.handler = handler; } //1. corePoolSize 核心线程数,所谓核心线程数,就是会一直存活的线程数,即使期间没有需要执行的任务 // 因此,当线程数小于核心线程数时,即使有线程空闲,线程池也会优先创建新线程处理任务,并不是交由现有 // 的线程处理,allowCoreThreadTimeout(true),默认为false,可以设置核心线程超时关闭 //2. maximumPoolSize,当线程数>=核心线程数时,根据上一篇的分析, //2.1如果此时任务队列没有满,此时会加入到任务队列中,等待任务调度执行, //2.2如果此时任务队列已满,此时会判断线程数与maximumPoolSize的大小 // 2.2.1如果此时线程数没有达到maximumPoolSize,那么就会创建新的线程执行任务 // 2.2.2如果此时线程数等于maximumPoolSize,那么就标志着超出线程池的处理范围,线程池会拒绝掉,具体 // 拒绝策略下面再分析 //3. keepAliveTime,当线程空闲时间达到keepAliveTime时,改线程会退出,直至线程数目为corePoolSize, // 如果allowCoreThreadTimeout设置为true的话,则所以线程均会退出直至线程数量为0. //可总结下线程池的任务执行策略 //1.当线程数小于核心线程数时,创建线程 //2.当线程数等于核心线程数时,且此时任务队列未满,将任务放入任务队列 //3.当线程数大于等于核心线程数,且任务队列已满 // 3.1若线程数小于最大线程数,创建线程 // 3.2若线程数等于最大线程数,拒绝任务
测试AbortPolicy
//测试线程池拒绝策略public class TestExceptionThread { private static int totalNum = 2; //ThreadPoolExecutor 提供了四种拒绝策略 //1.AbortPolicy,顾名思义,直接拒绝掉本次线程,抛出RejectedExecutionException //测试该种拒绝策略 public static void main(String[] args){ //构建出一个只有3个线程池大小的service ExecutorService service = Executors.newFixedThreadPool(totalNum); for(int i = 0; i < 5; i++){ final int j = i; System.out.println("线程"+j+"创建"); Runnable runnable = new Runnable() { @Override public void run() { try{ System.out.println("线程"+j+"执行中"); Thread.sleep(50000); }catch (Exception e){ e.printStackTrace(); } } }; service.submit(runnable); } }}结果如下,并没有抛出异常?奇怪了。。。怎么回事,难不成线程一直在加入,没有执行到抛出异常的范围.
线程0创建线程1创建线程0执行中线程2创建线程3创建线程4创建线程1执行中问题其实出在初始化步骤,可以看见初始化时使用了LinkedBlockingQueue的默认大小,这样的话,队列大小为Integer.MAX_VALUE,这种情况下,最大线程数就失去作用了,根据上述步骤,此时核心线程数虽然已满,但是队列确很大,因此全部加入了队列任务中去了,最终会被任务调度执行,可见,队列的大小设置也是有讲究的。
public static ExecutorService newFixedThreadPool(int nThreads) { return new ThreadPoolExecutor(nThreads, nThreads, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>()); }再次测试,这次设置队列任务大小为2,核心线程数为2,最大线程数为3.
//测试线程池拒绝策略public class TestExceptionThread { private static int totalNum = 2; //ThreadPoolExecutor 提供了四种拒绝策略 //1.AbortPolicy,顾名思义,直接拒绝掉本次线程,抛出RejectedExecutionException //测试该种拒绝策略 public static void main(String[] args) throws Exception{ //构建出一个只有3个线程池大小的service LinkedBlockingQueue queue = new LinkedBlockingQueue(2); ExecutorService service = new ThreadPoolExecutor(totalNum, totalNum+1, 0, TimeUnit.MILLISECONDS,queue); for(int i = 0; i < 10; i++){ final int j = i; Thread.sleep(2000); System.out.println("线程"+j+"创建"); Runnable runnable = new Runnable() { @Override public void run() { try{ System.out.println("线程"+j+"执行中"); Thread.sleep(50000); }catch (Exception e){ e.printStackTrace(); } } }; service.submit(runnable); } }}
测试结果如下:来看看和预期对不对.
核心线程数大小为2,最大数为3,队列任务是2.
1.线程0创建时,线程池中没有线程,执行时,线程池中运行线程数目为 1。
2.线程1创建时,核心线程为线程0,只有一个,没有到达核心线程池大小2,因此直接加入执行.此时运行线程数目为 2
3.线程2创建时,核心线程数为线程0,线程1.到达核心线程数2,因此加入到任务队列中去,任务队列中为1。
4.线程3创建时,加入到任务队列中去,因此任务队列为2,核心数还是2。
5.线程4创建时,任务队列已满了。但是此时运行的线程数只有线程0和线程1,小于最大线程数3,因此线程4被创建出并且执行了。(从结果图中可以看出)。
6.线程5创建时,运行线程数是3,并且队列已满,并且等于最大线程数了,所以直接抛出异常,因为此时线程池已经不能处理了.
7.后续的线程此时已经没办法进入了,因为线程5抛出异常了。
线程0创建线程0执行中线程1创建线程1执行中线程2创建线程3创建线程4创建线程4执行中线程5创建Exception in thread "main" java.util.concurrent.RejectedExecutionException: Task java.util.concurrent.FutureTask@4b33650d rejected from java.util.concurrent.ThreadPoolExecutor@43095c6c[Running, pool size = 3, active threads = 3, queued tasks = 2, completed tasks = 0]at java.util.concurrent.ThreadPoolExecutor$AbortPolicy.rejectedExecution(ThreadPoolExecutor.java:2048)at java.util.concurrent.ThreadPoolExecutor.reject(ThreadPoolExecutor.java:821)at java.util.concurrent.ThreadPoolExecutor.execute(ThreadPoolExecutor.java:1372)at java.util.concurrent.AbstractExecutorService.submit(AbstractExecutorService.java:110)at concurrenttest.TestExceptionThread.main(TestExceptionThread.java:40)at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)at java.lang.reflect.Method.invoke(Method.java:601)at com.intellij.rt.execution.application.AppMain.main(AppMain.java:120)
测试CallerRunsPolicy如下:
public class TestExceptionThread { private static int totalNum = 2; public static void main(String[] args) throws Exception{ //构建出一个只有3个线程池大小的service LinkedBlockingQueue queue = new LinkedBlockingQueue(2); ExecutorService service = new ThreadPoolExecutor(totalNum, totalNum+1, 0, TimeUnit.MILLISECONDS,queue,Executors.defaultThreadFactory(),new ThreadPoolExecutor.CallerRunsPolicy()); for(int i = 0; i < 10; i++){ final int j = i; Thread.sleep(2000); System.out.println("线程"+j+"创建"); Runnable runnable = new Runnable() { @Override public void run() { try{ System.out.println(Thread.currentThread().getName()+"线程"+j+"执行中"); Thread.sleep(500000); }catch (Exception e){ e.printStackTrace(); } } }; Thread.sleep(2000); service.submit(runnable); } System.out.println("主线程输出"); }}可以看见,此时线程5在执行失败后,并没有抛出异常,而是由调用线程继续执行,也即是这边的主线程,但是此时主线程后续的输出并没出来,说明这种方式会阻塞主线程。也算是个缺点吧。在这种情况下,感觉并不是很好.
线程0创建pool-1-thread-1线程0执行中线程1创建pool-1-thread-2线程1执行中线程2创建线程3创建线程4创建pool-1-thread-3线程4执行中线程5创建main线程5执行中
测试DiscardPolicy,其实看下源码就会发现这种处理很直接啊,什么方法都没有,这就意味着直接抛弃掉了当前线程的创建,继续执行之后的逻辑。
public class TestExceptionThread { private static int totalNum = 2; public static void main(String[] args) throws Exception{ //构建出一个只有3个线程池大小的service LinkedBlockingQueue queue = new LinkedBlockingQueue(2); ExecutorService service = new ThreadPoolExecutor(totalNum, totalNum+1, 0, TimeUnit.MILLISECONDS,queue,Executors.defaultThreadFactory(),new ThreadPoolExecutor.DiscardPolicy()); for(int i = 0; i < 10; i++){ final int j = i; Thread.sleep(2000); System.out.println("线程"+j+"创建"); Runnable runnable = new Runnable() { @Override public void run() { try{ System.out.println(Thread.currentThread().getName()+"线程"+j+"执行中"); Thread.sleep(500000); }catch (Exception e){ e.printStackTrace(); } } }; Thread.sleep(2000); service.submit(runnable); } System.out.println("主线程输出"); }}
从结果可以看出,线程5,开始就开始抛弃了,最终是回到主线程中输出日志,那么其实如果在线程6-线程9的新建过程中,线程池可以加入了,那么还是可以直接加入的。
线程0创建pool-1-thread-1线程0执行中线程1创建pool-1-thread-2线程1执行中线程2创建线程3创建线程4创建pool-1-thread-3线程4执行中线程5创建线程6创建线程7创建线程8创建线程9创建主线程输出
public class TestExceptionThread { private static int totalNum = 2; public static void main(String[] args) throws Exception{ //构建出一个只有3个线程池大小的service LinkedBlockingQueue queue = new LinkedBlockingQueue(2); ThreadPoolExecutor service = new ThreadPoolExecutor(totalNum, totalNum+1, 0, TimeUnit.MILLISECONDS,queue,Executors.defaultThreadFactory(),new ThreadPoolExecutor.DiscardOldestPolicy()); for(int i = 0; i < 20; i++){ final int j = i; System.out.println("线程" + j + "创建"); service.execute(new InnerThread("Thread "+j)); Iterator iterator = service.getQueue().iterator(); while (iterator.hasNext()){ InnerThread thread = (InnerThread) iterator.next(); System.out.println("队列线程有: "+thread.getName()); } } System.out.println("主线程输出"); }}class InnerThread implements Runnable{ private String name; public InnerThread(String name){ this.name = name; } public String getName() { return name; } public void setName(String name) { this.name = name; } @Override public void run() { try{ System.out.println("线程" + name + "执行中"); }catch (Exception e){ e.printStackTrace(); } }}可以看见大概在线程10到线程19的时候,会出现一直剔除添加的效果。
线程0创建线程1创建线程Thread 0执行中线程2创建队列线程有: Thread 2线程3创建队列线程有: Thread 2队列线程有: Thread 3线程4创建线程Thread 2执行中线程Thread 3执行中线程5创建队列线程有: Thread 5线程6创建队列线程有: Thread 5队列线程有: Thread 6线程7创建线程Thread 4执行中线程Thread 5执行中线程Thread 6执行中线程8创建队列线程有: Thread 8线程9创建队列线程有: Thread 8队列线程有: Thread 9线程10创建队列线程有: Thread 8队列线程有: Thread 9线程11创建队列线程有: Thread 9队列线程有: Thread 11线程12创建队列线程有: Thread 11队列线程有: Thread 12线程13创建队列线程有: Thread 12队列线程有: Thread 13线程14创建队列线程有: Thread 13队列线程有: Thread 14线程15创建队列线程有: Thread 14队列线程有: Thread 15线程16创建队列线程有: Thread 15队列线程有: Thread 16线程17创建队列线程有: Thread 16队列线程有: Thread 17线程18创建队列线程有: Thread 17队列线程有: Thread 18线程19创建队列线程有: Thread 18队列线程有: Thread 19主线程输出线程Thread 10执行中线程Thread 18执行中线程Thread 19执行中线程Thread 1执行中线程Thread 7执行中
public class TestExceptionThread { private static int totalNum = 2; public static void main(String[] args) throws Exception{ LinkedBlockingQueue queue = new LinkedBlockingQueue(2); ThreadPoolExecutor service = new ThreadPoolExecutor(totalNum, totalNum+1, 0, TimeUnit.MILLISECONDS,queue,new MyReject()); for(int i = 0; i < 10; i++){ final int j = i; Thread.sleep(2000); System.out.println("线程"+j+"创建"); Runnable runnable = new Runnable() { @Override public void run() { try{ System.out.println("线程"+j+"执行中"); Thread.sleep(50000); }catch (Exception e){ e.printStackTrace(); } } }; Thread.sleep(2000); service.execute(runnable); } } static class MyReject implements RejectedExecutionHandler{ @Override public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) { System.out.println("你被拒绝了"); } }}可以看出这种方式其实比较好,可以由自己决定后续执行逻辑。
线程0创建线程0执行中线程1创建线程1执行中线程2创建线程3创建线程4创建线程4执行中线程5创建你被拒绝了线程6创建你被拒绝了线程7创建你被拒绝了
本文总结了一下内部一写具体参数的含义,以及线程池的执行策略和拒绝策略。下一篇继续,去看看内部一写方法吧,感觉线程池需要理解的东西比较多,博客还是细分一下,将来自己回头来看时,能瞧的清楚一点。
阅读全文
0 0
- jdk-ThreadPoolExecutor(二)---内部参数和拒绝策略
- ThreadPoolExecutor使用和思考(中)-keepAliveTime及拒绝策略
- ThreadPoolExecutor使用和思考(中)-keepAliveTime及拒绝策略
- ThreadPoolExecutor使用和思考(中)-keepAliveTime及拒绝策略
- ThreadPoolExecutor使用和思考(中)-keepAliveTime及拒绝策略
- ThreadPoolExecutor使用和思考(中)-keepAliveTime及拒绝策略
- ThreadPoolExecutor使用和思考(中)-keepAliveTime及拒绝策略
- jdk-ThreadPoolExecutor(三)---内部Worker和执行方法
- java多线程-ThreadPoolExecutor的拒绝策略RejectedExecutionHandler
- Android线程池(二)——ThreadPoolExecutor及其拒绝策略RejectedExecutionHandler使用示例
- JDK中的线程池 :工作队列和拒绝策略 上
- ThreadPoolExecutor里面4种拒绝策略(详细)
- Java 线程池 ThreadPoolExecutor.(包含拒绝策略CallerRunsPolicy,AbortPolicy,DiscardPolicy,DiscardOldestPolicy )
- Java 线程池 ThreadPoolExecutor.(包含拒绝策略CallerRunsPolicy,AbortPolicy,DiscardPolicy,DiscardOldestPolicy )
- 线程池的生命周期和拒绝策略
- 二、ThreadPoolExecutor
- ThreadPoolExecutor内部机制
- java线程池参数说明及队列拒绝策略
- Java之正则表达式
- WAAS性能评估毕设及代码-读书札记
- ios避免button多次连续点击跳转到多个页面
- shell(3)--sed
- SQL触发器实例讲解
- jdk-ThreadPoolExecutor(二)---内部参数和拒绝策略
- Android 用surfaceview模拟帧动画的效果,解决帧动画的OOM问题
- 用Rational Rose画顺序图时没有标识序号
- ssh 暴力破解防护
- python报错——pip升级后报错
- 金山词霸 问题
- 取文件后缀名
- FFmpeg函数简单分析:avformat_close_input()
- knockoutjs的MVVM机制