`

java线程池2-任务队列的规则

 
阅读更多

先从一句代码开始,//创建固定线程数的线程池:

 

Java代码  收藏代码
  1. newFixedThreadPool = Executors.newFixedThreadPool(THREAD_POOL_SIZE);  

 

 

跟进这个方法,发现是一套默认参数创建出的ThreadPoolExecutor,而实际上,构造参数的参数是很多的,有门道

 

Java代码  收藏代码
  1. public static ExecutorService newFixedThreadPool(int nThreads) {  
  2.     return new ThreadPoolExecutor(nThreads, nThreads,  
  3.                                   0L, TimeUnit.MILLISECONDS,  
  4.                                   new LinkedBlockingQueue<Runnable>());  
  5. }  

 

 

那么来举例说明ThreadPoolExecutor的参数策略:

 

Java代码  收藏代码
  1. public ThreadPoolExecutor(int corePoolSize,  
  2.                           int maximumPoolSize,  
  3.                           long keepAliveTime,  
  4.                           TimeUnit unit,  
  5.                           BlockingQueue<Runnable> workQueue)  

 corePoolSize==10, 池内会维持10个线程,哪怕完全没有作业进入,或者是作业过多排队。

 

 maximumPoolSize==20  ,池内线程数最多可以达到20个,再多就不行了:) 但是能不能突破10,还需结合下面的参.

 

 keepAliveTime+TimeUnit==200ms, 当任务繁忙,core10个线程处理不过来的时候,新任务等待200ms后会被丢弃

,也就是排队超时机制

 

BlockingQueue ,排队策略,有三种:

 

1.直接提交方式(SynchronousQueue: 无缓冲队列,即时提交任务,即时处理。 当线程不够时会启动新线程处理任务,即突破corePoolSize的限制,奔向maximumPoolSize。如果最大线程数都处理不过来,任务将会被拒绝掉! 因此这里JDK推荐将maximum的值设置到尽量大。

 

  • Direct handoffs. A good default choice for a work queue is a SynchronousQueue that hands off tasks to threads without otherwise holding them. Here, an attempt to queue a task will fail if no threads are immediately available to run it, so a new thread will be constructed. This policy avoids lockups when handling sets of requests that might have internal dependencies. Direct handoffs generally require unbounded maximumPoolSizes to avoid rejection of new submitted tasks. This in turn admits the possibility of unbounded thread growth when commands continue to arrive on average faster than they can be processed. 

2.无界的队列(LinkedBlockingQueue),

会先维持corePoolSize个线程个数来处理队列中的任务,在任务繁忙的时候,Queue队列大小会增加到maximumPoolSize

而最大队列不能满足的情况下,则会出现提交阻塞,这个时候超时参数起作用。

Unbounded queues. Using an unbounded queue (for example a LinkedBlockingQueue without a predefined capacity) will cause new tasks to wait in the queue when all corePoolSize threads are busy. Thus, no more than corePoolSize threads will ever be created. (And the value of the maximumPoolSize therefore doesn't have any effect.) This may be appropriate when each task is completely independent of others, so tasks cannot affect each others execution; for example, in a web page server. While this style of queuing can be useful in smoothing out transient bursts of requests, it admits the possibility of unbounded work queue growth when commands continue to arrive on average faster than they can be processed.

 

3.有界队列(ArrayBlockingQueue),工作方式类似2,但是可以控制系统的资源消耗。不过往往非常难以取到平衡点。特别是经常阻塞的工作任务或者耗时较长的任务。

Bounded queues. A bounded queue (for example, an ArrayBlockingQueue) helps prevent resource exhaustion when used with finite maximumPoolSizes, but can be more difficult to tune and control. Queue sizes and maximum pool sizes may be traded off for each other: Using large queues and small pools minimizes CPU usage, OS resources, and context-switching overhead, but can lead to artificially low throughput. If tasks frequently block (for example if they are I/O bound), a system may be able to schedule time for more threads than you otherwise allow. Use of small queues generally requires larger pool sizes, which keeps CPUs busier but may encounter unacceptable scheduling overhead, which also decreases throughput.

 

 

下面仔细考虑三种队列的应用场景:

 

策略1.此策略可以避免在处理可能具有内部依赖性的请求集时出现锁。 任务线程互相等待的情况,使用策略一是明智的。

 

策略2.这种排队可用于处理瞬态突发请求,当命令以超过队列所能处理的平均数连续到达时,使用池子来缓冲,异步化。Web 服务器中非常适用。

 

策略3.是一种稳妥、防雪崩的方式。在任务阻塞可接受的情况下,配合较大keepAliveTime参数使用。只是如何取得线程调度和cpu,内存的平衡,比较困难。应该使用场景不多。

 

个人理解:

1.线程池非常适合用来做异步化。特别是对于峰值很高的web应用,应该异步化一切,特别是日志写。并且对于web应用来说,策略2使用最常见,偶尔也会用到策略3.

 

2. 策略1,2均有可能出现无界队列爆发性增长的可能性,导致系统资源过度消耗。过多的任务积累在内存中,一旦重启服务就会比较疼:)因此在这两种策略下,建议将池模型服务独立出来,不要胶合在业务进程。 业务和池进程可以使用udp包通讯,或者JMS。

 

3.异步化不代表出队速度可以比入队速度慢!因为欠下的债迟早还是要还的。因此异步化之后,第二件事情就是考虑优化task池的任务执行速度!

 

分享到:
评论

相关推荐

    JAVA并发编程实践-线程池-学习笔记

    2. **任务队列(Task Queue)**:用于存储待处理任务的队列,线程从队列中获取任务进行执行。队列的选择对线程池的行为有很大影响,例如有阻塞和非阻塞之分。 3. **线程工厂(Thread Factory)**:用于创建新线程的...

    Java 线程池详解,图文并茂.pdf

    2. 任务队列:任务被存储在任务队列中。 3. 获取任务:线程池从任务队列中获取任务。 4. 执行任务:线程池执行任务。 5. 任务完成:任务完成后,线程池将其从任务队列中删除。 线程池的设计思路可以用工厂的生产...

    1.Java分布式与微服务实战\多线程与分布式\第1节 线程池

    2. 如果线程数等于(或大于)corePoolSize但少于maximumPoolSize,则将任务放入队列。 3. 如果队列已满,并且线程数小于maxPoolSize,则创建一个新线程来运行任务。 4. 如果队列已满,并且线程数大于或等于maxPool...

    谈谈Java 线程池

    Java线程池是一种高效利用系统资源、管理和控制并发的重要工具。在Java中,线程池的概念借鉴了数据库连接池的思想,旨在通过复用已存在的线程来减少创建和销毁线程的开销,从而提高程序的运行效率。线程池不仅能够...

    java-Thread-study-summary.zip_java 多线程

    Java多线程是Java编程中的核心概念,它允许程序同时执行多个任务,提高了系统的效率和响应性。在Java中,实现多线程有两种主要方式:继承`Thread`类和实现`Runnable`接口。本资料“java-Thread-study-summary.zip”...

    java 线程池源码处理并发

    Java线程池是Java并发编程中的重要组成部分,它在处理多线程并发问题时提供了高效且灵活的解决方案。本文将深入解析Java线程池的源码,探讨其工作原理、核心组件以及如何优化并发性能。 Java线程池的实现主要基于`...

    线程池demo

    2. **任务队列**:线程池内部维护一个任务队列,用于存放待处理的任务。任务是通过`Runnable`或`Callable`接口来实现的,它们被提交到线程池后会被放入队列等待执行。 3. **线程工厂**:线程池可以自定义线程的创建...

    threadPoolDemo

    - **最大线程数(maximumPoolSize)**:线程池允许的最大线程数量,当任务队列满时,新任务会创建新的线程,直到达到这个限制。 - **工作队列(BlockingQueue&lt;Runnable&gt; workQueue)**:用于存储待执行任务的队列...

    spring 线程池

    2. **任务队列**:线程池内部维护一个任务队列,新提交的任务会被放入队列,等待空闲线程来处理。 3. **线程调度**:线程池根据预设的策略(如固定大小、有界队列、缓存线程池等)来决定何时创建新线程、何时回收...

    阻塞队列阻塞队列阻塞队列

    PriorityBlockingQueue不会保证线程公平性,但是它能保证元素的出队顺序遵循优先级规则,这在需要执行优先级任务的场景下非常有用。 这些阻塞队列都实现了java.util.concurrent.BlockingQueue接口,提供了如put、...

    定制化线程池实现高并发数据处理.zip

    在Java编程中,线程池是一种管理线程的机制,它可以有效地提高系统资源的利用率,减少线程创建和销毁的开销,同时还能控制系统的并发程度。本资料"定制化线程池实现高并发数据处理"主要探讨如何通过自定义线程池来...

    java 并发视频教程

    - `workQueue`:任务队列 - `threadFactory`:线程工厂 - `handler`:饱和策略 - `RejectedExecutionHandler`:拒绝策略 #### 五、Java并发工具类 - **`ConcurrentHashMap`**:线程安全的哈希表实现,使用分段...

    云外归鸟的线程池支持库

    2. **工作队列**:线程池内部维护一个任务队列,用于存储待执行的任务。当线程完成任务后,会从队列中取出新的任务继续执行,直到队列为空。 3. **线程管理**:线程池负责线程的生命周期管理,包括创建、启动、暂停...

    我的线程池

    线程池的监控和管理也是重要的一环,可以通过JMX(Java Management Extensions)来监控线程池的状态,包括活动线程数、已完成任务数、任务队列长度等,以便进行性能调优。 在实际应用中,还可以自定义线程池实现,...

    线程池的学习例子

    线程池的配置参数非常重要,包括核心线程数、最大线程数、线程存活时间、任务队列类型等。合理的配置能确保系统资源的高效利用,防止过多线程导致的资源耗尽,以及避免线程饥饿问题。 线程池中的线程还会遵循一定的...

    代理服务器改造设计说明书.doc

    - **任务队列类**:负责管理任务队列,当有新任务加入时,按照一定的规则分配给合适的线程。 - **线程分配与回收**:动态管理线程的创建和销毁过程,确保资源的有效利用。 #### 4.2 线程池管理 - **服务端线程池...

    java面试题2024资源下载

    - 创建定时任务线程池,支持周期性执行任务。 #### 十五、synchronized关键字的底层原理 - **监视器锁**: - synchronized关键字实现依赖于JVM的Monitor对象。 - 每个对象有一个Monitor与之关联,当且只有一个...

    线程学习.docx

    - `shutdownNow()` 尝试取消正在队列中等待的任务,并中断正在执行的任务,以便尽快关闭线程池。 总之,选择合适的线程池类型取决于具体的应用场景和需求。理解每种线程池的特点和适用场景可以帮助开发者更好地...

Global site tag (gtag.js) - Google Analytics