Java 中常见的锁与最佳实践

 更新时间:2026年03月11日 08:57:34   作者:数据  
本文介绍了Java中常见的锁,包括语法/实现层面的synchronized关键字、Lock接口及其实现类,讨论了锁的特性、常见误区与最佳实践,感兴趣的朋友跟随小编一起看看吧

Java 中的锁可以从多个维度来划分,常见的锁包括:

  • 语法/实现层面:synchronized 关键字(内置锁)、Lock 接口及其实现类(如 ReentrantLockReentrantReadWriteLockStampedLock)。
  • 特性层面:可重入锁、公平锁/非公平锁、读写锁、乐观锁/悲观锁、自旋锁、分段锁等。
  • 并发工具包中的辅助锁:Semaphore(信号量,可看作共享锁)、CountDownLatchCyclicBarrier 等虽不是严格意义上的锁,但也用于控制线程协作。

下面我们从最常用的几个维度展开聊聊。

1. 从语法和 API 层面看

synchronized(内置锁)

  • 使用方式:修饰实例方法、静态方法或代码块。
  • 原理:基于对象头的 Mark Word 和 monitor 对象实现。JDK 1.6 以后引入了偏向锁、轻量级锁、重量级锁的升级过程,以优化性能。
  • 特点:使用简单,自动释放锁(异常或正常退出时),可重入。但无法中断等待锁的线程,也无法设置超时。
  • 最佳实践:适用于锁的竞争不激烈、代码简单的情况。比如单例模式的同步方法、简单的线程安全计数器。

Lock接口(显式锁)

最核心的实现是 ReentrantLock,它提供了比 synchronized 更灵活的锁操作。

  • ReentrantLock
  • 示例:
ReentrantLock lock = new ReentrantLock(true); // 公平锁
lock.lock();
try {
    // 临界区
} finally {
    lock.unlock(); // 必须手动释放
}
  • 可重入:同一个线程可以多次获得同一把锁。
  • 公平/非公平:构造函数可指定是否公平。公平锁按线程等待顺序获取锁,非公平锁允许插队(默认非公平,吞吐量更高)。
  • 可中断:lockInterruptibly() 允许在等待锁时响应中断。
  • 超时获取:tryLock(long time, TimeUnit unit) 可以指定等待时间。
  • 配合 Condition:可实现多个等待/通知条件,比 wait/notify 更精细。
  • ReentrantReadWriteLock
  • 维护一对锁:读锁(共享)和写锁(排他)。读多写少场景下可大幅提升并发度。
  • 读锁可以被多个读线程同时持有,但写锁独占,且读写互斥。
  • 可能出现“写饥饿”问题,但在非公平模式下,写锁优先级通常较高。
  • StampedLock(JDK 8 引入)
  • 进一步优化读多写少场景,支持三种模式:写锁、读锁、乐观读。
  • 乐观读:不加锁,直接读取数据,之后通过 validate 检查是否有写操作发生。若无效再升级为读锁重读。
  • 特点:不可重入,不支持条件变量,适合读线程远多于写线程的场景。

2. 从锁的特性层面看

  • 悲观锁 vs 乐观锁
    • 悲观锁:假设并发冲突概率高,每次操作都加锁(如 synchronized、ReentrantLock)。适合写多场景。
    • 乐观锁:假设冲突少,先操作,提交时用 CAS(Compare And Swap)检测冲突,冲突则重试。如 java.util.concurrent.atomic 包下的原子类。适合读多写少、冲突概率低的场景。
  • 可重入锁
    • 同一线程可以重复获取同一把锁,避免死锁。Java 中的 synchronized 和 ReentrantLock 都是可重入的。
  • 公平锁 vs 非公平锁
    • 公平锁按线程请求锁的顺序获取锁,避免饥饿,但吞吐量较低;非公平锁允许插队,吞吐量更高,但可能导致某些线程长时间得不到锁。
  • 自旋锁
    • 线程获取锁失败时不立即挂起,而是循环尝试(自旋),减少线程上下文切换的开销。适合锁持有时间短的场景。JDK 内部大量使用了自旋锁(如 ConcurrentLinkedQueue 的入队操作)。Java 中也提供了 AbstractQueuedSynchronizer(AQS)对自旋和阻塞的支持。
  • 分段锁
    • ConcurrentHashMap 在 JDK 1.7 中的实现,将数据分段,每段一把锁,降低锁粒度,提升并发度。JDK 1.8 改用 CAS + synchronized 对每个桶(数组元素)加锁,相当于进一步细化。

