ThreadPoolExecutor类是如何保证线程池正确运行的

news2024/11/26 6:18:21

ThreadPoolExecutor类中的重要属性

在ThreadPoolExecutor类中,存在几个非常重要的属性和方法,接下来,我们就介绍下这些重要的属性和方法。

ctl相关的属性

AtomicInteger类型的常量ctl是贯穿线程池整个生命周期的重要属性,它是一个原子类对象,主要用来保存线程的数量和线程池的状态,我们看下与这个属性相关的代码如下所示。

//主要用来保存线程数量和线程池的状态,高3位保存线程状态,低29位保存线程数量
private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));
//线程池中线程的数量的位数(32-3)
private static final int COUNT_BITS = Integer.SIZE - 3;
//表示线程池中的最大线程数量
//将数字1的二进制值向右移29位,再减去1
private static final int CAPACITY   = (1 << COUNT_BITS) - 1;
//线程池的运行状态
private 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;
//获取线程状态
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; }
private static boolean runStateLessThan(int c, int s) {
	return c < s;
}
private static boolean runStateAtLeast(int c, int s) {
	return c >= s;
}
private static boolean isRunning(int c) {
	return c < SHUTDOWN;
}
private boolean compareAndIncrementWorkerCount(int expect) {
	return ctl.compareAndSet(expect, expect + 1);
}
private boolean compareAndDecrementWorkerCount(int expect) {
	return ctl.compareAndSet(expect, expect - 1);
}
private void decrementWorkerCount() {
	do {} while (! compareAndDecrementWorkerCount(ctl.get()));
}

对于线程池的各状态说明如下所示。

  • RUNNING:运行状态,能接收新提交的任务,并且也能处理阻塞队列中的任务 SHUTDOWN:
    关闭状态,不能再接收新提交的任务,但是可以处理阻塞队列中已经保存的任务,当线程池处于RUNNING状态时,调用shutdown()方法会使线程池进入该状态
  • STOP:
    不能接收新任务,也不能处理阻塞队列中已经保存的任务,会中断正在处理任务的线程,如果线程池处于RUNNING或SHUTDOWN状态,调用shutdownNow()方法,会使线程池进入该状态
  • TIDYING: 如果所有的任务都已经终止,有效线程数为0(阻塞队列为空,线程池中的工作线程数量为0),线程池就会进入该状态。
  • TERMINATED: 处于TIDYING状态的线程池调用terminated ()方法,会使用线程池进入该状态

也可以按照ThreadPoolExecutor类的注释,将线程池的各状态之间的转化总结成如下图所示。
在这里插入图片描述

  • RUNNING -> SHUTDOWN:显式调用shutdown()方法, 或者隐式调用了finalize()方法
  • (RUNNING or SHUTDOWN) -> STOP:显式调用shutdownNow()方法
  • SHUTDOWN -> TIDYING:当线程池和任务队列都为空的时候
  • STOP -> TIDYING:当线程池为空的时候
  • TIDYING -> TERMINATED:当 terminated() hook 方法执行完成时候

其他重要属性

除了ctl相关的属性外,ThreadPoolExecutor类中其他一些重要的属性如下所示。

//用于存放任务的阻塞队列  
private final BlockingQueue<Runnable> workQueue;
//可重入锁
private final ReentrantLock mainLock = new ReentrantLock();
//存放线程池中线程的集合,访问这个集合时,必须获得mainLock锁
private final HashSet<Worker> workers = new HashSet<Worker>();
//在锁内部阻塞等待条件完成
private final Condition termination = mainLock.newCondition();
//线程工厂,以此来创建新线程
private volatile ThreadFactory threadFactory;
//拒绝策略
private volatile RejectedExecutionHandler handler;
//默认的拒绝策略
private static final RejectedExecutionHandler defaultHandler = new AbortPolicy();

ThreadPoolExecutor类中的重要内部类

在ThreadPoolExecutor类中存在对于线程池的执行至关重要的内部类,Worker内部类和拒绝策略内部类。接下来,我们分别看这些内部类。

Worker内部类

Worker类从源代码上来看,实现了Runnable接口,说明其本质上是一个用来执行任务的线程,接下来,我们看下Worker类的源代码,如下所示。

