关于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线程池详解的主要内容,如果未能解决你的问题,请参考以下文章