前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >【Java 并发编程】线程池机制 ( 线程池阻塞队列 | 线程池拒绝策略 | 使用 ThreadPoolExecutor 自定义线程池参数 )

【Java 并发编程】线程池机制 ( 线程池阻塞队列 | 线程池拒绝策略 | 使用 ThreadPoolExecutor 自定义线程池参数 )

作者头像
韩曙亮
发布2023-03-29 16:54:43
1.6K0
发布2023-03-29 16:54:43
举报
文章被收录于专栏:韩曙亮的移动开发专栏

文章目录

一、线程池阻塞队列


线程池阻塞队列是线程池创建的第

5

个参数 : BlockingQueue<Runnable> workQueue ;

代码语言:javascript
复制
    public ThreadPoolExecutor(int corePoolSize,					// 核心线程数 , 这些线程基本不会被销毁
                              int maximumPoolSize, 				// 最大线程数 , 线程池能创建的最大线程数量
                              long keepAliveTime, 				// 空闲情况下 , 非核心线程存活时间
                              TimeUnit unit, 					// 空闲时间单位
                              BlockingQueue<Runnable> workQueue,// 任务的阻塞队列 ★
                              ThreadFactory threadFactory, 		// 创建线程的工厂类
                              RejectedExecutionHandler handler) // 拒绝策略

线程池阻塞队列 : 线程池中的阻塞队列 , 同一时刻 , 只能有

1

个线程访问队列 , 执行任务 入队 / 出队 操作 ; 队列都是 FIFO 先进先出 ;

  • 阻塞队列相关概念 :
    • 大小边界 :
      • 有界 : 阻塞队列 大小有限制 , 不是无限大的 ;
      • 无界 : 阻塞队列 理论上无限大 , 比如设置成 Integer.MAX_VALUE ;
    • 队列已满 : 只能出队 , 不能入队 ; 入队操作需阻塞等待 ;
    • 队列为空 : 只能入队 , 不能出队 ; 出队操作需要等待 ;
  • ArrayBlockingQueue : 有界阻塞队列 , 需要 指定阻塞队列大小 ;
  • LinkedBlockingQueue : 无界阻塞队列 , 基于链表的阻塞队列 ;
    • Executors.newCachedThreadPool()Executors.newFixedThreadPool(10) 方法创建的线程池 , 使用的是该阻塞队列 ;
  • SynchronousQueue : 队列 不存储元素 , 后一个 Runnable 任务入队 , 必须等到前一个任务执行完毕才可以 , 否则会一直阻塞等待 ;
    • Executors.newCachedThreadPool() 方法创建的线程池 , 使用的是该阻塞队列 ;
  • PriorityBlockingQueue : 有优先级的阻塞队列 ;

阻塞队列吞吐量 : SynchronousQueue > LinkedBlockingQueue > ArrayBlockingQueue ;

二、拒绝策略


线程池拒绝策略是线程池创建的第

7

个参数 : RejectedExecutionHandler handler ;

代码语言:javascript
复制
    public ThreadPoolExecutor(int corePoolSize,					// 核心线程数 , 这些线程基本不会被销毁
                              int maximumPoolSize, 				// 最大线程数 , 线程池能创建的最大线程数量
                              long keepAliveTime, 				// 空闲情况下 , 非核心线程存活时间
                              TimeUnit unit, 					// 空闲时间单位
                              BlockingQueue<Runnable> workQueue,// 任务的阻塞队列 
                              ThreadFactory threadFactory, 		// 创建线程的工厂类
                              RejectedExecutionHandler handler) // 拒绝策略 ★

线程池拒绝策略 : 如果核心线程 , 非核心线程都在执行任务 , 阻塞队列是有界的 , 也满了 , 此时线程池如果再添加任务 , 就会触发如下拒绝策略 ;

  • DiscardPolicy : 丢弃任务 ;
  • DiscardOldestPolicy : 丢弃队头的最旧的任务 ;
  • AbortPolicy : 抛出异常 , 这也是默认方式 ;
  • CallerRunsPolicy : 调用者自行处理 ;