private final class Worker extends AbstractQueuedSynchronizer implements Runnable{
	private static final long serialVersionUID = 6138294804551838833L;
	//真正执行任务的线程
	final Thread thread;
	//第一个Runnable任务,如果在创建线程时指定了需要执行的第一个任务
	//则第一个任务会存放在此变量中,此变量也可以为null
	//如果为null,则线程启动后,通过getTask方法到BlockingQueue队列中获取任务
	Runnable firstTask;
	//用于存放此线程完全的任务数,注意:使用了volatile关键字
	volatile long completedTasks;
	
	//Worker类唯一的构造放大,传递的firstTask可以为null
	Worker(Runnable firstTask) {
		//防止在调用runWorker之前被中断
		setState(-1);
		this.firstTask = firstTask;
		//使用ThreadFactory 来创建一个新的执行任务的线程
		this.thread = getThreadFactory().newThread(this);
	}
	//调用外部ThreadPoolExecutor类的runWorker方法执行任务
	public void run() {
		runWorker(this);
	}
 
	//是否获取到锁 
	//state=0表示锁未被获取
	//state=1表示锁被获取
	protected boolean isHeldExclusively() {
		return getState() != 0;
	}
 
	protected boolean tryAcquire(int unused) {
		if (compareAndSetState(0, 1)) {
			setExclusiveOwnerThread(Thread.currentThread());
			return true;
		}
		return false;
	}
 
	protected boolean tryRelease(int unused) {
		setExclusiveOwnerThread(null);
		setState(0);
		return true;
	}
 
	public void lock()        { acquire(1); }
	public boolean tryLock()  { return tryAcquire(1); }
	public void unlock()      { release(1); }
	public boolean isLocked() { return isHeldExclusively(); }
 
	void interruptIfStarted() {
		Thread t;
		if (getState() >= 0 && (t = thread) != null && !t.isInterrupted()) {
			try {
				t.interrupt();
			} catch (SecurityException ignore) {
			}
		}
	}
}

在Worker类的构造方法中,可以看出,首先将同步状态state设置为-1,设置为-1是为了防止runWorker方法运行之前被中断。这是因为如果其他线程调用线程池的shutdownNow()方法时,如果Worker类中的state状态的值大于0,则会中断线程,如果state状态的值为-1,则不会中断线程。

Worker类实现了Runnable接口,需要重写run方法,而Worker的run方法本质上调用的是ThreadPoolExecutor类的runWorker方法,在runWorker方法中,会首先调用unlock方法,该方法会将state置为0,所以这个时候调用shutDownNow方法就会中断当前线程,而这个时候已经进入了runWork方法,就不会在还没有执行runWorker方法的时候就中断线程。

注意:大家需要重点理解Worker类的实现。

拒绝策略内部类

在线程池中,如果workQueue阻塞队列满了,并且没有空闲的线程池,此时,继续提交任务,需要采取一种策略来处理这个任务。而线程池总共提供了四种策略,如下所示。

  • 直接抛出异常,这也是默认的策略。实现类为AbortPolicy。
  • 用调用者所在的线程来执行任务。实现类为CallerRunsPolicy。
  • 丢弃队列中最靠前的任务并执行当前任务。实现类为DiscardOldestPolicy。
  • 直接丢弃当前任务。实现类为DiscardPolicy。

在ThreadPoolExecutor类中提供了4个内部类来默认实现对应的策略,如下所示。

public static class CallerRunsPolicy implements RejectedExecutionHandler {
 
	public CallerRunsPolicy() { }
 
	public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
		if (!e.isShutdown()) {
			r.run();
		}
	}
}
 
public static class AbortPolicy implements RejectedExecutionHandler {
 
	public AbortPolicy() { }
 
	public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
		throw new RejectedExecutionException("Task " + r.toString() + " rejected from " + e.toString());
	}
}
 
public static class DiscardPolicy implements RejectedExecutionHandler {
 
	public DiscardPolicy() { }
 
	public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
	}
}
 
public static class DiscardOldestPolicy implements RejectedExecutionHandler {
 
	public DiscardOldestPolicy() { }
 
 
	public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
		if (!e.isShutdown()) {
			e.getQueue().poll();
			e.execute(r);
		}
	}
}

