• 深入理解Java并发锁


    图片

    在Java中,并发锁是用来控制多个线程对共享资源的访问,确保数据的一致性和完整性。Java提供了多种并发锁机制,包括内置锁(synchronized)、显示锁(如ReentrantLock)、原子变量、并发容器以及一些高级技巧如乐观锁和String.intern()等。

    1. synchronized关键字

    特点:

    synchronized是Java内建的锁机制,它提供了隐式锁,也称为内部锁或监视器锁。

    当一个线程获得对象的锁后,其他试图获取该锁的线程将会被阻塞,直到锁被释放。

    实现原理:

    每个对象都有一个内置锁和一个计数器。当线程请求锁时,JVM将计数器加一。

    如果线程已经持有锁,计数器会再次增加,这允许同一个线程多次同步。

    当线程完成同步代码块时,计数器减一。当计数器为零时,锁被释放。

    使用场景:

    适用于方法或代码块的简单同步。

    优点:

    简单易用,不需要手动释放锁。

    缺点:

    不能被中断;不支持公平性;无法设置超时。

    代码示例:

    1. public class SynchronizedExample {
    2. private Object lock = new Object();
    3. public void method() {
    4. synchronized (lock) {
    5. // 临界区代码
    6. }
    7. }
    8. }

    2. ReentrantLock

    特点:

    ReentrantLock是一个可重入互斥锁,由java.util.concurrent.locks包提供。

    支持公平锁和非公平锁。

    实现原理:

    基于AbstractQueuedSynchronizer(AQS)框架实现。

    维护了一个状态变量来跟踪锁的状态。

    使用场景:

    适用于需要高度自定义和灵活的同步控制的场景。

    优点:

    高度灵活,支持中断、超时、公平性。

    缺点:

    必须手动释放锁,否则可能导致死锁。

    代码示例:

    1. import java.util.concurrent.locks.ReentrantLock;
    2. public class ReentrantLockExample {
    3. private final ReentrantLock lock = new ReentrantLock();
    4. public void method() {
    5. lock.lock();
    6. try {
    7. // 临界区代码
    8. } finally {
    9. lock.unlock();
    10. }
    11. }
    12. }

    图片

    3. ReadWriteLock

    特点:

    允许多个读线程同时访问,但只允许一个写线程。

    读写锁通常用于读多写少的场合。

    实现原理:

    通过两个锁来实现:一个读锁和一个写锁。

    读锁是共享的,写锁是独占的。

    使用场景:

    适用于读多写少的数据结构,如缓存系统。

    优点:

    提高并发性能,减少锁竞争。

    缺点:

    写操作可能会饥饿,如果读操作持续不断。

    代码示例:

    1. import java.util.concurrent.locks.ReadWriteLock;
    2. import java.util.concurrent.locks.ReentrantReadWriteLock;
    3. public class ReadWriteLockExample {
    4. private final ReadWriteLock rwLock = new ReentrantReadWriteLock();
    5. public void read() {
    6. rwLock.readLock().lock();
    7. try {
    8. // 读操作代码
    9. } finally {
    10. rwLock.readLock().unlock();
    11. }
    12. }
    13. public void write() {
    14. rwLock.writeLock().lock();
    15. try {
    16. // 写操作代码
    17. } finally {
    18. rwLock.writeLock().unlock();
    19. }
    20. }
    21. }

    4. StampedLock

    特点:

    StampedLock支持乐观读、悲观读、写锁和锁的升级。

    它提供了一个版本号来避免不必要的唤醒。

    实现原理:

    使用了一种称为“乐观读”的技术,通过标记来避免长时间的等待。

    使用CAS操作来尝试获取和释放锁。

    使用场景:

    适用于高并发且读多写少的场景。

    优点:

    高性能,特别是在高并发环境下。

    缺点:

    相对复杂,需要更小心地管理状态。

    代码示例:

    1. import java.util.concurrent.locks.StampedLock;
    2. public class StampedLockExample {
    3. private final StampedLock stampedLock = new StampedLock();
    4. public void method() {
    5. long stamp = stampedLock.writeLock();
    6. try {
    7. // 临界区代码
    8. } finally {
    9. stampedLock.unlockWrite(stamp);
    10. }
    11. }
    12. }

    5. Semaphore、CountDownLatch和CyclicBarrier

    这三个工具类虽然不是锁,但它们常用于多线程的同步控制。

    Semaphore: 控制同时访问特定资源的线程数量。适用于限制并发线程数。

    CountDownLatch: 允许一个或多个线程等待其他线程完成操作。适用于等待一组线程完成任务后再执行的场景。

    CyclicBarrier: 允许一组线程相互等待,直到所有线程都准备好再同时执行。适用于多线程计算数据的场景。

    总结

    Java提供了丰富的并发锁和同步工具,以满足不同的并发需求。从简单的synchronized到复杂的StampedLock,每种锁都有其适用场景和特定的优缺点。了解这些并发工具的原理和使用方式对于编写高效且线程安全的Java程序至关重要。在实际开发中,选择合适的锁取决于具体的需求、性能考虑以及代码的复杂性。

    图片

  • 相关阅读:
    k8s教程:使用cert-manager证书管理工具在集群中提供https证书并自动续期
    K8s之Replicaset控制器详解
    通达OA V12版,引入thinkphp5.1框架,及获取session
    能直接运营的发接任务平台小程序搭建开发演示
    直播预告丨中高频多因子库存储的最佳实践
    B站刘二大人-数据集及数据加载 Lecture 8
    Java核心知识点十万字最强总结(从基础到高级,Java的核心知识点的上篇,全部都是精华)
    深度学习--神经网络基础
    使用soapUI获取webservice接口的调用格式
    Java Heap Space问题解析与解决方案(InsCode AI 创作助手)
  • 原文地址:https://blog.csdn.net/weixin_40381772/article/details/139858488