92. 你说你精通Java并发,那给我讲讲JUC吧(一)

简介: 92. 你说你精通Java并发,那给我讲讲JUC吧(一)

92. 你说你精通Java并发,那给我讲讲JUC吧(一)


J.U.C

J.U.C即java.util.concurrent包,为我们提供了很多高性能的并发类,可以说是java并发的核心。

J.U.C和CAS和Unsafe和AQS

Concurrent包下所有类底层都是依靠CAS操作来实现,而sun.misc.Unsafe为我们提供了一系列的CAS操作。

AQS框架是J.U.C中实现锁及同步机制的基础,其底层是通过调用 LockSupport .unpark()和 LockSupport .park()实现线程的阻塞和唤醒。

J.U.C框架

J.U.C的整个框架分为5个部分:tools、locks、collections、executor和atomic。

Atomic

该包下主要是一些原子变量类,仅依赖于Unsafe,并且被其他模块所依赖。

Locks

该包下主要是关于锁及其相关类,仅依赖于Unsafe或内部依赖,并且被其他高级模块所依赖。由于LockSupport类底层逻辑简单且仅依赖Unsafe,同时为其他高级模块所依赖,所以需要先了解LockSupport类的运行原理,然后重点研究AbstractQueuedSynchronizer框架,理解独占锁和共享锁的实现原理,并清楚Condition如何与AbstractQueuedSynchronizer进行协作,最后很容易就能理解ReentrantLock是如何实现的。

Collections

该包会依赖Unsafe和前两个基础模块,并且模块内部各个容器间相互较为独立,所以没有固定的学习顺序,理解编程中常用的集合类原理即可:ConcurrentHashMap、CopyOnWriteArrayList、CopyOnWriteArraySet、ArrayBlockingQueue、LinkedBlockingQueue(阻塞队列在线程池中有使用,所以理解常用阻塞队列的特性很重要)。

Executor

这一部分的核心是线程池的运行原理,也是实际应用中较多的部分,会依赖于前几个模块。首先了解Callable、Future、RunnableFuture三个接口间的关系以及FutureTask的实现原理,然后研究如何创建ThreadPoolExecutor,如何运行一个任务,如何管理自身的线程,同时了解RejectedExecutionHandler的四种实现差异,最后,在实际应用中学习如何通过调整ThreadPoolExecutor的参数来优化线程池。

Tools

这一部分是以前面几个模块为基础的高级特性模块,实际应用的场景相对较少,主要应用在多线程间相互依赖执行结果场景,没有具体的学习顺序,最好CountDownLatch、CyclicBarrier、Semaphore、Exchanger、Executors都了解下,对后面学习Guava的框架有帮助。

参考:

J.U.C框架学习顺序

CAS与sun.misc.Unsafe

Doug Lea并发编程文章全部译文

J.U.C体系结构(java.util.concurrent)

JAVA并发编程J.U.C学习总结

J.U.C - AQS

可重入锁

ReentrantLock是可重入锁,可重入锁就是当前持有该锁的线程能够多次获取该锁,无需等待。可重入锁是如何实现的呢?这要从ReentrantLock的一个内部类Sync的父类说起,Sync的父类是AbstractQueuedSynchronizer(AQS,抽象队列同步器)。

AQS

AQS是JDK1.5提供的一个基于FIFO等待队列实现的一个用于实现同步器的基础框架,这个基础框架的重要性可以这么说,JCU包里面几乎所有的有关锁、多线程并发以及线程同步器等重要组件的实现都是基于AQS这个框架。AQS的核心思想是基于 volatileintstate这样的一个属性同时配合Unsafe工具对其原子性的操作来实现对当前锁的状态进行修改。当state的值为0的时候,标识该Lock不被任何线程所占有。

ReentrantLock锁的架构

ReentrantLock的架构主要包括一个Sync的内部抽象类以及Sync抽象类的两个实现类。他们的结构示意图如下:

如上图所示,AQS的父类AOS(AbstractOwnableSynchronizer)主要提供一个exclusiveOwnerThread属性,用于关联当前持有该锁的线程。  另外、Sync的两个实现类分别是NonfairSync和FairSync,一个是用于实现公平锁,一个是用于实现非公平锁。那么Sync为什么要被设计成内部类呢?Sync被设计成为安全的外部不可访问的内部类,使得ReentrantLock中所有涉及对AQS的访问都要经过Sync,其实,Sync被设计成为内部类主要是为了安全性考虑,这也是作者在AQS的comments上强调的一点。

AQS框架

总体框架图

如上图所示和前面所述,AQS维护了一个volatile int state域和一个FIFO线程等待队列(利用双向链表实现,多线程争用资源被阻塞时会进入此队列)。

域和方法

主要的域如下:

private transient volatile Node head; // 同步队列的head节点
private transient volatile Node tail; // 同步队列的tail节点
private volatile int state; // 同步状态

AQS提供的可以修改同步状态的3个方法

protected final int getState();  // 获取同步状态
protected final void setState(int newState);  // 设置同步状态
protected final boolean compareAndSetState(int expect, int update);  // CAS设置同步状态

这三种叫做均是原子操作,其中compareAndSetState的实现依赖于Unsafe的compareAndSwapInt()方法。代码实现如下:

