Java并发之线程池详解
2017-11-29 00:00
489 查看
Java线程池有哪些状态?如何切换?
线程池的种类有哪些?
创建线程池需要哪些参数?含义?
将任务添加到线程池的运行流程?
线程池怎么重用线程?
线程池如何关闭?
各种状态的说明在源码的注释中都有,我们来看一下:
The runState provides the main lifecycle control, taking on values:
处于RUNNING状态的线程池可以接收新的任务,也能够处理阻塞队列里面的任务。
SHUTDOWN:不能接受新的任务,可以处理阻塞队列里面的任务。
STOP:不能接受新的任务,也不会处理阻塞队列的任务。而且中断正在处理的任务。
TIDYING:所有的任务都被终止,线程池中工作线程的数量为0,将要调用terminated()方法。
TERMINATED: terminated()方法调用完毕,终止状态。
状态之间进行切换:
RUNNING切换到SHUTDOWN状态:调用shutdown()方法后切换到SHUTDOWN状态。
RUNNING、SHUTDOWN切换到STOP状态:调用shutdownNow()方法切换到STOP状态
SHUTDOWN切换到TIDYING状态:在阻塞队列和线程池为空的情况下切换到TIDYING状态。
STOP切换到TIDYING状态:线程池为空时切换到该状态。
TIDYING切换到TERMINATED状态:
调用terminated()方法切换到该状态。
submit()和execute()方法。
区别是submit()方法可以传入一个实现Callable()接口的对象,在当前任务结束的时候能返回一个Future对象来获取任务的返回值。
submit()方法还是调用了execute()方法
下面我们重点来看一下execute()方法:
首先判断当前线程的数量与核心线程数量比较,如果小于核心线程的数量,直接创建一个新的worker线程
如果当前线程数量大于corePoolSize的数量,尝试添加任务到阻塞队列里面,然后第二次检查线程的数量,如果线程池状态不在RUNNING,直接移除,同时拒绝当前请求的任务,如果状态为RUNNING且线程的数量为0,创建一个新的线程。
如果当前状态不是RUNNING,则尝试创建一个新的worker来处理任务,如果创建失败,拒绝当前任务。
线程运行的四个阶段:
1.poolSize<corePoolSize
当前线程数量小于核心线程数量,直接创建线程来处理
2.poolSize=corePoolSize,而且此时阻塞队列没有满,将此任务添加到阻塞队列里面,如果此时存在工作线程(非核心线程),由工作线程来处理阻塞队列中的任务,如果工作线程数量为0,则会创建工作线程来处理
3. poolSize=corePoolSize 并且此时阻塞队列满了,直接创建新的工作线程来处理当前任务
4.poolSize=maxmumPoolSize:此时阻塞队列也满了,就会触发拒绝机制,具体什么策略由传入的RejectExceptionHandler决定
Java中常用线程池:
线程池的种类有哪些?
创建线程池需要哪些参数?含义?
将任务添加到线程池的运行流程?
线程池怎么重用线程?
线程池如何关闭?
首先线程池有哪些状态以及如何切换
来搞一下源码:ThreadPoolExecutor.javaprivate static final int RUNNING = -1 << COUNT_BITS; private static final int SHUTDOWN = 0 << COUNT_BITS; private static final int STOP = 1 << COUNT_BITS; private static final int TIDYING = 2 << COUNT_BITS; private static final int TERMINATED = 3 << COUNT_BITS;
各种状态的说明在源码的注释中都有,我们来看一下:
The runState provides the main lifecycle control, taking on values:
RUNNING: Accept new tasks and process queued tasks SHUTDOWN: Don't accept new tasks, but process queued tasks STOP: Don't accept new tasks, don't process queued tasks,and interrupt in-progress tasks TIDYING: All tasks have terminated, workerCount is zero, the thread transitioning to state TIDYING will run the terminated() hook method TERMINATED: terminated() has completed
处于RUNNING状态的线程池可以接收新的任务,也能够处理阻塞队列里面的任务。
SHUTDOWN:不能接受新的任务,可以处理阻塞队列里面的任务。
STOP:不能接受新的任务,也不会处理阻塞队列的任务。而且中断正在处理的任务。
TIDYING:所有的任务都被终止,线程池中工作线程的数量为0,将要调用terminated()方法。
TERMINATED: terminated()方法调用完毕,终止状态。
状态之间进行切换:
RUNNING -> SHUTDOWN On invocation of shutdown(), perhaps implicitly in finalize() (RUNNING or SHUTDOWN) -> STOP On invocation of shutdownNow() SHUTDOWN -> TIDYING When both queue and pool are empty STOP -> TIDYING When pool is empty TIDYING -> TERMINATED When the terminated() hook method has completed
RUNNING切换到SHUTDOWN状态:调用shutdown()方法后切换到SHUTDOWN状态。
RUNNING、SHUTDOWN切换到STOP状态:调用shutdownNow()方法切换到STOP状态
SHUTDOWN切换到TIDYING状态:在阻塞队列和线程池为空的情况下切换到TIDYING状态。
STOP切换到TIDYING状态:线程池为空时切换到该状态。
TIDYING切换到TERMINATED状态:
调用terminated()方法切换到该状态。
创建线程池需要哪些参数?参数的含义?
源码中创建ThreadPoolExecutor的构造方法是这样的:public ThreadPoolExecutor int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler) {
corePoolSize: 核心线程的数量,当一个任务条件到线程池中执行时,只要线程的数量达不到corePoolSize的数量,就会创建新的线程,直到线程数量达到corePoolSize的大小,不再创建,将新的任务放到阻塞队列中等待执行。 maximumPoolSize:线程池中允许创建最大线程数量,如果阻塞队列已满,创建的线程数量小于maximumPoolSize的话,会创建新的线程来处理阻塞队列中的任务。 keepAliveTime:线程活动的保持时间,当线程数量大于corePoolSize时,核心线程之外的线程空闲时间,大于该时间将会被回收。 unit:keepAliveTime的单位。 workQueue: 阻塞队列,当线程池中的线程数量为corePoolSize时,新来的任务会放到该阻塞队列中,有四种阻塞队列: ArrayBlockingQueue:基于数组的阻塞队列 LinkedBlockingQueue:基于链表的阻塞队列 SychronusBlockingQueue:不存储元素的阻塞队列(没见过) PriorityBlockingQueue:基于优先级的阻塞队列 threadFactory:创建线程的工厂 handler: 当阻塞队列满了,没有空闲线程的情况下,线程中的数量已经达到了最大数目,必须采取一种策略来处理新来的任务。主要有四种策略:AbortPolicy(直接抛出异常)、CallerRunsPolicy(使用调用者的线程处理)、DiscardOldsPolciy(丢弃阻塞队列中一个任务,处理当前任务)、Discard直接丢弃。
线程池的运行流程?
线程池对象有两个方法用来执行线程:submit()和execute()方法。
区别是submit()方法可以传入一个实现Callable()接口的对象,在当前任务结束的时候能返回一个Future对象来获取任务的返回值。
submit()方法还是调用了execute()方法
public Future<?> submit(Runnable task) { if (task == null) throw new NullPointerException(); RunnableFuture<Void> ftask = newTaskFor(task, null); execute(ftask); return ftask; }
下面我们重点来看一下execute()方法:
int c = ctl.get(); if (workerCountOf(c) < corePoolSize) { if (addWorker(command, true)) return; c = ctl.get(); } if (isRunning(c) && workQueue.offer(command)) { int recheck = ctl.get(); if (! isRunning(recheck) && remove(command)) reject(command); else if (workerCountOf(recheck) == 0) addWorker(null, false); } else if (!addWorker(command, false)) reject(command);
首先判断当前线程的数量与核心线程数量比较,如果小于核心线程的数量,直接创建一个新的worker线程
如果当前线程数量大于corePoolSize的数量,尝试添加任务到阻塞队列里面,然后第二次检查线程的数量,如果线程池状态不在RUNNING,直接移除,同时拒绝当前请求的任务,如果状态为RUNNING且线程的数量为0,创建一个新的线程。
如果当前状态不是RUNNING,则尝试创建一个新的worker来处理任务,如果创建失败,拒绝当前任务。
线程运行的四个阶段:
1.poolSize<corePoolSize
当前线程数量小于核心线程数量,直接创建线程来处理
2.poolSize=corePoolSize,而且此时阻塞队列没有满,将此任务添加到阻塞队列里面,如果此时存在工作线程(非核心线程),由工作线程来处理阻塞队列中的任务,如果工作线程数量为0,则会创建工作线程来处理
3. poolSize=corePoolSize 并且此时阻塞队列满了,直接创建新的工作线程来处理当前任务
4.poolSize=maxmumPoolSize:此时阻塞队列也满了,就会触发拒绝机制,具体什么策略由传入的RejectExceptionHandler决定
重用线程
线程池重用线程,主要是在执行worker线程时候去阻塞队列里面拿任务,不断的去拿任务交给线程来执行,达到重用的目的,直到getTask为null为止。final void runWorker(Worker w) { Thread wt = Thread.currentThread(); Runnable task = w.firstTask; w.firstTask = null; w.unlock(); // allow interrupts boolean completedAbruptly = true; try { while (task != null || (task = getTask()) != null) {
线程池关闭
调用shutdown()和shutdownNow()方法Java中常用线程池:
<p>newSingleThreadExecutor:创建一个单线程的线程池。这个线程池只有一个线程在工作,也就是相当于单线程串行执行所有任务。如果这个唯一的线程因为异常结束,那么会有一个新的线程来替代它。此线程池保证所有任务的执行顺序按照任务的提交顺序执行。</p> <p>newFixedThreadPool:创建固定大小的线程池。每次提交一个任务就创建一个线程,直到线程达到线程池的最大大小。线程池的大小一旦达到最大值就会保持不变,如果某个线程因为执行异常而结束,那么线程池会补充一个新线程。</p> <p>newCachedThreadPool:创建一个可缓存的线程池。如果线程池的大小超过了处理任务所需要的线程,那么就会回收部分空闲(60秒不执行任务)的线程,当任务数增加时,此线程池又可以智能的添加新线程来处理任务。此线程池不会对线程池大小做限制,线程池大小完全依赖于操作系统(或者说JVM)能够创建的最大线程大小。</p> <p>newScheduledThreadPool:创建一个大小无限的线程池。此线程池支持定时以及周期性执行任务的需求。</p> <p>newSingleThreadExecutor:创建一个单线程的线程池。此线程池支持定时以及周期性执行任务的需求。</p>
相关文章推荐
- Java并发编程 11 Executor线程池详解
- Java并发核心基础——线程池使用及底层实现机制详解
- Java并发:线程池详解(ThreadPoolExecutor)
- @Java并发编程:线程池的使用
- 《Java 7 并发编程指南》学习概要 (5) 线程池
- Java并发编程:线程池 - 实例
- Java高并发--线程池
- java并发编程:线程池的使用
- Java Executor并发框架(六)Executor框架线程池任务执行全过程(上)
- 【Java 并发】详解 ThreadLocal
- java并发线程池---了解ThreadPoolExecutor就够了
- 使用Spring中的线程池ThreadPoolTaskExecutor实现JAVA并发
- java并发多线程-基于线程池设计的ScheduledExecutor任务调度(8)
- java编程思想笔记-并发之并发锁synchronized详解(二)
- [置顶] Java并发之AQS详解
- Java并发笔记-未完待续待详解
- Java 并发:Executors 和线程池
- JAVA CONCURRENCY EXECUTORS 介绍Java并发处理线程池
- java并发包&线程池原理分析&锁的深度化
- 我理解的Java并发基础(七):线程池和Executors工具类