一个例子理解java线程池 ThreadPoolExecutor

创建一个线程池需要7个参数

  • corePoolSize 核心线程数量
  • maximumPoolSize 最大线程数量
  • keepAliveTime 当线程数大于核心时,这是多余空闲线程在终止之前等待新任务的最长时间
  • TimeUnit 等待时间keepAliveTime的单位
  • workQueue 任务队列类型为BlockingQueue
  • ThreadFactory 创建线程的工厂
  • RejectedExecutionHandler 线程池拒绝处理器

    例子

    如何理解这几个参数呢,举个栗子

       可以把线程池执行任务想象成我们去营业厅办理业务, 假设营业厅有5个窗口可以办理业务, 当同时办理业务的人多余5个的时候, 工作人员会安排剩下的人到等候厅的椅子上等候办理, 假设等候厅有20个椅子, 那么如果人多到椅子坐不下会怎么办, 营业厅会再开设5个临时窗口, 新来的人发现等候厅的椅子坐不下了, 就会去临时窗口办理, 临时窗口不会一直开设, 某个临时窗口如果发现一个小时之内都没有人来就会关闭. 还有可能人实在太多, 多到临时窗口也被占满, 这个时候新来的人就会被告知明天再来(被拒绝)

联系例子,再来看一下参数

  • corePoolSize 营业厅原本的5个窗口,它们会一直开着
  • maximumPoolSize 原本的窗口数+临时窗口数
  • keepAliveTime 某个临时窗口发现一个小时内没人来就会关闭,这个time就指这一个小时
  • workQueue 等候厅的20个椅子
  • ThreadFactory 这些窗口办理的是联通业务还移动业务有它规定
  • RejectedExecutionHandler 当临时窗口也被占满时要怎么处理, 如例子中的告知明天再来办理就是一种拒绝处理

代码

//设置线程属性 规定窗口属性	
ThreadFactory threadFactory = new ThreadFactory() {
           @Override
           public Thread newThread(Runnable runnable) {
               Thread thread = new Thread(runnable);
               thread.setName("联通业务");
               return thread;
           }
       };

       //拒绝策略
       RejectedExecutionHandler handler = new RejectedExecutionHandler() {
           @Override
           public void rejectedExecution(Runnable runnable, ThreadPoolExecutor executor) {
               System.out.println("明天再来");
           }
       };
   
       ThreadPoolExecutor threadPool = new ThreadPoolExecutor(
               //corePoolSize 核心线程数 常驻窗口数(5)
               5,
               //maximumPoolSize  最大线程数 常驻窗口(5)+临时窗口(5)
               10,
               //keepAliveTime 临时窗口关闭时间(1小时)
               1L,
               //unit 单位小时
               TimeUnit.HOURS,
               //workQueue 任务队列 等候厅座位(20)
               new ArrayBlockingQueue<Runnable>(20),
               //threadFactory 线程工厂 规定窗口属性
               threadFactory,
               //RejectedExecutionHandler 拒绝策略
               handler
       );

测试代码

for (int i = 1; i <= 50; i++) {
    System.out.println("第" + i + "个人来办理业务");
    threadPool.submit(() -> {
        try {
            System.out.println(Thread.currentThread().getName()+"窗口正在办理业务");
            Thread.sleep(100000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    });

    Thread.sleep(100);
}

测试结果

第1个人来办理业务
联通业务窗口正在办理业务
第2个人来办理业务
联通业务窗口正在办理业务
第3个人来办理业务
联通业务窗口正在办理业务
第4个人来办理业务
联通业务窗口正在办理业务
第5个人来办理业务
联通业务窗口正在办理业务  	---------->前5个直接上窗口办理
第6个人来办理业务
第7个人来办理业务
第8个人来办理业务
......
第25个人来办理业务
第26个人来办理业务        ---------->20个被安排在等候厅
联通业务窗口正在办理业务
第27个人来办理业务
联通业务窗口正在办理业务
第28个人来办理业务
联通业务窗口正在办理业务
第29个人来办理业务
联通业务窗口正在办理业务
第30个人来办理业务
联通业务窗口正在办理业务
第31个人来办理业务       ---------->开设5个临时窗口办理
明天再来
第32个人来办理业务
明天再来
......
第50个人来办理业务
明天再来                ---------->被拒绝     

其它

线程池的一些其它注意点,任务队列,常用四种线程池,合理配置等可参看一个大佬的文章

由浅入深理解Java线程池及线程池的如何使用

转载请注明出处


本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!