摘要:本文主要向大家介绍了Java语言并发编程之线程池的使用详解,通过具体的内容向大家展示,希望对大家学习JAVA语言有所帮助。
本文主要向大家介绍了Java语言并发编程之线程池的使用详解,通过具体的内容向大家展示,希望对大家学习JAVA语言有所帮助。
Java中的ThreadPoolExecutor类
java.uitl.concurrent.ThreadPoolExecutor类是线程池中最核心的一个类,因此如果要透彻地了解Java中的线程池,必须先了解这个类。下面我们来看一下ThreadPoolExecutor类的具体实现源码。
在ThreadPoolExecutor类中提供了四个构造方法:
public class ThreadPoolExecutor extends AbstractExecutorService {
//...
public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit, BlockingQueue<Runnable> workQueue);
public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit,
BlockingQueue<Runnable> workQueue,ThreadFactory threadFactory);
public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit,
BlockingQueue<Runnable> workQueue,RejectedExecutionHandler handler);
public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit,
BlockingQueue<Runnable> workQueue,ThreadFactory threadFactory,RejectedExecutionHandler handler);
//...
}
下面介绍各个参数的意义:
corePoolSize: 指的是保留的线程池大小;
maximumPoolSize: 指的是线程池的最大大小;
keepAliveTime: 指的是空闲线程结束的超时时间;
unit: 是一个枚举,表示 keepAliveTime 的单位;
workQueue: 表示存放任务的队列;
threadFactory: 线程工厂,主要用来创建线程;
handler: 表示当拒绝处理任务时的策略;
我们可以从线程池的工作过程中了解这些参数的意义。线程池的工作过程如下:
线程池刚创建时,里面没有一个线程。任务队列是作为参数传进来的。不过,就算队列里面有任务,线程池也不会马上执行它们。
当调用 execute() 方法添加一个任务时,线程池会做如下判断:
a. 如果正在运行的线程数量小于 corePoolSize,那么马上创建线程运行这个任务;
b. 如果正在运行的线程数量大于或等于 corePoolSize,那么将这个任务放入队列。
c. 如果这时候队列满了,而且正在运行的线程数量小于 maximumPoolSize,那么还是要创建线程运行这个任务;
d. 如果队列满了,而且正在运行的线程数量大于或等于 maximumPoolSize,那么线程池会抛出异常,告诉调用者“我不能再接受任务了”。
当一个线程完成任务时,它会从队列中取下一个任务来执行。
当一个线程无事可做,超过一定的时间(keepAliveTime)时,线程池会判断,如果当前运行的线程数大于 corePoolSize,那么这个线程就被停掉。所以线程池的所有任务完成后,它最终会收缩到 corePoolSize 的大小。
这样的过程说明,并不是先加入任务就一定会先执行。假设队列大小为 10,corePoolSize 为 3,maximumPoolSize 为 6,那么当加入 20 个任务时,执行的顺序就是这样的:首先执行任务 1、2、3,然后任务 4-13 被放入队列。这时候队列满了,任务 14、15、16 会被马上执行,而任务 17-20 则会抛出异常。最终顺序是:1、2、3、14、15、16、4、5、6、7、8、9、10、11、12、13。
线程池实现原理
下面具体介绍线程池的方法以及属性:
线程池状态
要读懂线程池的状态,需要知道几个属性:
/*
*可以将这个参数看成是一个三十二位的二进制数,
*其中前三位表示线程池的状态,
*后二十九位表示线程池中工作线程的数量
*/
private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));
private static final int COUNT_BITS = Integer.SIZE - 3;
private static final int CAPACITY = (1 << COUNT_BITS) - 1;
// runState is stored in the high-order bits
private static final int RUNNING = -1 << COUNT_BITS; //RUNNING状态表示线程池可以接受任务正常工作
private static final int SHUTDOWN = 0 << COUNT_BITS; //SHUTDOWN状态表示线程池不接受任务,但如果阻塞队列中还有任务,会将阻塞队列中的任务执行完
private static final int STOP = 1 << COUNT_BITS; //STOP状态表示线程池不接受任务,也不会执行阻塞队列中的任务,即使阻塞队列中还存在任务
private static final int TIDYING = 2 << COUNT_BITS; //TIDYING状态表示所有任务都结束了,workerCount为0,调用terminated()方法
private static final int TERMINATED = 3 << COUNT_BITS; //TERMINATED状态terminated()方法调用完成
// Packing and unpacking ctl
private static int runStateOf(int c) { return c & ~CAPACITY; } //获取线程池的状态
private static int workerCountOf(int c) { return c & CAPACITY; } //获取线程池工作线程的数量
private static int ctlOf(int rs, int wc) { return rs | wc; } //用于切换线程池状态,必要的时候改变工作线程的数量
自定义线程池
对于处理些特殊的业务,我们有时会严格要求,发起的每个请求(execute)都是顺序执行的,但是同时有需要具备一定的优先级,也就是FIFO&PRIORIT。
类结构一览:
Priority 枚举类,标明任务的优先级,可实现优先执行
PriorityRunnableBase 优先级基础类,排序的依据,实现Runnable, Comparable
PriorityRunnable 具体业务runnable
FifoPriorityThreadPoolExecutor工作线程池
FifoPriorityThreadPoolExecutor线程池的构造方法:
//代码片段来自FifoPriorityThreadPoolExecutor
static {
mThreadPoolExecutor = new ThreadPoolExecutor(
CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE, TimeUnit.MILLISECONDS,
new PriorityBlockingQueue<Runnable>(), sThreadFactory);
mThreadPoolExecutor.allowCoreThreadTimeOut(true);
}
FifoPriorityThreadPoolExecutor执行任务:
//代码片段来自FifoPriorityThreadPoolExecutor
public void execute(Runnable runnable) {
mThreadPoolExecutor.execute(runnable);
}
设计中最重要的是PriorityRunnableBase,下面看看代码:
/**
* Created by JiangYiDong on 2018/1/19.
*/
public abstract class PriorityRunnableBase implements Runnable, Comparable<PriorityRunnableBase> {
/**
* 数字越大,优先级越高
*/
protected Priority priority;
private int order;
private static final AtomicInteger ordering = new AtomicInteger();
public PriorityRunnableBase(Priority priority) {
this.priority = priority;
this.order = ordering.getAndIncrement();
}
@Override
public int compareTo(PriorityRunnableBase another) {
return this.priority.ordinal() < another.priority.ordinal() ? 1
: this.priority.ordinal() > another.priority.ordinal() ? -1 : this.order - another.order;
}
}
注意:执行任务方法务必使用execute,具体请看线程池execute与submit的区别。
本文由职坐标整理并发布,希望对同学们有所帮助。了解更多详情请关注编程语言JAVA频道!
您输入的评论内容中包含违禁敏感词
我知道了
请输入正确的手机号码
请输入正确的验证码
您今天的短信下发次数太多了,明天再试试吧!
我们会在第一时间安排职业规划师联系您!
您也可以联系我们的职业规划师咨询:
版权所有 职坐标-一站式IT培训就业服务领导者 沪ICP备13042190号-4
上海海同信息科技有限公司 Copyright ©2015 www.zhizuobiao.com,All Rights Reserved.
沪公网安备 31011502005948号