关于Java线程池详解

Posted zjoe80

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了关于Java线程池详解相关的知识,希望对你有一定的参考价值。

一.为什么要用线程池?

1.减少资源的开销 ;

2.减少了每次创建线程、销毁线程的开销;

3.提高响应速度 ,每次请求到来时,由于线程的创建已经完成,故可以直接执行任务,因此提高了响应速度。

   提高线程的可管理性 ,线程是一种稀缺资源,若不加以限制,不仅会占用大量资源,而且会影响系统的稳定性。 

   因此,线程池可以对线程的创建与停止、线程数量等等因素加以控制,使得线程在一种可控的范围内运行,不仅能保证系统稳定运行,而且方便性能调优。

 

二.Executor框架中的所有类可以分成三类:

1.任务:

任务有两种类型:Runnable和Callable。

2.任务执行器: 

Executor框架最核心的接口是Executor,它表示任务的执行器。 

Executor的子接口为ExecutorService。 

ExecutorService有两大实现类:ThreadPoolExecutor和ScheduledThreadPoolExecutor。

3.执行结果: 

Future接口表示异步的执行结果,它的实现类为FutureTask。

 

三.4种类型的线程池:

1. FixedThreadPool 定长线程池:

它是一种固定大小的线程池;

corePoolSize和maximunPoolSize都为用户设定的线程数量nThreads;

keepAliveTime为0,意味着一旦有多余的空闲线程,就会被立即停止掉;但这里keepAliveTime无效;

阻塞队列采用了LinkedBlockingQueue,它是一个无界队列;

由于阻塞队列是一个无界队列,因此永远不可能拒绝任务;

由于采用了无界队列,实际线程数量将永远维持在nThreads,因此maximumPoolSize和keepAliveTime将无效。

2. CachedThreadPool 可缓存线程池:

它是一个可以无限扩大的线程池;

它比较适合处理执行时间比较小的任务;

corePoolSize为0,maximumPoolSize为无限大,意味着线程数量可以无限大;

keepAliveTime为60S,意味着线程空闲时间超过60S就会被杀死;

采用SynchronousQueue装等待的任务,这个阻塞队列没有存储空间,这意味着只要有请求到来,就必须要找到一条工作线程处理他,如果当前没有空闲的线程,那么就会再创建一条新的线程。

3. SingleThreadExecutor  单一线程池:

它只会创建一条工作线程处理任务;

采用的阻塞队列为LinkedBlockingQueue;

 

4. ScheduledThreadPool  可调度的线程池

四. 线程池的处理流

 

 技术图片

 

 

一个线程从被提交(submit)到执行共经历以下流程:

1.线程池判断核心线程池里是的线程是否都在执行任务,如果不是,则创建一个新的工作线程来执行任务。如果核心线程池里的线程都在执行任务,则进入下一个流程;

2.线程池判断工作队列是否已满。如果工作队列没有满,则将新提交的任务储存在这个工作队列里。如果工作队列满了,则进入下一个流程。

3.线程池判断其内部线程是否都处于工作状态。如果没有,则创建一个新的工作线程来执行任务。如果已满了,则交给饱和策略来处理这个任务。

线程池在执行execute方法时,主要有以下四种情况:

1.如果当前运行的线程少于corePoolSize,则创建新线程来执行任务(需要获得全局锁)

2.如果运行的线程等于或多于corePoolSize ,则将任务加入BlockingQueue

3.如果无法将任务加入BlockingQueue(队列已满),则创建新的线程来处理任务(需要获得全局锁)

4.如果创建新线程将使当前运行的线程超出maxiumPoolSize,任务将被拒绝,并调用RejectedExecutionHandler.rejectedExecution()方法。

线程池采取上述的流程进行设计是为了减少获取全局锁的次数。在线程池完成预热(当前运行的线程数大于或等于corePoolSize)之后,几乎所有的excute方法调用都执行步骤2。

以上是关于关于Java线程池详解的主要内容,如果未能解决你的问题,请参考以下文章

关于Java线程池详解

java线程池参数详解

Java线程池详解

Java自带线程池和队列详解

美团面试题:Java-线程池 ThreadPool 专题详解

Java多线程:线程池详解