Java中锁的全面解析之类型、使用场景、优缺点及实现方式(示例代码)

 更新时间:2026年01月27日 10:52:15   作者:就这个丶调调  
本文将从锁的基本概念出发,详细讲解Java中常见的锁类型、它们的使用场景、优缺点以及底层实现原理,并通过代码示例帮助读者深入理解,感兴趣的朋友跟随小编一起看看吧

Java中锁的全面解析:类型、使用场景、优缺点及实现方式

在多线程编程中,锁是保证数据一致性和线程安全的核心机制。Java 提供了丰富的锁机制来应对不同的并发场景。本文将从锁的基本概念出发,详细讲解 Java 中常见的锁类型、它们的使用场景、优缺点以及底层实现原理,并通过代码示例帮助读者深入理解。

1. 锁的基本概念

锁是一种同步机制,用于控制多个线程对共享资源的访问。当一个线程获取锁后,其他线程必须等待该锁被释放才能继续执行,从而避免竞态条件(Race Condition)。

2. Java 中常见的锁类型

2.1 互斥锁(Mutex Lock)

特点:
  • 一次只允许一个线程持有锁。
  • 保证临界区的独占访问。
常见实现:
  • synchronized 关键字(内置锁)
  • ReentrantLock(可重入锁)
代码示例:使用 synchronized
public class Counter {
    private int count = 0;
    // 同步方法,使用对象锁(this)
    public synchronized void increment() {
        count++;
    }
    // 同步代码块,使用指定对象锁
    public void decrement() {
        synchronized (this) {
            count--;
        }
    }
    public int getCount() {
        return count;
    }
}
优点:
  • 简单易用,无需手动释放锁。
  • JVM 自动管理锁的获取与释放。
缺点:
  • 无法中断等待中的线程。
  • 不能设置超时时间。
  • 只能是非公平锁(默认)。

2.2 可重入锁(Reentrant Lock)

特点:
  • 支持同一个线程多次获取同一把锁(即“可重入”)。
  • 提供更灵活的控制能力。
代码示例:使用 ReentrantLock
import java.util.concurrent.locks.ReentrantLock;
public class ReentrantExample {
    private final ReentrantLock lock = new ReentrantLock();
    private int count = 0;
    public void increment() {
        lock.lock();
        try {
            count++;
            // 可以再次获取锁(可重入)
            if (count == 1) {
                System.out.println("Thread " + Thread.currentThread().getName() + " is re-entering the lock.");
            }
        } finally {
            lock.unlock();
        }
    }
    public int getCount() {
        lock.lock();
        try {
            return count;
        } finally {
            lock.unlock();
        }
    }
}
优点:
  • 支持可中断的锁获取(lockInterruptibly())。
  • 支持超时锁获取(tryLock(timeout))。
  • 支持公平锁和非公平锁(通过构造函数选择)。
缺点:
  • 必须手动释放锁,容易忘记 unlock() 导致死锁。
  • 语法比 synchronized 复杂。

2.3 读写锁(ReadWriteLock)

特点:
  • 分离读操作和写操作的锁。
  • 多个读线程可以同时访问共享资源,但写操作必须独占。
常见实现:ReentrantReadWriteLock
代码示例:读写锁的应用
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
public class ReadWriteExample {
    private final ReadWriteLock lock = new ReentrantReadWriteLock();
    private String data = "Default";
    // 读操作:多个线程可同时读
    public String readData() {
        lock.readLock().lock();
        try {
            System.out.println(Thread.currentThread().getName() + " is reading data: " + data);
            return data;
        } finally {
            lock.readLock().unlock();
        }
    }
    // 写操作:独占访问,其他读写均被阻塞
    public void writeData(String newData) {
        lock.writeLock().lock();
        try {
            System.out.println(Thread.currentThread().getName() + " is writing data: " + newData);
            data = newData;
        } finally {
            lock.writeLock().unlock();
        }
    }
}
优点:
  • 读多写少的场景下性能显著提升(减少锁竞争)。
  • 提高并发效率。
缺点:
  • 写操作会阻塞所有读操作,可能导致“写饥饿”(Writer Starvation)。
  • 逻辑复杂度增加。

2.4 原子锁(Atomic Lock)

特点:
  • 使用原子操作(CAS)实现无锁编程。
  • 避免传统锁带来的上下文切换开销。
常见类:AtomicInteger,AtomicReference,StampedLock(分段锁)
代码示例:使用 AtomicInteger
import java.util.concurrent.atomic.AtomicInteger;
public class AtomicCounter {
    private final AtomicInteger count = new AtomicInteger(0);
    public void increment() {
        count.incrementAndGet(); // CAS 操作,原子递增
    }
    public int getCount() {
        return count.get();
    }
}
优点:
  • 无锁机制,避免线程阻塞。
  • 性能高,适合高并发场景。
缺点:
  • 无法处理复杂的复合操作(如“读-修改-写”)。
  • 存在 ABA 问题(可通过 AtomicStampedReference 解决)。

2.5 StampedLock(戳记锁)

特点:
  • JDK 8 引入,支持乐观读锁(Optimistic Read)。
  • 读写分离,支持读写锁和乐观读锁三种模式。