我们也可以通过实现RejectedExecutionHandler接口,并重写RejectedExecutionHandler接口的rejectedExecution方法来自定义拒绝策略,在创建线程池时,调用ThreadPoolExecutor的构造方法,传入我们自己写的拒绝策略。

例如,自定义的拒绝策略如下所示。

public class CustomPolicy implements RejectedExecutionHandler {
 
	public CustomPolicy() { }
 
	public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
		if (!e.isShutdown()) {
			System.out.println("使用调用者所在的线程来执行任务")
			r.run();
		}
	}
}

使用自定义拒绝策略创建线程池。

new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                       60L, TimeUnit.SECONDS,
                       new SynchronousQueue<Runnable>(),
                       Executors.defaultThreadFactory(),
		       new CustomPolicy());

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/50392.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

LRU Cache【理论讲解 + 代码实现】

LRU Cache&#x1f4d6;1. 什么是LRU Cache&#x1f4d6;2. 为什么需要LRU算法&#xff1f;&#x1f4d6;3. LRU Cache的实现&#x1f4d6;1. 什么是LRU Cache LRU是Least Recently Used的缩写&#xff0c;意思是最近最少使用. 它是一种Cache替换算法. 什么是Cache? 狭义的…

校园论坛(Java)—— 登录注册和用户信息模块

校园论坛&#xff08;Java&#xff09;—— 登录注册和用户信息模块 文章目录校园论坛&#xff08;Java&#xff09;—— 登录注册和用户信息模块1、写在前面2、系统结构设计2.1 各个页面之间的调用关系2.2. 登录注册模块各层的设计3、登录注册模块设计3.1 用户注册功能3.2 用户…

HighTec 工程配置详解

HighTec 工程配置详解 编译配置 构建配置管理器 管理器内&#xff0c;可以创建各种不同用途的配置项。例如用于生产工程的 ROM 配置&#xff0c;用于调试工程的 Debug 配置。对于每个配置&#xff0c;所设置的工程属性是单独分开的&#xff0c;互相之间没有影响。 打开构建配…

[附源码]计算机毕业设计springboot咖啡销售平台

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

Unity复刻骑砍中的帝国象棋(一)

Unity复刻骑砍中的帝国象棋&#xff08;一&#xff09; 起因和简介 这两天从一款游戏中发现了这么个棋类小游戏&#xff0c;觉得挺有意思&#xff0c;没错&#xff0c;就是下面这个&#xff1a; 作为程序员的我&#xff0c;一下就想到复刻它一下。这个棋类小游戏&#xff0c…

【程序人生】4年创作纪念日,不忘初心,继续前行

&#x1f4eb;作者简介&#xff1a;小明java问道之路&#xff0c;专注于研究 Java/ Liunx内核/ C及汇编/计算机底层原理/源码&#xff0c;就职于大型金融公司后端高级工程师&#xff0c;擅长交易领域的高安全/可用/并发/性能的架构设计与演进、系统优化与稳定性建设。 &#x1…

JavaScript --04. 流程控制语句介绍

文章目录流程控制1 代码块1.1 声明代码块1.2 let 和 var的作用域2 条件判断语句 -- if语句3 条件分支语句3.1 if-else语句3.2 if-else if-else语句3.3 练习4 Switch语句5 循环语句5.1 While循环5.2 do-while循环5.3 for循环5.4 嵌套循环6 break和continue6.1 break6.2 continue…

PTL智能拣货系统

一、PTL背景介绍 随着工业 4.0 理念持续扩展并被接受&#xff0c;智能制造将是中国制造业发展趋势。未来的生产企业不仅仅在生产过程中追求智能化&#xff0c;仓储、工具、设备智能化管理都会成为新的趋势。 现阶段物流仓储行业进入了一个快速的发展期&#xff0c;各种各样的…

辣椒疫霉RXLR效应子抑制植物免疫

文章信息 题目&#xff1a;A Phytophthora capsici RXLR effector targets and inhibits the central immune kinases to suppress plant immunity 刊名&#xff1a;New Phytologist 作者&#xff1a;Xiangxiu Liang&#xff0c;Daolong Dou et al. 单位&#xff1a;China …

微信无感知检测单项好友【WeTool 免费版】【微信如何检测单向好友?】

