JUC 核心组件全景:Lock、Atomic、AQS!
开篇语
哈喽,各位小伙伴们,你们好呀,我是喵手。运营社区:C站/掘金/腾讯云/阿里云/华为云/51CTO;欢迎大家常来逛逛
今天我要给大家分享一些自己日常学习到的一些知识点,并以文字的形式跟大家一起交流,互相学习,一个人虽可以走的更快,但一群人可以走的更远。
我是一名后端开发爱好者,工作日常接触到最多的就是Java语言啦,所以我都尽量抽业余时间把自己所学到所会的,通过文章的形式进行输出,希望以这种方式帮助到更多的初学者或者想入门的小伙伴们,同时也能对自己的技术进行沉淀,加以复盘,查缺补漏。
小伙伴们在批阅的过程中,如果觉得文章不错,欢迎点赞、收藏、关注哦。三连即是对作者我写作道路上最好的鼓励与支持!
前言
JUC(Java Util Concurrent)是 Java 并发编程中的重要组成部分,提供了一系列核心组件,帮助开发者高效地进行多线程和并发控制。JUC 中有三个非常重要的核心组件:Lock、Atomic 和 AQS,它们在并发控制、资源共享、任务同步等方面起着关键作用。
在深入了解这三个组件之前,我们需要先对 Java 并发编程的基本概念有一个清晰的认识。Java 并发编程面临的挑战主要包括线程同步、资源共享的安全性、以及性能的优化。JUC 提供的这些核心组件,正是为了解决这些问题,提供了更加灵活且高效的解决方案。
一、Lock(锁)
Lock 是 Java 并发编程中的基础工具之一,旨在替代传统的 synchronized 关键字,它提供了更细粒度的控制和更好的性能。Lock 接口定义了与锁相关的基本操作,如加锁、解锁等。
1.1 Lock 的核心特点
- 可重入:
ReentrantLock是一种常见的 Lock 实现,它允许线程多次获得同一个锁。 - 可中断的加锁:可以在等待锁时响应中断,这在某些需要超时控制或希望响应中断的场景中非常有用。
- 公平性控制:
ReentrantLock提供了公平锁(Fair Lock)的实现。公平锁保证了锁的获取顺序是按照线程请求锁的顺序来分配的,从而避免了某些线程“饥饿”的问题。 - 锁的细粒度控制:通过
lock()和unlock()方法,Lock 可以更精细地控制加锁与释放锁的时机,避免死锁等问题。
1.2 常见实现类
- ReentrantLock:实现了
Lock接口,提供了可重入、可中断、可公平的锁。 - ReadWriteLock:为读写锁提供支持,允许多个线程同时读取共享资源,但在写操作时,独占资源。
1.3 典型示例
import java.util.concurrent.locks.ReentrantLock;
public class LockExample {
private final ReentrantLock lock = new ReentrantLock();
public void doSomething() {
lock.lock(); // 加锁
try {
// 执行代码
System.out.println("Executing task with lock");
} finally {
lock.unlock(); // 解锁
}
}
}
二、Atomic(原子操作)
Atomic 是 JUC 中的一组类,提供了对共享变量的原子操作,确保了多线程环境下的操作是线程安全的。原子操作意味着在多线程的环境中,某个操作要么完全执行,要么完全不执行,中间不会被其他线程打断。
2.1 Atomic 类的核心特点
- 原子性保证:Atomic 类通过底层硬件的支持(例如 CAS,Compare And Swap)来保证操作的原子性,避免了使用
synchronized的开销。 - 无锁操作:Atomic 类通常采用无锁的算法,能显著提高性能,尤其是在高并发环境下。
- 支持常见的数据类型:Java 提供了多种原子类,如
AtomicInteger、AtomicLong、AtomicReference等,适用于不同的数据类型。
2.2 典型类与方法
- AtomicInteger:提供了对整数类型的原子操作。
- AtomicLong:提供了对长整型的原子操作。
- AtomicReference:提供了对对象引用的原子操作。
- CAS(Compare And Swap):通过 CAS 算法实现无锁的原子更新操作。
2.3 典型示例
import java.util.concurrent.atomic.AtomicInteger;
public class AtomicExample {
private AtomicInteger counter = new AtomicInteger(0);
public void increment() {
counter.incrementAndGet(); // 原子性加1
}
public int getCounter() {
return counter.get(); // 获取原子变量的值
}
}
三、AQS(AbstractQueuedSynchronizer)
AQS 是 Java 并发工具中的一个重要抽象类,它为许多并发控制工具(如 ReentrantLock、CountDownLatch、Semaphore)提供了底层支持。AQS 通过队列的方式来管理线程对资源的争用,线程请求资源时会被挂起,直到资源可用时才被唤醒。
3.1 AQS 的核心特点
- 状态管理:AQS 通过维护一个共享的状态(如一个整数值),来表示资源的占用情况。
- 队列管理:AQS 使用一个 FIFO(先进先出)队列来管理所有等待资源的线程。
- 支持公平与非公平:AQS 可以通过公平队列机制来保证资源分配的顺序,或者采用非公平的方式提高吞吐量。
3.2 典型子类与应用
- ReentrantLock:继承了 AQS,利用它来管理线程对锁的竞争。
- CountDownLatch:通过 AQS 实现,允许线程等待其他线程完成操作。
- Semaphore:通过 AQS 实现的信号量,控制多个线程对资源的访问。
- CyclicBarrier:允许一组线程在执行到某个步骤时相互等待,直到所有线程都达到某个条件。
3.3 典型示例
import java.util.concurrent.locks.AbstractQueuedSynchronizer;
public class AQSExample extends AbstractQueuedSynchronizer {
@Override
protected boolean tryAcquire(int acquires) {
// 自定义获取锁的方式
return compareAndSetState(0, acquires); // 比较并设置状态
}
@Override
protected boolean tryRelease(int releases) {
// 自定义释放锁的方式
setState(0); // 释放锁,设置状态为0
return true;
}
public static void main(String[] args) {
AQSExample sync = new AQSExample();
// 使用 AQS 实现同步控制
}
}
四、如何选择合适的组件?
- Lock:当需要对资源进行精细化控制,特别是需要避免死锁、支持可中断和公平性时,
Lock适用。它比synchronized提供了更多的功能和灵活性。 - Atomic:当对简单的共享变量进行操作时,
Atomic类提供了一种高效且无锁的解决方案,适用于计数器、标志位等场景。 - AQS:当需要实现复杂的同步控制机制时(例如自定义锁、信号量、计数器等),可以基于 AQS 来实现更高层次的并发控制。
结语
在 Java 并发编程中,Lock、Atomic 和 AQS 是三大核心组件,各自有不同的应用场景和优势。通过理解它们的工作原理和使用场景,开发者可以根据需求选择合适的组件,从而有效提高程序的并发性能。掌握这些工具,不仅可以让你编写出高效、可靠的并发程序,还能让你在多线程编程的世界里游刃有余!💡
… …
文末
好啦,以上就是我这期的全部内容,如果有任何疑问,欢迎下方留言哦,咱们下期见。
… …
学习不分先后,知识不分多少;事无巨细,当以虚心求教;三人行,必有我师焉!!!
wished for you successed !!!
⭐️若喜欢我,就请关注我叭。
⭐️若对您有用,就请点赞叭。
⭐️若有疑问,就请评论留言告诉我叭。
版权声明:本文由作者原创,转载请注明出处,谢谢支持!
- 点赞
- 收藏
- 关注作者
评论(0)