线程池特性的实例检验

本文通过代码实例详细检验了线程池的工作原理,包括:当线程池中线程数量小于corePoolSize时如何处理任务,任务如何放入工作队列,何时创建新线程,以及超过最大线程数时如何应用不同的拒绝策略,如AbortPolicy、CallerRunsPolicy、DiscardOldestPolicy和DiscardPolicy,并展示了不同策略下任务的执行情况。

通过代码实现来检验以下特性:

l 如果此时线程池中的数量小于corePoolSize,即使线程池中的线程都处于空闲状态,也要创建新的线程来处理被添加的任务。

l 如果此时线程池中的数量等于 corePoolSize,但是缓冲队列 workQueue未满,那么任务被放入缓冲队列。

l 如果此时线程池中的数量大于corePoolSize,缓冲队列workQueue满,并且线程池中的数量小于maximumPoolSize,建新的线程来处理被添加的任务。

l 如果此时线程池中的数量大于corePoolSize,缓冲队列workQueue满,并且线程池中的数量等于maximumPoolSize,那么通过 handler所指定的策略来处理此任务。也就是:处理任务的优先级为:核心线程corePoolSize、任务队列workQueue、最大线程maximumPoolSize,如果三者都满了,使用handler处理被拒绝的任务。

l 当线程池中的线程数量大于 corePoolSize时,如果某线程空闲时间超过keepAliveTime,线程将被终止。这样,线程池可以动态的调整池中的线程数。

程序设计

  • 设计一个简单的Tread子类,以一定间隔输出信息。
  • 使用线程池执行一系列子类,控制任务的数量以填充线程池,队列。
  • 监视线程池信息。

代码

线程

//ConfigurableThread具体代码请见《简单可定制业务的线程类》

public class TaskOne extends ConfigurableThread{
    private int i = 0;
    private int id = 0;
    public TaskOne(int id){this.id = id;}
    @Override
    public void doRun(){
        System.out.println("线程 : " + this.id + " | 计算:"+ ++i);
        this.successFlag = true;
    }
}

线程池

我们设置核心线程数量为3,最大线程数量为5,队列长度为3,最大空闲时间为3s。拒绝策略依次测试。同时往线程池中填充10个任务,观察输出情况。

        BlockingQueue queue = new LinkedBlockingQueue<Runnable>(3);
        ThreadPoolExecutor pool = new ThreadPoolExecutor(3, 5, 5L,TimeUnit.SECONDS, queue, new ThreadPoolExecutor.AbortPolicy());


        for(int i = 0; i < 10; i  ++){
            try {
                pool.execute(new TaskOne(i).enableExeLimit().setExeLimit(3).setInterval(1000L));
                Thread.sleep(10L);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

        //任务填充完毕后监视线程池的活动线程数量
        while(true){
            try {
                System.out.println("线程状态 : "+pool.getPoolSize());
                Thread.sleep(500L);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }

拒绝策略与结果

AbortPolicy-拒绝新任务

执行结果

线程 : 0 | 计算:1
线程 : 1 | 计算:1
线程 : 2 | 计算:1
线程 : 6 | 计算:1
线程 : 7 | 计算:1
java.util.concurrent.RejectedExecutionException: Task Thread[Thread-8,5,main] rejected from java.util.concurrent.ThreadPoolExecutor@5aaa6d82[Running, pool size = 5, active threads = 5, queued tasks = 3, completed tasks = 0]
    at java.util.concurrent.ThreadPoolExecutor$AbortPolicy.rejectedExecution(Unknown Source)
    at java.util.concurrent.ThreadPoolExecutor.reject(Unknown Source)
    at java.util.concurrent.ThreadPoolExecutor.execute(Unknown Source)
    at app.APP.main(APP.java:21)
java.util.concurrent.RejectedExecutionException: Task Thread[Thread-9,5,main] rejected from java.util.concurrent.ThreadPoolExecutor@5aaa6d82[Running, pool size = 5, active threads = 5, queued tasks = 3, completed tasks = 0]
    at java.util.concurrent.ThreadPoolExecutor$AbortPolicy.rejectedExecution(Unknown Source)
    at java.util.concurrent.ThreadPoolExecutor.reject(Unknown Source)
    at java.util.concurrent.ThreadPoolExecutor.execute(Unknown Source)
    at app.APP.main(APP.java:21)

可已看出线程0,1,2依次占用3个核心线程,3,4,5放入队列。当队列放不下时,6,7放入新开的线程,此时达到最大线程数5。因此8,9任务返回拒绝异常。

CallerRunsPolicy-阻塞并持续等待

执行结果

线程 : 0 | 计算:1
线程 : 1 | 计算:1
线程 : 2 | 计算:1
线程 : 6 | 计算:1
线程 : 7 | 计算:1
线程 : 8 | 计算:1
任务执行成功,线程结束
循环结束,退出
线程 : 3 | 计算:1
任务执行成功,线程结束
循环结束,退出
线程 : 4 | 计算:1
任务执行成功,线程结束
循环结束,退出
线程 : 5 | 计算:1
任务执行成功,线程结束
循环结束,退出

//......
//一系列输出....直到有线程执行结束才开始输出状态检验

线程状态 : 5
线程状态 : 5
线程状态 : 5

//...等待3s后

线程状态 : 5
线程状态 : 5
线程状态 : 4
线程状态 : 4
线程状态 : 3
线程状态 : 3

从上边结果可以看出两个信息:
* 任务0,1,2,6,7首先执行,3,4,5队列等待,此时线程池满。代码一直等待而不往下执行线程状态监视部分。直到有任务结束,8,9也加入线程池后,代码才继续往下执行。
* 当线程数量大于核心数量时,空闲线程等待时间满足最大空闲时间后,多余的线程将被销毁。

DiscardOldestPolicy-忽略最老的任务

执行结果

线程 : 0 | 计算:1
线程 : 1 | 计算:1
线程 : 2 | 计算:1
线程 : 6 | 计算:1
线程 : 7 | 计算:1
线程状态 : 5
线程状态 : 5
任务执行成功,线程结束
循环结束,退出
线程 : 5 | 计算:1
任务执行成功,线程结束
循环结束,退出
线程 : 8 | 计算:1
任务执行成功,线程结束
循环结束,退出
线程 : 9 | 计算:1
任务执行成功,线程结束

可以看到,0,1,2,6,7最先执行,3,4,5在队列中,当8,9加入时,最老的任务3,4被忽略,5被保留。

DiscardPolicy-忽略后来的任务

执行结果

线程 : 0 | 计算:1
线程 : 1 | 计算:1
线程 : 2 | 计算:1
线程 : 6 | 计算:1
线程 : 7 | 计算:1
线程状态 : 5
线程状态 : 5
任务执行成功,线程结束
循环结束,退出
线程 : 3 | 计算:1
任务执行成功,线程结束
循环结束,退出
线程 : 4 | 计算:1
任务执行成功,线程结束
循环结束,退出
线程 : 5 | 计算:1
任务执行成功,线程结束

可以看出0,1,2,6,7最先执行,3,4,5在队列中,当8,9加入时,直接忽略8,9。因此只有前8个任务真正被执行。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值