原文:http://hellojava.info/?p=13
在有了java.util.concurrent包后,通常都会采用Executors或ThreadPoolExecutor来创建线程池,但这两个类都挺容易用错,如果不仔细阅读它的API或源码的话,很容易就踩进坑里。
通过new ThreadPoolExecutor可创建相应配置的线程池,但这个接口挺容易被误用,也许会导致行为和你想要的不太一样,之前在微博上我出了下面这道题。
有以下两个线程池:
ThreadPoolExecutor aPool = new ThreadPoolExecutor(10,20,5,TimeUnit.MINUTES,new SynchronousQueue<Runnable>());
ThreadPoolExecutor bPool = new ThreadPoolExecutor(10,20,5,TimeUnit.MINUTES,new ArrayBlockingQueue<Runnable>(10));
目前已有10个请求正在处理中,请问当第11个请求进来时aPool和bPool分别会如何处理?
从评论上来看,答错的人还是有一些的,这道题的正确答案是:
当第11个请求进来时,aPool会启动线程来立刻处理,bPool会放入BlockingQueue,等待前面的线程处理完才会被处理。
原因是ThreadPoolExecutor的实现机制为当目前运行的线程数 >= corePoolSize(也就是上面的10)时,ThreadPoolExecutor会将请求放进Queue中(例如上面的aPool是 SynchronousQueue),如放失败且目前的线程数 < maxPoolSize(也就是上面的20),那么就直接启动新线程来处理,如目前运行的线程数等于maxPoolSize,则执行对应的策略,上面的 aPool和bPool使用的都是默认的拒绝并跑出异常的策略;如放成功则进行再次的检查(例如线程池是否被shutdown、运行的线程数是否小于 corePoolSize),然后返回。
SynchronousQueue是一个很特殊的Queue,当往这个Queue放东西时,必须有另外一个线程在从这个Queue里拿,如没有,则 直接失败,在上面的场景中,当第11个请求进来时,往这个Queue中放就将失败,而这个时候运行的线程数又小于maxPoolSize,因此将启动新线 程进行处理。
而bPool采用的是ArrayBlockingQueue,put将成功,可见在bPool的情况下,想要运行的线程数增加到11个,必须是10个线程 已经在处理中,并且ArrayBlockingQueue已经排队了10个请求,那么这个时候如果再有第21个请求进来,才会启动第11个线程进行处理, 刚用这个API时,很容易会认为只有当线程数已经达到了maxPoolSize后才会往Queue里放。
Executors是ThreadPoolExecutor的包装,基于它可以更简单的去创建线程池,但在使用它创建线程池也要特别的注意,下面就说说这个类中常用的几个方法创建的线程池的一些特征:
1. newCachedThreadPool
这种方式创建出来的线程池corePoolSize为0,maxPoolSize为Integer.MAX_VALUE,BlockingQueue为 SynchronousQueue,因此这个线程池的行为为如线程均在运行中,新任务需要执行,则直接启动线程,直到运行的线程数达到 Integer.MAX_VALUE。
这种线程池在某些情况下可能会创建非常大量的线程,鉴于这个原因,不推荐使用。
2. newFixedThreadPool
这种方式创建出来的线程池corePoolSize和maxPoolSize均为指定的大小,BlockingQueue为 LinkedBlockingQueue,因此这个线程池的行为为如同时处理的请求小于指定的大小,那么就创建新的线程来处理,如达到了指定的大小,则放 入Queue中。
这种线程池在某些情况下可能会出现Queue中堆积了很多的任务,导致内存被耗光的现象,因此也不推荐使用,如有类似需求,建议使用限定大小的ArrayBlockingQueue等。
最后无论是用哪种方式创建的线程池,最好都增加下名字,可通过实现ThreadPoolFactory接口来做到(例如这个), 否则的话当线程池的线程处于等待任务处理时,如这个时候jstack,会看到一堆类似pool-x-thread-y的线程名字,堆栈中也都是 java.util之类的,如这个时候问题出在这个线程池创建的线程过多时,那排查起来就比较麻烦些(那就只能挂起btrace来跟踪)。
相关推荐
Java8并行流中自定义线程池操作示例 Java8并行流中自定义线程池操作示例主要介绍了Java8并行流中自定义线程池操作,结合实例形式分析了并行流的相关概念、定义及自定义线程池的相关操作技巧。 1. 概览 Java8引入了...
java线程池使用后到底要关闭吗 java线程池是一种高效的并发编程技术,可以帮助开发者更好地管理线程资源,提高系统的性能和可靠性。然而,在使用java线程池时,一个常见的问题是:使用完线程池后到底要不要关闭?...
Java线程池封装是Java并发编程中重要的一环,合理的线程池配置和封装能显著提升程序的性能和稳定性。理解线程池的工作原理,根据业务需求选择合适的参数,以及正确处理拒绝策略,都是实现高效并发处理的关键。在实际...
本文将深入探讨如何在Java中使用线程池来查询大量数据,以及这样做的好处和实现方法。 首先,理解线程池的概念至关重要。线程池是一种多线程处理形式,预先创建了若干个线程,当有任务需要执行时,会从线程池中取出...
### Java编程中线程池的最大风险规避 #### 死锁 在Java编程中,线程池带来的一个显著风险就是死锁。死锁是指多个线程因互相等待对方持有的资源而不释放自身资源,导致无限期等待的情况。对于一般的多线程程序而言...
在Java中,`java.util.concurrent`包下的`ExecutorService`、`ThreadPoolExecutor`和`Executors`类提供了线程池的实现。 消息队列(Message Queue)则是一种异步通信机制,它允许应用程序将消息发送到队列,然后由...
在Java中,`ThreadPoolExecutor`是线程池的核心实现类之一,它提供了丰富的配置选项来满足不同的应用场景需求。该类继承自`AbstractExecutorService`,实现了线程池的主要功能。 **构造方法详解**: ```java ...
在Java中,线程池的核心接口是`Executor`,它是所有线程池实现的基础。该接口定义了一个`execute()`方法,用于提交任务进行执行。 ```java public interface Executor { void execute(Runnable command); } ``` #...
java线程池知识、
讲述了java线程池的优点,参数,6种线程池的使用场景,线程池用到的handler,线程任务的提交方式等等。
线程池在Java中主要通过`java.util.concurrent`包中的`ExecutorService`接口及其实现类来实现。本示例将深入探讨线程池的基本概念、工作原理以及如何在实际开发中应用。 线程池的核心组件包括:工作队列(Work ...
本文将深入探讨Java中的线程池实现及其相关知识点。 ### 1. Java线程池的实现 Java通过`java.util.concurrent`包中的`ExecutorService`接口和`ThreadPoolExecutor`类来实现线程池。`ExecutorService`是线程池的主要...
在Java中,通过使用线程池,我们可以预先创建一定数量的线程,这些线程在空闲时可以被复用,从而避免了每次创建新线程时的系统开销。此外,线程池还可以控制并发量,防止过多线程导致系统资源耗尽,从而提高系统的...
在Java中,`java.util.concurrent`包提供了`ExecutorService`接口和相关的实现,如`ThreadPoolExecutor`,它是线程池的核心。`ExecutorService`接口定义了添加任务、启动线程池、关闭线程池等方法。`...
在Java中,`java.util.concurrent`包提供了`ExecutorService`接口和它的实现类,如`ThreadPoolExecutor`,来支持线程池的创建和管理。本实例将深入探讨如何在Java中使用线程池,以及其背后的原理和最佳实践。 首先...
Java线程池是Java并发编程中的重要组成部分,它在多线程和高并发场景下扮演着关键角色。本文将深入探讨Java线程池的源码分析,并对比不同类型的线程池,以帮助开发者更好地理解和利用这一强大的工具。 首先,我们要...
在Java中,线程池的实现主要依赖于`java.util.concurrent`包中的`ExecutorService`接口和它的实现类,如`ThreadPoolExecutor`。`ExecutorService`定义了线程池的基本操作,如执行任务、关闭线程池等。而`...
Java线程池是Java并发编程中的重要组成部分,它允许开发者管理多个线程并有效地调度任务。线程池通过ThreadPoolExecutor类实现,这是一个高度可配置的工具,能够根据具体需求定制线程的创建、管理和销毁策略。 ...
线程池在Java中由`java.util.concurrent`包下的`ExecutorService`接口及其实现类,尤其是`ThreadPoolExecutor`类提供。这篇博文可能详细介绍了线程池的工作原理、配置参数以及如何使用。 线程池的核心组件包括: 1....