精华内容
下载资源
问答
  • 一、线程池阻塞队列、 二、拒绝策略、 三、使用 ThreadPoolExecutor 自定义线程池参数、





    一、线程池阻塞队列



    线程池阻塞队列是线程池创建的第 5 5 5 个参数 : BlockingQueue<Runnable> workQueue ;

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

    线程池阻塞队列 : 线程池中的阻塞队列 , 同一时刻 , 只能有 1 1 1 个线程访问队列 , 执行任务 入队 / 出队 操作 ; 队列都是 FIFO 先进先出 ;

    • 阻塞队列相关概念 :

      • 大小边界 :
        • 有界 : 阻塞队列 大小有限制 , 不是无限大的 ;
        • 无界 : 阻塞队列 理论上无限大 , 比如设置成 Integer.MAX_VALUE ;
      • 队列已满 : 只能出队 , 不能入队 ; 入队操作需阻塞等待 ;
      • 队列为空 : 只能入队 , 不能出队 ; 出队操作需要等待 ;
    • ArrayBlockingQueue : 有界阻塞队列 , 需要 指定阻塞队列大小 ;

    • LinkedBlockingQueue : 无界阻塞队列 , 基于链表的阻塞队列 ;

      • Executors.newCachedThreadPool()Executors.newFixedThreadPool(10) 方法创建的线程池 , 使用的是该阻塞队列 ;
    • SynchronousQueue : 队列 不存储元素 , 后一个 Runnable 任务入队 , 必须等到前一个任务执行完毕才可以 , 否则会一直阻塞等待 ;

      • Executors.newCachedThreadPool() 方法创建的线程池 , 使用的是该阻塞队列 ;
    • PriorityBlockingQueue : 有优先级的阻塞队列 ;


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





    二、拒绝策略



    线程池拒绝策略是线程池创建的第 7 7 7 个参数 : RejectedExecutionHandler handler ;

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

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

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

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

        private static final RejectedExecutionHandler defaultHandler =
            new AbortPolicy();
    




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



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


    代码示例 :

    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 12 12 , 也就是从 0 0 0 开始计数 , 执行了 13 13 13 个任务 , 其中 3 3 3 个线程池各自执行一个任务 , 阻塞队列存放 10 10 10 个任务 , 再次尝试将第 14 14 14 个任务放入阻塞队列时 , 报出 java.util.concurrent.RejectedExecutionException 异常 , 但是队列中的 10 10 10 个任务也正常执行完毕 ;

    线程 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
    

    在这里插入图片描述

    展开全文
  • @TOC线程池阻塞队列为什么都用LinkedBlockingQueue LinkedBlockingQueue 使用单链表实现,提供3种构造函数 LinkedBlockingQueue() 无参构造函数,链表长度为Integer.MAX_VALUE LinkedBlockingQueue(int capacity) ...

    @TOC线程池阻塞队列为什么都用LinkedBlockingQueue

    LinkedBlockingQueue
    使用单链表实现,提供3种构造函数

    LinkedBlockingQueue() 无参构造函数,链表长度为Integer.MAX_VALUE

    LinkedBlockingQueue(int capacity) 指定capacity长度

    LinkedBlockingQueue(Collection c) 不指定长度,即默认长度为Integer.MAX_VALUE,提供初始化元素

    链表节点由Node对象组成,每个Node有item变量用于存储元素,next变量指向下一个节点

    执行put的时候,将元素放到链表尾部节点;take的时候从头部取元素

    两种操作分别有一个锁putLock, takeLock,互不影响,可以同时进行

    /** Lock held by take, poll, etc */
    private final ReentrantLock takeLock = new ReentrantLock();

    /** Lock held by take, poll, etc */
    private final ReentrantLock takeLock = new ReentrantLock();

    ArrayBlockingQueue
    使用数组实现,3种构造函数

    ArrayBlockingQueue(int capacity) 指定长度

    ArrayBlockingQueue(int capacity, boolean fair) 指定长度,及指定是否使用FIFO顺序进出队列

    ArrayBlockingQueue(int capacity, boolean fair, Collection c) 指定长度,进行队列顺序,初始元素

    从构造函数看出,ArrayBlockingQueue必须指定初始化长度,如果线程池使用该队列,指定长度大了浪费内存,长度小队列并发性不高,在数组满的时候,put操作只能阻塞等待,或者返回false

    ArrayBlockingQueue 只定义了一个Lock,put和take使用同一锁,不能同时进行

    /** Main lock guarding all access */
    final ReentrantLock lock;

    总结
    LinkedBlockingQueue 无须指定长度,放入和取出元素使用不同的锁,双锁机制,互不影响,效率高,通用性强。

    ArrayBlockingQueue 必须指定长度,大了浪费内存,小了性能不高,使用同一把锁,效率低。

    原文:https://my.oschina.net/itsaysay/blog/3122750

    展开全文
  • 本问题主要考察线程池工作原理 有界队列,可以避免内存溢出 【corePoolSize】核心线程数设置为10 【maximumPoolSize】最大线程数,设置为Integer.MAX_VALUE 21亿 【queue】队列设置为有界队列ArrayBlockQueue...

    本问题主要考察线程池工作原理

    有界队列,可以避免内存溢出

    【corePoolSize】核心线程数设置为10

    【maximumPoolSize】最大线程数,设置为Integer.MAX_VALUE 21亿

    【queue】队列设置为有界队列ArrayBlockQueue(200)

    如果瞬间任务特别多,你可以无限制的不停地创建额外的线程出来,一台机器上可能有很多很多很多线程,每个线程都有自己的栈内存,占用一定的内存资源,会导致内存资源耗尽,系统也会崩溃。

    即使内存没有崩溃,也会导致机器的cpu load(cpu负载)特别高。

    假设【maximumPoolSize】最大线程数,设置为200。可能会导致任务被拒绝掉,很多任务无法被执行。

    无界队列用的比较多,实际情况下得看系统业务的具体负载。具体情况具体分析

    可以自定义一个拒绝策略:

    自定义一个reject策略,如果线程池无法执行更多的任务了,此时建议你可以把这个任务信息持久化写入磁盘里去,后台专门启动一个线程,后续等待你的线程池的工作负载降低了,他可以慢慢的从磁盘里读取之前持久化的任务,重新提交到线程池里去执行

    【评论区】

    1、8核16G的内存 一般可以创建多少线程呢?

    根据你的业务场景来去设计,核心线程数=CPU核数*(执行时间/(执行时间+等待时间))

    执行时间:代码中运算

    等待时间:比如调用dubbo接口等待响应

    2、如果使用无界队列,那么可能会导致OOM甚至宕机。 如果使用有界队列,然后设置max线程数=max那么会导致创建很多线程,也可能导致服务器崩溃。 所以要根据具体的场景以及具体的压测数据,来设定这些参数。最后就是我们可以手动去实现一个拒绝策略,将请求持久化一下,然后后台线程去等线程池负载降下来了后再读出来继续执行。

    展开全文
  • 并发-线程池阻塞队列 并发-线程池阻塞队列 并发-线程池阻塞队列
  • 线程池阻塞队列

    2021-07-26 22:21:48
    阻塞队列 add/remove 如果队列满了,add(T)会抛出异常 如果队列为空,remove()会抛出异常 ...如果队列满了,put(T)会阻塞 如果队列为空,take()会阻塞 常用的阻塞队列 LinkedBlockingQueue...

    阻塞队列

    add/remove

            如果队列满了,add(T)会抛出异常        

            如果队列为空,remove()会抛出异常

    offer/poll

            如果队列满了,offer(T)会返回false

            如果队列为空,poll()会返回null

    put/take

            如果队列满了,put(T)会阻塞

            如果队列为空,take()会阻塞

    常用的阻塞队列

           LinkedBlockingQueue:链表实现的阻塞队列,可以不指定大小,默认为Integer.MAX_VALUE

           ArrayBlockingQueue:数组实现的阻塞队列,必须指定大小

           SynchronousQueue:不能存放元素的阻塞队列

    线程池

    线程池参数

            corePoolSize:核心线程数

            maximumPoolSize:最大线程数、规定阻塞队列满了之后,允许创建的最大任务个数

            keepAliveTime:线程空闲时间

            unit:线程空闲时间单位

            workQueue:阻塞队列

            threadFactory:线程工厂,主要是给线程指定name

            handler:拒绝策略,默认是抛出异常

                     AbortPolicy:当任务书大于maximumPoolSize+阻塞队列大小之后,会抛出异常

                     DiscardPolicy:抛弃最近提交的任务

                     DiscardOldestPolicy:抛弃最早提交未执行的任务

                     CallerRunsPolicy:由调用线程自己执行该任务,如果是主线程那么就是main

    线程池工作原理

    ·         提交的任务数小于等于核心线程数,会创建核心线程执行任务

             ·提交的任务数大于核心线程数,超出部分会被加入阻塞队列中

             ·阻塞队列如果满了,判断超出的任务数是否大于最大线程数,如果大于那么走拒绝策略,否则执行。

    合理配置线程池

    CPU密集型

            有大量计算型的任务,最大线程数不要超过逻辑核心数

    IO密集型

            有大量磁盘io,网络通讯,最大线程数一般配置为2*逻辑核心数

    线程不安全的原因

             java内存模型中,为了提高效率在线程中引入了工作内存和主存,工作内存是线程私有的,两个线程同时要修改一个变量,刚开始都是从主存中拷贝一份副本,然后在工作内存中修改值,在未来某个时间刷新到主存中,由于两个线程都是在自己内部的工作内存修改变量,所以最终刷新到主存中的数据可能是不正确的,这就是线程不安全的原因。

    展开全文
  • Java 线程池等待队列问题

    千次阅读 2019-09-20 15:38:48
    线程池的等待队列最大长度默认为int的最大值,随口默写出来就是2147483647(2^31 -1,高中物理老师说过一句话,记住一些固定的数字可以预判一些问题)。线程池在提交任务时,如果线程池未达到最大线程数,则起线程...
  • 阻塞队列线程池

    2020-01-10 14:25:17
    文章目录阻塞队列线程池阻塞队列阻塞队列类型入队出队操作生产消费者模式传统版v1版本传统版v2版本阻塞队列v3版线程池线程池几种线程池线程池七大参数线程池运行过程线程池拒绝策略使用哪种线程池拒绝策略验证...
  • (五)java 线程池工作队列

    千次阅读 2018-07-01 15:20:01
    线程池工作队列 &nbsp;&nbsp;上一章我们介绍了线程的基本情况,这一章进一步了解线程池中的工作队列,BlockingQueue 队列。 在类 Executors 中,我们可以看到不同线程池维护的工作队列是不同的,如...
  • 线程池阻塞队列 1 SynchronousQueue 无缓冲阻塞队列: 该队列每个插入操作必须等待另一个线程进行相应的操作,本身不存储数据,只有当前一个线程删除时,后一个线程才能被删除。 2 ArrayBlokingQueue 有界阻塞...
  • 线程池工作队列饱和策略

    万次阅读 2016-07-03 00:13:03
    Java线程池会将提交的任务先置于工作队列中,在从工作队列中获取(SynchronousQueue直接由生产者提交给工作线程)。那么工作队列就有两种实现策略:无界队列和有界队列。无界队列不存在饱和的问题,但是其问题是当请求...
  • 一,线程池 首先了解线程池整个框架 1,这里记住最核心的类是ThreadPoolExecutor 2,在ExecuorService中提供了newSingleThreadExecutor,newFixedThreadPool,newCacheThreadPool,newScheduledThreadPool四个...
  • 线程池阻塞队列

    2020-07-27 11:23:29
    由于频繁的创建和销毁线程会消耗很多资源,因此线程池应运而生来去除频繁的创建与删除线程这一过程。 2、常见线程池 ①、newSingleThreadExecutor 单一线程池,使用唯一的工作线程执行任务,保证所有任务按照指定...
  • 8.线程池队列一般设置多少

    万次阅读 2018-09-24 14:49:03
    一、ThreadPoolExecutor的... 当线程数小于核心线程数时,即使有线程空闲,线程池也会优先创建新线程处理 设置allowCoreThreadTimeout=true(默认false)时,核心线程会超时关闭 queueCapacity:任务队列容量(...
  • Java线程池阻塞队列

    2020-08-17 01:16:24
    一.Java线程池的优点 1.降低资源消耗:通过重复利用线程池中已创建好的线程来降低线程创建和销毁造成的消耗。 2.提高响应速度:当任务到达时,任务可以直接拿到线程池中已创建好的线程立即执行。 3.提高线程的可...
  • 挑一道实战的来讲,线程池队列满了之后任务丢弃,怎么解决 开整 众所周知,线程池默认拒绝策略是丢弃并抛出异常,这样的话那溢出的任务就不见了,在实际业务中会受到影响。 优化: 改写拒绝策略,延迟任务重新投向...
  • 线程池 线程池介绍 一种线程使用模式。线程过多会带来调度开销,进而影响缓存局部性和整体性能。而线程池维护着多个线程,等待着监督管理者分配可并发执行的任务。这避免了在处理短时间任务时创建与销毁线程的代价...
  • 线程池 newCachedThreadPool() newFixedThreadPool(int nThreads) newSingleThreadPoolExecutor() newScheduledThreadPool(int corePoolSize) newWorkStrealingPool(int parallelism) 队列 SynchronousQueue...
  • 线程池&阻塞队列实现--笔记

    千次阅读 2018-08-23 08:58:42
    参考链接: ... http://tutorials.jenkov.com/java-concurrency/thread-pools.html 阻塞队列 阻塞队列是一个可以阻塞线程的队列。当你尝试向空队列中弹出元素时,会被阻塞,直到入队一个新元素。当向满队列写入...
  • 5.线程池常用阻塞队列 ArrayBlockingQueue(基于数组的先进先出队列,有界) LinkedBlockingQueue(基于链表的先进先出队列,无界) SynchronousQueue(无缓冲的等待队列,无界) DelayedWorkQueue 6.有哪6种常见的...
  • 一、线程池定义和使用 jdk 1.5 之后就引入了线程池。 1.1 定义 从上面的空间切换看得出来,线程是稀缺资源,它的创建与销毁是一个相对偏重且耗资源的操作,而Java线程依赖于内核线程,创建线程需要进行操作系统状态...
  • 为什么要用线程池 ...插入:队列不满时可以插入,阻塞插入元素的线程 移除:队列不为空时可以移除,空了阻塞取走元素的线程 即生产者-消费者模式 参数意义 public ThreadPoolExecutor( // 核心线程数
  • (1)如果使用的是无界队列LinkedBlockingQueue,也就是无界队列的话,没关系,继续添加任务到阻塞队列中等待执行,因为LinkedBlockingQueue 可以近乎认为是一个无穷大的队列,可以无限存放任务 ( 2 ) 如果使用的...
  • 线程池策略 corePoolSize:核心线程数;...第二步: 判断工作队列(workQueue)是否已,未则将新的任务提交到工作队列中,了则进入下一步; 第三步: 判断线程池中的线程数量是否达到了maxumunPo
  • java线程池--阻塞队列

    2019-02-14 10:20:40
    线程池的线程全部开启后,之后的线程任务就会先放入阻塞队列,由阻塞队列把线程任务发放到线程池的空闲线程,当阻塞队列没有任务时,线程池就会一直阻塞,直到新的线程任务进入,具体的线程池细节可参考我的另一篇...
  • 工作中有个任务需要写多线程记录一下登陆日志,...我很常规的设置了这些参数,核心线程数:5 最大线程数:Integer.MaxValue 存活时间:60s 阻塞队列:synBlockinQueue() 饱和策略重写的 后来code review的时候发现阻塞...
  • 分别是newCachedThreadPool、newFixedThreadPool、newSingleThreadExecutor,同时根据这些线程池与ThreadPoolExecutor的关系,进而引出了阻塞队列BlockingQueue,接下来我们详细介绍了接口BlockingQueue和接口中的...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 38,334
精华内容 15,333
关键字:

线程池阻塞队列满了