java 创建线程池

参考了 Matrix海 子的博客 Java并发编程:线程池的使用

ThreadPoolExecutor的构造函数

 public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue,
                              ThreadFactory threadFactory,
                              RejectedExecutionHandler handler)
  1. corePoolSize:核心池的大小
  2. maximumPoolSize:线程池最大线程数
  3. keepAliveTime:表示线程没有任务执行时最多保持多久时间会终止
  4. unit:参数keepAliveTime的时间单位
  5. workQueue:任务缓存队列及排队策略:
  6. threadFactory:线程工厂,用于创建线程,一般用默认即可;
  7. handler:任务拒绝策略: 表示当拒绝处理任务时的策略。

任务缓存队列及排队策略

一个阻塞队列,阻塞队列有以下几种

  1. ArrayBlockingQueue;
    有界任务队列,若有新的任务需要执行时,线程池会创建新的线程,直到创建的线程数量达到corePoolSize时,则会将新的任务加入到等待队列中。若等待队列已满,即超过ArrayBlockingQueue初始化的容量,则继续创建线程,直到线程数量达到maximumPoolSize设置的最大线程数量,若大于maximumPoolSize,则执行拒绝策略。
  2. LinkedBlockingQueue;
    基于链表的先进先出队列,如果创建时没有指定此队列大小,则默认为Integer.MAX_VALUE;
  3. SynchronousQueue; 这个队列比较特殊,它不会保存提交的任务,而是将直接新建一个线程来执行新来的任务。

任务拒绝策略

当线程池的任务缓存队列已满并且线程池中的线程数目达到maximumPoolSize,如果还有任务到来就会采取任务拒绝策略,通常有以下四种策略:

  1. ThreadPoolExecutor.AbortPolicy:丢弃任务并抛出RejectedExecutionException异常。这种策略是默认的拒绝策略
  2. ThreadPoolExecutor.DiscardPolicy:也是丢弃任务,但是不抛出异常。
  3. ThreadPoolExecutor.DiscardOldestPolicy:丢弃队列最前面的任务,然后重新尝试执行任务(重复此过程)
  4. ThreadPoolExecutor.CallerRunsPolicy:由调用线程处理该任务

Executors提供的三个静态方法来创建线程池

Executors.newFixedThreadPool(int)(固定大小线程池
Executors.newSingleThreadExecutor()(单个后台线程)
Executors.newCachedThreadPool()(无界线程池,可以进行自动线程回收)

  1. newFixedThreadPool 固定大小的线程池 创建的线程池corePoolSize和maximumPoolSize值是相等的,它使用的LinkedBlockingQueue;
  2. newSingleThreadExecutor 单线程的线程池 将corePoolSize和maximumPoolSize都设置为1,也使用的LinkedBlockingQueue;
  3. newCachedThreadPool 有缓冲池的线程池 将corePoolSize设置为0,将maximumPoolSize设置为Integer.MAX_VALUE,使用的SynchronousQueue,也就是说来了任务就创建线程运行,当线程空闲超过60秒,就销毁线程。

线程池执行过程

  1. 如果当前线程池中的线程数目小于corePoolSize,则每来一个任务,就会创建一个线程去执行这个任务;
  2. 如果当前线程池中的线程数目>=corePoolSize,则每来一个任务,会尝试将其添加到任务缓存队列当中,若添加成功,则该任务会等待空闲线程将其取出去执行;若添加失败(一般来说是任务缓存队列已满),则会尝试创建新的线程去执行这个任务;
  3. 如果当前线程池中的线程数目达到maximumPoolSize,则会采取任务拒绝策略进行处理;
  4. 如果线程池中的线程数量大于 corePoolSize时,如果某线程空闲时间超过keepAliveTime,线程将被终止,直至线程池中的线程数目不大于corePoolSize;如果允许为核心池中的线程设置存活时间,那么核心池中的线程空闲时间超过keepAliveTime,线程也会被终止。

demo

新建 MyRejected


import java.util.concurrent.RejectedExecutionHandler;
import java.util.concurrent.ThreadPoolExecutor;

public class MyRejected implements RejectedExecutionHandler {

    public MyRejected(){
    }

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

新建 ThreadExecutor


import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.RejectedExecutionHandler;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

public class ThreadExecutor {

    public static void main(String[] args) throws InterruptedException {
        ThreadExecutor threadExecutor = new ThreadExecutor();
        threadExecutor.test01();
    }

    /**
     *  创建线程池
     */
    public void test01() throws InterruptedException {
        RejectedExecutionHandler handler = new MyRejected();
        ThreadPoolExecutor executor = new ThreadPoolExecutor(5, 10, 200, TimeUnit.MILLISECONDS, new ArrayBlockingQueue<Runnable>(5), handler);
        for(int i=0; i<15; i++){
//        for(int i=0; i<20; i++){
            MyTask myTask = new MyTask(i);
            executor.execute(myTask);
            Thread.sleep(10);
        }
        executor.shutdown();
    }
}

class MyTask implements Runnable {
    private int taskNum;

    public MyTask(int num) {
        this.taskNum = num;
    }

    @Override
    public void run() {
        try {
            Thread.sleep(4000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("task "+taskNum+"执行完毕");
    }
}

在这里插入图片描述
先执行了 0 -4 的线程,5 - 9 的线程放入了ArrayBlockingQueue队列中,紧接着10 - 14 的线程准开始执行,发现队列放不下了,因此去创建线程去执行,0 - 4 线程被执行完了之后,线程池取出队列中的线程去执行。
当 for 循环,循环创建20个线程时,执行了拒绝策略
在这里插入图片描述
根据此截图看出超出了最大线程数时,同时队列也满了,线程池再执行线程则会执行线程池的拒绝策略,因此在这个demo中,MyRejected抛出了异常

提前创建线程

创建线程池后,当执行任务时,才会创建线程,如果创建线程池的时候,就调用了prestartAllCoreThreads,则会先创建线程,等待任务使用

  1. public int prestartAllCoreThreads()启动所有核心线程,使其处于等待工作的空闲状态。仅当执行新任务时,此操作才重写默认的启动核心线程策略。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值