代码示例:StampedLock 用法
import java.util.concurrent.locks.StampedLock;
public class StampedLockExample {
    private final StampedLock stampedLock = new StampedLock();
    private double x, y;
    // 乐观读:不加锁,先尝试读取,失败则升级为悲观读
    public double distanceFromOrigin() {
        long stamp = stampedLock.tryOptimisticRead();
        double currentX = x, currentY = y;
        // 检查是否在读期间发生了写操作(版本变化)
        if (!stampedLock.validate(stamp)) {
            stamp = stampedLock.readLock();
            try {
                currentX = x;
                currentY = y;
            } finally {
                stampedLock.unlockRead(stamp);
            }
        }
        return Math.sqrt(currentX * currentX + currentY * currentY);
    }
    // 写操作:独占锁
    public void move(double deltaX, double deltaY) {
        long stamp = stampedLock.writeLock();
        try {
            x += deltaX;
            y += deltaY;
        } finally {
            stampedLock.unlockWrite(stamp);
        }
    }
}
优点:
  • 读操作性能极高(乐观读无需阻塞)。
  • 适用于读多写少且对读性能要求极高的场景。
缺点:
  • API 复杂,需要显式验证版本。
  • 容易出错(如忘记验证或释放锁)。

3. 锁的使用场景总结

锁类型适用场景推荐程度
synchronized简单同步,小范围临界区⭐⭐⭐⭐⭐
ReentrantLock需要超时、中断、公平性控制⭐⭐⭐⭐☆
ReentrantReadWriteLock读多写少的共享数据⭐⭐⭐⭐☆
AtomicXXX简单计数器、状态标志⭐⭐⭐⭐⭐
StampedLock极高读性能需求,读多写少⭐⭐⭐☆☆

4. 锁的底层实现原理(简述)

  • synchronized:基于 JVM 的对象头(Mark Word)实现,通过 Monitor 机制管理锁状态。
  • ReentrantLock:基于 AQS(AbstractQueuedSynchronizer)实现,使用 CAS+FIFO 队列管理线程排队。
  • StampedLock:基于版本戳(Stamp)和状态位管理,支持乐观读。

5. 最佳实践建议

  1. 优先使用 synchronized,除非有特殊需求。
  2. 避免在 finally 块外调用 unlock(),防止死锁。
  3. 读写锁适用于读多写少的场景,避免“写饥饿”。
  4. 原子类适合简单操作,复杂逻辑仍需锁保护。
  5. StampedLock 适合高性能读场景,但需谨慎使用。

6. 结语

锁是 Java 并发编程的核心,合理选择锁类型能极大提升程序性能与稳定性。掌握不同锁的特点与适用场景,是成为一名高级 Java 工程师的必经之路。希望本文能为你提供清晰的指导!

到此这篇关于Java中锁的全面解析之类型、使用场景、优缺点及实现方式(示例代码)的文章就介绍到这了,更多相关java锁使用内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • java List中相同的数据合并到一起

    java List中相同的数据合并到一起

    这篇文章主要介绍了java List中相同的数据合并到一起,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2023-07-07
  • SpringBoot日志信息以及Lombok的常用注解详析

    SpringBoot日志信息以及Lombok的常用注解详析

    日志在我们的日常开发当中是必定会用到的,这篇文章主要给大家介绍了关于SpringBoot日志信息以及Lombok的常用注解的相关资料,文中通过代码介绍的非常详细,需要的朋友可以参考下
    2023-12-12
  • Java随机生成字符串的四种方式例子

    Java随机生成字符串的四种方式例子

    这篇文章主要给大家介绍了关于Java随机生成字符串的四种方式,随机数在实际中使用很广泛,比如要随即生成一个固定长度的字符串、数字,文中给出了详细的代码示例,需要的朋友可以参考下
    2023-10-10
  • Java 中的 clone( ) 和 new哪个效率更高

    Java 中的 clone( ) 和 new哪个效率更高

    很多朋友不太清楚clone()和new那个更快?针对这个问题我百度了好多资料,最终小编总结下关于Java 中的 clone( ) 和 new哪个效率更高的问题,感兴趣的朋友跟随小编一起看看吧
    2021-12-12
  • mybatis自定义参数类型转换器数据库字段加密脱敏

    mybatis自定义参数类型转换器数据库字段加密脱敏

    这篇文章主要为大家介绍了mybatis自定义参数类型转换器数据库字段加密脱敏,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-09-09
  • java控制台输出版多人聊天室

    java控制台输出版多人聊天室

    这篇文章主要为大家详细介绍了java控制台输出版多人聊天室,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-09-09
  • java对象初始化顺序验证示例

    java对象初始化顺序验证示例

    以下这段小程序对调用对象构造函数时,父类构造函数、成员变量初始化函数,以及非静态初始化块调用顺序进行验证,不考虑静态成员及静态初始化块
    2014-02-02
  • Mybatis 级联删除的实现

    Mybatis 级联删除的实现

    这篇文章主要介绍了Mybatis 级联删除的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-11-11
  • IDEA代码警告(warning)整理以及解决方案

    IDEA代码警告(warning)整理以及解决方案

    在日常开发中,IntelliJ IDEA会通过problems窗口和编辑窗口的黄色标记提示警告,这些警告可能指示代码存在潜在风险或需要优化的空间,文章介绍了如何利用IDEA检查代码,以及针对常见警告的原因和解决办法
    2024-10-10
  • JavaWeb入门教程之分页查询功能的简单实现

    JavaWeb入门教程之分页查询功能的简单实现

    这篇文章主要介绍了JavaWeb入门教程之分页查询功能的简单实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-11-11

最新评论