3. 并发工具包中的 “锁” 变体

  • Semaphore:计数信号量,可以控制同时访问资源的线程数量(共享锁)。比如限流场景。
  • CountDownLatch:让一个或多个线程等待,直到一组操作完成。
  • CyclicBarrier:让一组线程互相等待,到达某个屏障点后再同时执行。

虽然这些不是传统意义上的锁,但它们也常被用来解决线程协作问题,面试时可以作为补充提及。

常见误区与最佳实践

  • 误区一:认为 synchronized 性能总比 ReentrantLock 差。实际上 JDK 1.6 以后 synchronized 经过优化,性能与 ReentrantLock 差距不大,甚至在低竞争时更好。选择时应更关注功能需求。
  • 误区二:滥用读写锁。如果读操作很短,或者写操作频繁,读写锁可能不如普通互斥锁,因为维护读锁和写锁本身也有开销。
  • 误区三:忘记在 finally 中释放显式锁。这是新手最容易犯的错误,可能导致死锁。
  • 最佳实践:
    • 优先使用 synchronized,简洁安全;需要高级功能(如可中断、超时、公平性、多 Condition)时才选用 ReentrantLock。
    • 读多写少且数据一致性要求不那么极致时,可考虑 StampedLock 的乐观读模式,或使用 CopyOnWrite 容器。
    • 对于简单的原子操作,优先使用 Atomic 系列类(乐观锁思想),避免锁开销。
    • 了解 JVM 的锁优化(如偏向锁、轻量级锁),有助于调优高并发应用。

到此这篇关于Java 中常见的锁有哪些?的文章就介绍到这了,更多相关java常见锁内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Java网络通信中URL与HTTP编程技术详解

    Java网络通信中URL与HTTP编程技术详解

    要想实现网络编程,除了可以使用Socket之外,我们还可以利用URL编程或HTTP编程技术,所以今天这篇文章,就给大家介绍一下URL编程和HTTP编程技术,看看这两种技术有什么特点,文中有详细的代码讲解,需要的朋友可以参考下
    2023-11-11
  • Java中接收键盘输入的三种方法

    Java中接收键盘输入的三种方法

    这篇文章主要介绍了Java中接收键盘输入的三种方法,本文给出3个方法实现通过读取控制台的输入与用户实现交互,需要的朋友可以参考下
    2015-06-06
  • idea导入gradle项目时遇到的坑及解决

    idea导入gradle项目时遇到的坑及解决

    这篇文章主要介绍了idea导入gradle项目时遇到的坑及解决,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2025-04-04
  • 详解基于JWT的springboot权限验证技术实现

    详解基于JWT的springboot权限验证技术实现

    这篇文章主要介绍了详解基于JWT的springboot权限验证技术实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-11-11
  • Java多线程批量数据导入的方法详解

    Java多线程批量数据导入的方法详解

    这篇文章主要介绍了Java多线程批量数据导入的方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,下面小编和大家来一起学习下吧
    2019-06-06
  • spring data jpa开启批量插入、批量更新的问题解析

    spring data jpa开启批量插入、批量更新的问题解析

    这篇文章主要介绍了spring data jpa开启批量插入、批量更新问题,本文通过图文实例相结合给大家介绍的非常详细,需要的朋友可以参考下
    2021-07-07
  • SpringBoot使用自定义注解实现权限拦截的示例

    SpringBoot使用自定义注解实现权限拦截的示例

    本篇文章主要介绍了SpringBoot使用自定义注解实现权限拦截的示例,具有一定的参考价值,有兴趣的可以了解一下
    2017-09-09
  • 如何在Spring data中使用r2dbc详解

    如何在Spring data中使用r2dbc详解

    这篇文章主要给大家介绍了关于如何在Spring data中使用r2dbc的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-11-11
  • RocketMQ的消费者类型与最佳实践详解

    RocketMQ的消费者类型与最佳实践详解

    这篇文章主要介绍了RocketMQ的消费者类型与最佳实践详解,在 RocketMQ 5.0 中,更加强调了客户端类型的概念,尤其是消费者类型,为了满足多样的 RocketMQ 中一共有三种不同的消费者类型,分别是 PushConsumer、SimpleConsumer 和 PullConsumer,需要的朋友可以参考下
    2023-10-10
  • SpringSecurity 默认表单登录页展示流程源码

    SpringSecurity 默认表单登录页展示流程源码

    本篇主要讲解 SpringSecurity提供的默认表单登录页 它是如何展示流程,本文图文并茂给大家介绍的非常详细,具有一定的参考借鉴价值,需要的朋友参考下吧
    2020-01-01

最新评论