线程池-自定义线程池

最近在研究Executors线程池,出了常用的4个基本创建线程池的方法,newFixedThreadPool(),newSingleThreadExextor(),newCachedThreadPool(),newScheduledThreadPool()之外,我们完全可以通过自定义的方式实现自己想要的线程池,进而满足我们项目需求。
对于自定义线程池也是基于ThreadPoolExecutor的构造函数来设置自定义的。先对其构造函数有一个基本了解

/**
     *
     * @param corePoolSize   池中所保存的核心线程数
     * @param maximumPoolSize  池中允许的最大线程数
     * @param keepAliveTime   非核心线程空闲等待新任务的最长时间,超过此时间,线程则会被回收
     * @param unit  参数时间单位
     * @param workQueue   任务队列
     */
    public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue) {
        this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
                Executors.defaultThreadFactory(), defaultHandler);
    }

直接通过创建的方式就可以自定义一个我们想要的线程,自定义线程分为两种,种一:有界队列;种二:无界队列,今日我们通过有界队列对自定义线程有一个深入的了解。
何为有界队列?

  • 在使用有界队列时,若有新的任务需要执行,如果线程池实际线程数小于corePoolSize,则优先创建线程,若大于corePoolSize,则会将任务加入队列。若队列已满,则在总线程数不大于maximumPoolSize的前提下,创建新的线程,若线程数大于maximumPoolSize,则执行拒绝策略,或其他自定义方式。

通过创建一个简单的实体类和一个测试方法来实现。
实体类:

public class MyTask  implements Runnable{

    private int taskId;
    private String taskName;

    //构造函数
    public MyTask(int taskId,String taskName){
        this.taskId=taskId;
        this.taskName=taskName;
    }

    @Override
    public void run() {
        System.out.println("run taskId="+this.taskId);
        try {
            //每次调用线程都沉睡5秒
            Thread.sleep(5*1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public String toString(){
        return Integer.toString(this.taskId);
    }
}

测试类:我们通过创建ThreadPoolExecutor来控制线程数,指定想要的队列。

public static void main(String[] args) {

        ThreadPoolExecutor pool = new ThreadPoolExecutor(
                1,    //coreSize
                2,   //MaxSize
                60, //60
                TimeUnit.SECONDS,
                new ArrayBlockingQueue<Runnable>(3)     //指定一种队列(有界队列)
        );

        MyTask mt1 = new MyTask(1, "任务1");
        MyTask mt2 = new MyTask(2, "任务2");
        MyTask mt3 = new MyTask(3, "任务3");
        MyTask mt4 = new MyTask(4, "任务4");
        MyTask mt5 = new MyTask(5, "任务5");
        MyTask mt6 = new MyTask(6, "任务6");

        pool.execute(mt1);
        pool.execute(mt2);
        pool.execute(mt3);
        pool.execute(mt4);
        pool.execute(mt5);
        pool.execute(mt6);
        pool.shutdown();
    }

从ThreadPoolExecutor创建的线程条件我们可以得知,我们创建了一个核心线程数,最大线程数为2,非核心线程等待的时间为60秒。

  • 只执行mt1,则符合核心线程数,所以会直接执行。因为设置的等待时间为60秒,意思就是假设执行mt1用了10秒,假如在剩下的50秒钟无任何线程进入,则该线程池直接被回收。若进入则直接执行下一个线程。
  • 执行mt1,mt2则是核心线程和最大线程,则会在执行完mt1之后,大概5秒之后,执行mt2;
  • ArrayBlockingQueue队列是可以容纳3个值的,所以为mt2,mt3,mt4都可以放入队列中,等待执行。执行4个线程中间的时间间隔则为设置的5秒左右。
  • 而mt5则已经超过了队列的容纳范围,所以重新创建一个新的线程,因为如需放入队列中,所以应该是和mt1同步的执行,无需等待。
  • 而mt6则直接拒绝。因为超过了,最大线程和队列存入个数。最后执行的效果如下:
Exception in thread "main" java.util.concurrent.RejectedExecutionException: Task 6 rejected from java.util.concurrent.ThreadPoolExecutor@165e6c89[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:42)
    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

通过错误数字都可以看到问题的所在。对于在项目中的使用情况,需要根绝具体需求而定。通过学习各种线程,线程池,有一个整体的规划,这样在使用时方能想到,熟能生巧。

posted on 2017-06-26 10:55  huohuoL  阅读(132)  评论(0编辑  收藏  举报

导航