ThreadPoolExecutor 学习 (上篇)

Java有两个线程池类:ThreadPoolExecutor和ScheduledThreadPoolExecutor,继承AbstractExecutorService类,AbstractExecutorService类实现了ExecutorService接口。Java API提供了Executors工厂类来帮助创建各种线程池。

ThreadPoolExecutor 构造方法

ThreadPoolExecutor 的构造方法如下:
public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue workQueue) {
this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
Executors.defaultThreadFactory(), defaultHandler);
}

  1. corePoolSize:指定了线程池中的线程数量。
  2. maximumPoolSize:指定了线程池中的最大线程数量。
  3. keepAliveTime:当前线程池数量超过 corePoolSize 时,多余的空闲线程的存活时间,即多
    次时间内会被销毁。
  4. unit:keepAliveTime 的单位。
  5. workQueue:任务队列,被提交但尚未被执行的任务。
  6. threadFactory:线程工厂,用于创建线程,一般用默认的即可。
  7. handler:拒绝策略,当任务太多来不及处理,如何拒绝任务。

ThreadPoolExecutor工作流程

1、线程池刚创建时,里面没有一个线程。任务队列是作为参数传进来的。不过,就算队列里面
有任务,线程池也不会马上执行它们。
2、当调用 execute() 方法添加一个任务时,线程池会做如下判断:
a、如果正在运行的线程数量小于 corePoolSize,那么马上创建线程运行这个任务;
b、如果正在运行的线程数量大于或等于 corePoolSize,那么将这个任务放入队列;
c、如果这时候队列满了,而且正在运行的线程数量小于 maximumPoolSize,那么还是要
创建非核心线程立刻运行这个任务;
d、如果队列满了,而且正在运行的线程数量大于或等于 maximumPoolSize,那么线程池
会抛出异常 RejectExecutionException。
3、当一个线程完成任务时,它会从队列中取下一个任务来执行。
4、当一个线程无事可做,超过一定的时间(keepAliveTime)时,线程池会判断,如果当前运
行的线程数大于 corePoolSize,那么这个线程就被停掉。所以线程池的所有任务完成后,它
最终会收缩到 corePoolSize 的大小。

现代码实验下:

当池中正在运行的线程数(包括空闲线程)小于corePoolSize时,新建线程执行任务。

public class Exam13_1 {
    public static void main(String[] args) {
        ExecutorService executor = new ThreadPoolExecutor(2, 3, 1, TimeUnit.HOURS,
                new LinkedBlockingQueue<>(1));

        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName());
            }
        };

        //任务1
        executor.submit(runnable);

        //任务2
        executor.submit(runnable);

    }
}

实验结果

从实验结果上可以看出,当执行任务1的线程(thread-1)执行完成之后,任务2并没有去复用thread-1而是新建线程(thread-2)去执行任务。

当池中正在运行的线程数大于等于corePoolSize时,新插入的任务进入workQueue排队(如果workQueue长度允许),等待空闲线程来执行。

public class Exam13_1 {
    public static void main(String[] args) {
        ExecutorService executor = new ThreadPoolExecutor(2, 3, 1, TimeUnit.HOURS,
                new LinkedBlockingQueue<>(1));

        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName());
            }
        };

        //任务1
        executor.submit(runnable);

        //任务2
        executor.submit(runnable);

        //任务3
        executor.submit(runnable);

    }
}

从实验结果上看,任务3会等待任务1执行完之后,有了空闲线程,才会执行。并没有新建线程执行任务3,这时maximumPoolSize=3这个参数不起作用

当队列里的任务数达到上限,并且池中正在运行的线程数小于maximumPoolSize,对于新加入的任务,新建线程。

public class Exam13_1 {
    public static void main(String[] args) {
        ExecutorService executor = new ThreadPoolExecutor(2, 3, 1, TimeUnit.HOURS,
                new LinkedBlockingQueue<>(1));

        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName());
            }
        };

        //任务1
        executor.submit(runnable);

        //任务2
        executor.submit(runnable);

        //任务3
        executor.submit(runnable);

        //任务4
        executor.submit(runnable);

    }
}


从实验结果上看,当任务4进入队列时发现队列的长度已经到了上限,所以无法进入队列排队,而此时正在运行的线程数(2)小于maximumPoolSize所以新建线程执行该任务。

当队列里的任务数达到上限,并且池中正在运行的线程数等于maximumPoolSize,对于新加入的任务,执行拒绝策略(线程池默认的拒绝策略是抛异常)。

public class Exam13_1 {
    public static void main(String[] args) {
        ExecutorService executor = new ThreadPoolExecutor(2, 3, 1, TimeUnit.HOURS,
                new LinkedBlockingQueue<>(1));

        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName());
            }
        };

        //任务1
        executor.submit(runnable);

        //任务2
        executor.submit(runnable);

        //任务3
        executor.submit(runnable);

        //任务4
        executor.submit(runnable);

        //任务5
        executor.submit(runnable);


    }
}

实验结果分析:当任务5加入时,队列达到上限,池内运行的线程数达到最大,故执行默认的拒绝策略,抛异常。

猜你喜欢

转载自www.cnblogs.com/aixw/p/10535434.html
今日推荐