线程池默认的拒绝策略是 抛出异常 方式 ;

代码语言:javascript
复制
    private static final RejectedExecutionHandler defaultHandler =
        new AbortPolicy();

三、使用 ThreadPoolExecutor 自定义线程池参数


创建

1

个线程池 , 核心线程数是

2

, 最大线程数是

3

, 则非核心线程 0 ~ 1 个 , 非核心线程最大空闲存活时间 60 秒 , 阻塞队列最大存放 10 个元素 , 拒绝策略设置为抛出异常方式 , 如果阻塞队列装满 , 再次尝试执行新任务时 , 会抛出异常 ;

代码示例 :

代码语言:javascript
复制
import java.util.concurrent.*;

public class Main {

    public static void main(String[] args) {
        ExecutorService executorService = new ThreadPoolExecutor(
                2,                          // 核心线程数 2
                3,                      // 最大线程数 3, 非核心线程 0 ~ 1 个
                60,                        // 非核心线程最大空闲存活时间 60 秒
                TimeUnit.SECONDS,
                new ArrayBlockingQueue<>(10),   // 阻塞队列, 最大存放 10 个元素
                Executors.defaultThreadFactory(),       // 线程工厂
                new ThreadPoolExecutor.AbortPolicy()    // 决绝策略, 如果执行任务失败, 抛出异常
        );
        for (int i = 0; i < 20; i ++) {
            executorService.execute(new Task(i));
        }
    }

    static class Task implements Runnable {
        /**
         * 记录线程的索引 0 ~ 99
         */
        private int i = 0;

        public Task(int i) {
            this.i = i;
        }

        @Override
        public void run() {
            System.out.println("线程 ID : " + Thread.currentThread().getName() + " , 线程索引 : " + i);

            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

执行结果 : 这里线程最大执行到了

12

, 也就是从

0

开始计数 , 执行了

13

个任务 , 其中

3

个线程池各自执行一个任务 , 阻塞队列存放

10

个任务 , 再次尝试将第

14

个任务放入阻塞队列时 , 报出 java.util.concurrent.RejectedExecutionException 异常 , 但是队列中的

10

个任务也正常执行完毕 ;

代码语言:javascript
复制
线程 ID : pool-1-thread-2 , 线程索引 : 1
线程 ID : pool-1-thread-3 , 线程索引 : 12
线程 ID : pool-1-thread-1 , 线程索引 : 0
Exception in thread "main" java.util.concurrent.RejectedExecutionException: 
Task Main$Task@5cad8086 rejected from java.util.concurrent.ThreadPoolExecutor@6e0be858
[Running, pool size = 3, active threads = 3, queued tasks = 10, completed tasks = 0]
	at java.util.concurrent.ThreadPoolExecutor$AbortPolicy.rejectedExecution(ThreadPoolExecutor.java:2047)
	at java.util.concurrent.ThreadPoolExecutor.reject(ThreadPoolExecutor.java:823)
	at java.util.concurrent.ThreadPoolExecutor.execute(ThreadPoolExecutor.java:1369)
	at Main.main(Main.java:16)
线程 ID : pool-1-thread-3 , 线程索引 : 2
线程 ID : pool-1-thread-1 , 线程索引 : 4
线程 ID : pool-1-thread-2 , 线程索引 : 3
线程 ID : pool-1-thread-1 , 线程索引 : 5
线程 ID : pool-1-thread-2 , 线程索引 : 7
线程 ID : pool-1-thread-3 , 线程索引 : 6
线程 ID : pool-1-thread-1 , 线程索引 : 9
线程 ID : pool-1-thread-2 , 线程索引 : 8
线程 ID : pool-1-thread-3 , 线程索引 : 10
线程 ID : pool-1-thread-2 , 线程索引 : 11
在这里插入图片描述
在这里插入图片描述
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2021-09-10,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 文章目录
  • 一、线程池阻塞队列
  • 二、拒绝策略
  • 三、使用 ThreadPoolExecutor 自定义线程池参数
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档