private volatile int state;
protected final int getState() {   
    return state;
}
protected final void setState(int newState) {    
    state = newState;
}
protected final boolean compareAndSetState(int expect, int update) {    
    // See below for intrinsics setup to support this 
    return unsafe.compareAndSwapInt(this, stateOffset, expect, update);
}


目录
相关文章
|
2月前
|
安全 Java API
JAVA并发编程JUC包之CAS原理
在JDK 1.5之后,Java API引入了`java.util.concurrent`包(简称JUC包),提供了多种并发工具类,如原子类`AtomicXX`、线程池`Executors`、信号量`Semaphore`、阻塞队列等。这些工具类简化了并发编程的复杂度。原子类`Atomic`尤其重要,它提供了线程安全的变量更新方法,支持整型、长整型、布尔型、数组及对象属性的原子修改。结合`volatile`关键字,可以实现多线程环境下共享变量的安全修改。
|
13天前
|
存储 设计模式 分布式计算
Java中的多线程编程:并发与并行的深度解析####
在当今软件开发领域,多线程编程已成为提升应用性能、响应速度及资源利用率的关键手段之一。本文将深入探讨Java平台上的多线程机制,从基础概念到高级应用,全面解析并发与并行编程的核心理念、实现方式及其在实际项目中的应用策略。不同于常规摘要的简洁概述,本文旨在通过详尽的技术剖析,为读者构建一个系统化的多线程知识框架,辅以生动实例,让抽象概念具体化,复杂问题简单化。 ####
|
1月前
|
存储 消息中间件 安全
JUC组件实战:实现RRPC(Java与硬件通过MQTT的同步通信)
【10月更文挑战第9天】本文介绍了如何利用JUC组件实现Java服务与硬件通过MQTT的同步通信(RRPC)。通过模拟MQTT通信流程,使用`LinkedBlockingQueue`作为消息队列,详细讲解了消息发送、接收及响应的同步处理机制,包括任务超时处理和内存泄漏的预防措施。文中还提供了具体的类设计和方法实现,帮助理解同步通信的内部工作原理。
JUC组件实战:实现RRPC(Java与硬件通过MQTT的同步通信)
|
18天前
|
Java 数据库连接 数据库
如何构建高效稳定的Java数据库连接池,涵盖连接池配置、并发控制和异常处理等方面
本文介绍了如何构建高效稳定的Java数据库连接池,涵盖连接池配置、并发控制和异常处理等方面。通过合理配置初始连接数、最大连接数和空闲连接超时时间,确保系统性能和稳定性。文章还探讨了同步阻塞、异步回调和信号量等并发控制策略,并提供了异常处理的最佳实践。最后,给出了一个简单的连接池示例代码,并推荐使用成熟的连接池框架(如HikariCP、C3P0)以简化开发。
39 2
|
1月前
|
Java
【编程进阶知识】揭秘Java多线程:并发与顺序编程的奥秘
本文介绍了Java多线程编程的基础,通过对比顺序执行和并发执行的方式,展示了如何使用`run`方法和`start`方法来控制线程的执行模式。文章通过具体示例详细解析了两者的异同及应用场景,帮助读者更好地理解和运用多线程技术。
26 1
|
2月前
|
存储 缓存 安全
【Java面试题汇总】多线程、JUC、锁篇(2023版)
线程和进程的区别、CAS的ABA问题、AQS、哪些地方使用了CAS、怎么保证线程安全、线程同步方式、synchronized的用法及原理、Lock、volatile、线程的六个状态、ThreadLocal、线程通信方式、创建方式、两种创建线程池的方法、线程池设置合适的线程数、线程安全的集合?ConcurrentHashMap、JUC
【Java面试题汇总】多线程、JUC、锁篇(2023版)
|
2月前
|
Java API 容器
JAVA并发编程系列(10)Condition条件队列-并发协作者
本文通过一线大厂面试真题,模拟消费者-生产者的场景,通过简洁的代码演示,帮助读者快速理解并复用。文章还详细解释了Condition与Object.wait()、notify()的区别,并探讨了Condition的核心原理及其实现机制。
|
2月前
|
监控 Java 调度
【Java学习】多线程&JUC万字超详解
本文详细介绍了多线程的概念和三种实现方式,还有一些常见的成员方法,CPU的调动方式,多线程的生命周期,还有线程安全问题,锁和死锁的概念,以及等待唤醒机制,阻塞队列,多线程的六种状态,线程池等
132 6
【Java学习】多线程&JUC万字超详解
|
3月前
|
存储 Java
Java 中 ConcurrentHashMap 的并发级别
【8月更文挑战第22天】
52 5
|
3月前
|
缓存 Java 调度
【Java 并发秘籍】线程池大作战:揭秘 JDK 中的线程池家族!
【8月更文挑战第24天】Java的并发库提供多种线程池以应对不同的多线程编程需求。本文通过实例介绍了四种主要线程池:固定大小线程池、可缓存线程池、单一线程线程池及定时任务线程池。固定大小线程池通过预设线程数管理任务队列;可缓存线程池能根据需要动态调整线程数量;单一线程线程池确保任务顺序执行;定时任务线程池支持周期性或延时任务调度。了解并正确选用这些线程池有助于提高程序效率和资源利用率。
52 2