一.微信无感知检测单项好友 1.1 背景 因为最近业务的原因加了好多的陌生微信好友&#xff0c;难免有很多好友删了我&#xff0c;但是我还有他的微信&#xff0c;岂不是很占地方&#xff1f; 所以我琢磨如何检测这些单项好友【利用转账、拉群的方法太费时间】&#xff0c;我无…

[附源码]计算机毕业设计springboot拉勾教育课程管理系统

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

事件绑定(onclick,onfocus,onblur)

事件绑定(onclick,onfocus,onblur) 学习路线&#xff1a;JavaScript_DOM->事件绑定(onclick,onfocus,onblur)-> 事件绑定(onmouseout,onmouseover) ->事件绑定(onsubmit)表单提交 ->提交表单与验证表单案例 常用绑定方式 方式一&#xff1a;通过 HTML标签中的事…

Java Hash 碰撞

散列函数&#xff08;英语&#xff1a;Hash function&#xff09;又称散列算法、哈希函数&#xff0c;是一种从任何一种数据中创建小的数字“指纹”的方法。散列函数把消息或数据压缩成摘要&#xff0c;使得数据量变小&#xff0c;将数据的格式固定下来。 该函数将数据打乱混合…

获取windows硬件、软件信息的方法

1&#xff0c;方法1 systeminfo 该命令是Windows中用于显示关于计算机及其操作系统的详细配置信息&#xff0c;包括操作系统配置、安全信息、产品 ID 和硬件属性&#xff0c;如 RAM、磁盘空间和网卡和补丁信息等。 SYSTEMINFO [/S system [/U username [/P [password]]]] [/FO…

从阿里降薪百分之三十来了国企,没想到还是要加班!哭了!

从阿里进国企&#xff0c;图什么&#xff1f;图它降工资&#xff1f;图它技术强&#xff1f;当然是图它轻松不加班&#xff0c;稳定不裁员&#xff01;但如果像下面这位阿里程序员一样&#xff0c;降薪百分之三十进了国企&#xff0c;发现还是得加班&#xff0c;大概只能emo了.…

[附源码]Python计算机毕业设计Django的文成考研培训管理系统

项目运行 环境配置&#xff1a; Pychram社区版 python3.7.7 Mysql5.7 HBuilderXlist pipNavicat11Djangonodejs。 项目技术&#xff1a; django python Vue 等等组成&#xff0c;B/S模式 pychram管理等等。 环境需要 1.运行环境&#xff1a;最好是python3.7.7&#xff0c;…

Ae 动态图形模板

哈喽&#xff0c;各位小伙伴&#xff01;今天我们来学习一下如何通过AePr导出和安装动态图形模板&#xff1f; 新建合成 首先&#xff0c;新建一个合成&#xff0c;然后点击文字工具&#xff0c;内容自定义&#xff08;例&#xff1a;一场彗星雨&#xff0c;隔断了时空&#…

【408篇】C语言笔记-第九章(数据结构概述)

文章目录第一节&#xff1a;逻辑结构与存储结构1. 逻辑结构2. 存储结构1. 顺序存储2. 链式存储3. 顺序存储与链式存储分析第二节&#xff1a;算法的评价&#xff08;时间复杂度与空间复杂度&#xff09;1. 算法定义2. 时间复杂度3. 空间复杂度第一节&#xff1a;逻辑结构与存储…

CentOS7安装GmSSL过程记录

近期因为项目需要上区块链&#xff0c;在集成过程中证书选择了国密SM2&#xff0c;于是开启了入坑之旅&#xff0c;由于整个过程反复多次&#xff0c;我的记录也可能存在遗漏&#xff0c;只能尽力记录&#xff0c;这也是我为什么熬夜也要写下这篇记录&#xff01; 环境说明Virt…

[附源码]Python计算机毕业设计Django的玉石交易系统

项目运行 环境配置&#xff1a; Pychram社区版 python3.7.7 Mysql5.7 HBuilderXlist pipNavicat11Djangonodejs。 项目技术&#xff1a; django python Vue 等等组成&#xff0c;B/S模式 pychram管理等等。 环境需要 1.运行环境&#xff1a;最好是python3.7.7&#xff0c;我…