线程池-自定义线程池

对于上篇文章而言,我们了解了有界序列的使用方式。对于剩余的mt6,拒绝,单纯的抛出异常也并非是一个好的办法。对于拒绝这点,其实JDK提供了好几种拒绝策略

  • AbortPolicy:直接抛出异常组织系统正常工作;
  • CallerRunsPolicy:只要线程池未关闭,该策略直接在调用者线程中,运行当前被丢弃的任务;
  • DiscardOldestPolicy:丢弃最老的一个请求,尝试再次提交当前任务;
  • DiscardPolicy:丢地无法处理的任务,不给予任何处理;
    其实这点我们直接在ThreadPoolExecutor创建的时候直接加入就行,它也是属于ThreadPoolExecutor的方法。具体看如下 构造函数
ThreadPoolExecutor pool = new ThreadPoolExecutor(
                1,    //coreSize
                2,   //MaxSize
                60, //60
                TimeUnit.SECONDS,
                new ArrayBlockingQueue<Runnable>(3)     //指定一种队列(有界队列)
                //丢弃最早的任务,尝试再次提交当前任务
                //,new ThreadPoolExecutor.DiscardOldestPolicy()
                //丢弃无法处理的任务,不给予任何处理
                //,new ThreadPoolExecutor.DiscardPolicy()
                //默认情况,直接抛出异常组织系统正常工作
                //, new ThreadPoolExecutor.AbortPolicy()
                //只要线程池未关闭,该策略直接在调用者线程中,运行当前被丢弃的任务
                , new ThreadPoolExecutor.CallerRunsPolicy()
        );

拿上篇文章的demo举例来实践说明一下:
1、new ThreadPoolExecutor.DiscardOldestPolicy()

  • 看结果,发现mt2没执行?这是为什么呢?因为上篇博客我们也分析过,mt2,3,4是放在队列中的,mt1,5已经创建线程执行了,DiscardOldestPolicy要求是丢弃最早的任务,尝试再次提交的当前任务,根据队列先进先出的要求,所以mt2算是最老的成员了。
run taskId=1
run taskId=5
run taskId=3
run taskId=4
run taskId=6

2、new ThreadPoolExecutor.DiscardPolicy()

  • 既然没有你的容纳之地,那我还是直接把你抛弃的好,眼不见心不烦的境界。
run taskId=1
run taskId=5
run taskId=2
run taskId=3
run taskId=4

3、new ThreadPoolExecutor.AbortPolicy()

  • 默认的一种情况,其实就是直接抛出异常,不进行任何处理
Exception in thread "main" java.util.concurrent.RejectedExecutionException: Task 6 rejected from java.util.concurrent.ThreadPoolExecutor@73abdb5e[Running, pool size = 2, active threads = 2, queued tasks = 3, 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 Thread.Executors.UseThreadPoolExecutor1.main(UseThreadPoolExecutor1.java:51)
    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:147)
run taskId=1
run taskId=5
run taskId=2
run taskId=3
run taskId=4

4、new ThreadPoolExecutor.CallerRunsPolicy()

  • 之前曾经说过,对于有界队列而言,有一个非核心线程等待的执行时间,假如在执行完mt4最后一个可执行线程后,该线程池还未关闭,那么就而已留情面的把多余的线程6执行成功。
run taskId=6
run taskId=5
run taskId=1
run taskId=2
run taskId=3
run taskId=4

除了JDK提供的4中拒绝策略之外,我们也可以通过实现RejectedExecutionHandler接口来完成想要的需求,来告诉我们具体被拒绝的任务,通过创建一个类实现接口。

public class MyProject implements RejectedExecutionHandler {

    public MyProject(){

    }

    @Override
    public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
        System.out.println("当前被拒绝任务为:"+r.toString());
    }
}

最后执行的结果为:

当前被拒绝任务为:6
run taskId=1
run taskId=5
run taskId=2
run taskId=3
run taskId=4

其实点开第一步实现,就可以发现JDK提供的拒绝策略也是通过实现RejectedExecutionHandler接口实现了,只是多了自己的一步封装而已。关键代码如下:

public static class CallerRunsPolicy implements RejectedExecutionHandler {
        /**
         * Creates a {@code CallerRunsPolicy}.
         */
        public CallerRunsPolicy() { }

 public static class AbortPolicy implements RejectedExecutionHandler {
        /**
         * Creates an {@code AbortPolicy}.
         */
        public AbortPolicy() { }

public static class DiscardPolicy implements RejectedExecutionHandler {
        /**
         * Creates a {@code DiscardPolicy}.
         */
        public DiscardPolicy() { }

public static class DiscardOldestPolicy implements RejectedExecutionHandler {
        /**
         * Creates a {@code DiscardOldestPolicy} for the given executor.
         */
        public DiscardOldestPolicy() { }

通过简单的源码可以有一个整体的了解。有有界队列,对应的肯定就是无界队列了。
何为无界队列?

  • LinkedBlockingQueue。与有界队列相比,除非系统资源耗尽,否则无界的任务队列不存在任务入队失败的情况。当有新任务到来,系统的线程数小于corePoolSize时,则新建线程执行任务。当达到corePoolSize后,就不会继续增加。若后续仍有新的任务加入,而没有空闲的线程资源,则任务直接进入队列等待。若任务创建和处理的速度差异很大,无界队列会保持快速增长,直到耗尽系统内存。
  • 换句话理解就是,虽然和有界队列也有核心线程,最大线程,但是在无界的环境下,核心线程占据了主要位置,也就是主导者,管你最大线程是多少,也起不到什么实质性作用。

到底该如何使用,了解之后,看实际需求而定。

posted on 2017-06-27 12:09  huohuoL  阅读(129)  评论(0编辑  收藏  举报

导航