Java线程里的14种锁

article/2025/10/20 18:49:27

 参考资料:

  1. 不可不说的Java“锁”事
  2. java多线程的15种锁

以下内容是参考上面两片文章写出的粗略总结, 想要细究可以看上面两位大佬写的文章, 由于是参考着写的, 所以有很多地方相同, 如果有侵权或不妥的地方还请联系删除.


一. 线程是否同步资源?

1. 悲观锁 : 同步

每次拿数据都按照 最坏 的情况来定, 认为一定会有别的线程过来修改, 所以每次拿数据之前都会先上锁, 这样别的线程要想来拿这个数据的时候就会被阻塞, 直到这个线程解锁. 

部分锁实现: 

synchronized 的实现就是悲观锁, 主要用于多写的场景, 可以确保数据同步正确

存在的部分问题: 

  • 线程持有该锁会导致其他需要此锁的线程阻塞
  • 竞争强烈的情况下, 不断的加锁和解锁都会影响cpu的调度从而出现性能问题
  • 如果一个优先级高的线程等待一个优先级低的线程释放锁会导致优先级倒置从而出现性能问题

2. 乐观锁 : 不同步

每次拿数据都按照 最好 的情况来定, 认为不会有别的线程过来修改, 所以每次拿数据之前都不会上锁, 但是会在更新数据的时候判断有没有别的线程去修改了这个数据.

部分锁实现: 

CAS算法, 主要用于多读的场景, 以此来提高数据的吞吐量

存在的部分问题: 

  • CAS只能保证单个变量操作的原子性,当涉及到多个变量时,CAS是无能为力的
  • 乐观锁在执行更新时频繁失败,就需要不断重试,从而浪费cpu资源
  • ABA问题

CAS (Compare And Swap) 比较和交换 : 用来保证数据操作的原子性

CAS包含了三个值: 

需要读写的内存值 V

进行比较的值 A

要写入的新值 B

一条线程想要对V修改为B, 那么在进程刚进入的时候就会让A=V, 然后在修改之前会进行判断, 如果此时的A==V, 那么就说明没有线程对V的值进行修改, 就会把B赋值给V, 如果出现了A!=V的情况, 就说明了有其他线程对V的值进行了修改, 那么就不会进行赋值, 而是会不断的自旋, 直到V==A.

但是CAS算法也存在一个非常明显的问题, 即:

ABA问题

ABA又是什么呢? 例如, 线程把数据从A修改为了B, 然后又把B修改成了A, 这样另一条线程读取的时候, 就会误认为数据一直是A, 没有变化, 从而忽略了过程.

但是ABA问题的解决方法也非常的简单: AtomicStampedReference

即在每次修改的时候添加一个版本号, 每次更新的时候都把版本号增加, 以此来解决ABA问题.

二. 同步资源失败, 是否要阻塞?

1. 阻塞

当一个线程在获取锁的时候, 如果该锁已被其他线程获取了, 那么该线程会切换至阻塞状态, 直到被唤醒.

2. 自旋锁 : 不阻塞

当一个线程在获取锁的时候, 如果该锁已被其他线程获取了, 那么该线程会进入一个循环自旋的状态, 不断尝试重新获取, 直到成功, 自旋锁的实现原理也来自CAS.

存在的部分问题:

  • 虽然避免了切换线程状态的开销, 但是它要占用cpu的时间, 如果长时间的自旋会白白浪费cpu的调度

3. 适应性自旋锁 : 不阻塞

适应性自旋锁是在jdk1.6之后引入的, 意味着自旋的次数将不再固定, 而是由上一次在该锁上的自旋时间和拥有者的状态共同决定的, 即如果有一个线程刚获得过该锁, 并且该线程还在运行中, 那么虚拟机就会认为这次自旋成功的概率也很大, 从而允许它自旋更长的时间, 反之如果一个某个锁, 很少被线程成功获得过, 那么对应的就会减少获取该锁线程的自旋时间甚至直接进入阻塞状态, 从而来避免cpu资源浪费.

三. 多个线程竞争同步资源的流程细节

这四种锁匙指锁的状态, 专门针对synchronized的

1. 无锁

没有锁住资源, 所有线程都能访问并修改同个资源, 但同一时间里只有一个能修改资源成功, 其他线程会循环重试, 直至修改成功.

CAS的原理就是无锁的实现, 无锁无法全面替换有锁, 但无锁在某些场合下的性能非常高.

2. 偏向锁

指一段同步代码一直被一个线程访问, 那么该线程会自动获取锁, 降低获取锁的代价.

大多数情况下, 锁总是由同一线程多次获得, 不存在多线程竞争, 所以出现了偏向锁, 其目的就是为了提高只有一条线程执行同步代码块的时候能够提高效率, 偏向锁只在遇到其他线程尝试竞争偏向锁的时候, 持有偏向锁的线程才会释放锁.

3. 轻量级锁

当偏向锁被另外的线程访问时, 就会升级为轻量级锁, 其他线程会通过自旋的形式来尝试获取锁, 不会阻塞, 从而提高性能.

4. 重量级锁

当轻量级锁的自旋超过一定次数, 或者又有第三个线程来拿锁的时候, 就会升级成重量级锁, 此时在等待锁的所有线程都会进入阻塞状态

四. 多个线程竞争时是否要排队

1. 公平锁 : 排队

指多个线程安装申请锁的顺序来获取锁, 线程直接进入队列中排队. 优点是等待锁的线程不会饿死, 缺点时整体吞吐效率相对非公平锁要低, 队列中除了第一个线程, 其他线程都会进入阻塞状态, CPU唤醒阻塞线程的开销比非公平锁大.

2. 不公平锁 : 不排队

指多个线程加锁时可以直接尝试获取该锁, 获取不到才会进入队列排队, 但如果刚好锁可用, 则会直接插队获取锁, 无须阻塞等待, 所以非公平可能会出现后申请先获得的情况. 非公平锁优点是可以减少唤醒线程的开销, 整体吞吐量高, 但是缺点也会导致等待队列中的线程要等待很久才会获得锁, 或者饿死.

公平锁和非公平锁的源代码中唯一的区别就在于公平锁在获取锁的时候多了一个限制条件: hasQueuedPredecessors(), 用于判断当前线程是否处于队列的第一个.

五. 一个线程中的多个流程能否获取同把锁

1. 可重入锁 : 能

指同一个线程在外层方法获取锁的时候, 再进入该线程的内层方法时, 会自动获取锁 (前提得是同一个锁对象), 不会因为外层已经获取过且还没有释放而导致阻塞.

部分锁实现:

ReentrantLock和synchronized都是可重入锁, 优点是可以一定程度上避免死锁的出现

2. 不可重入锁 : 不能

不可重入锁与之对立, 当同一个线程在外层获取到锁的时候, 再进入内层, 会导致内层一直在等待外层释放锁, 而外层又在等待内层执行, 无法释放锁, 从而出现死锁.

六. 多个线程能否共享一把锁

1. 共享锁 : 能

指当一个线程获取该锁后, 其他锁依旧可以对数据进行读取操作, 但是只有获取该锁的线程能对数据进行改写的操作

2. 互斥锁 : 不能

指当一个线程获取该锁后, 其他锁将不能对数据进行读写操作, 只有获取到该锁的线程可以对数据进行读写

以上的内容的是个人的一个总结, 水平有限, 可能不一定正确, 这篇文章仅对Java几个线程锁进行了一个初步的理解, 并没有深入探究, 如有错误还请多多包涵.


http://chatgpt.dhexx.cn/article/aiTWj4va.shtml

相关文章

Java多线程 各种锁(一篇全搞懂)

Java多线程 锁 文章目录 Java多线程 锁1、乐观锁与悲观锁2、公平锁与非公平锁3、可重入锁与不可重入锁4、独享锁与共享锁5、自旋锁 VS 适应性自旋锁6、无锁 、 偏向锁、量级锁 和 重量级锁(难点) 1、乐观锁与悲观锁 (1)悲观锁 对…

Java多线程编程(三)——线程锁

卖票案例 同步代码块解决数据安全问题 同步方法解决数据安全问题 同步方法的格式: 同步方法和同步方法块的区别: 同步静态方法 Lock锁 卖票案例 某电影院目前正在上映国产大片,共有30张票,而它有3个窗口卖票,请…

浅析Java 多线程中的锁

前言 随着互联网技术的快速发展,多线程编程已经成为了现今编程领域中必不可少的知识点之一。Java 是一种广泛使用的编程语言,也是一些底层应用程序和高并发应用程序的首选语言。而 Java 提供的多线程编程机制和相关的锁机制,则成为了 Java 开…

【Java多线程进阶】常见的锁策略

前言 众所周知,拳击运动员是要分等级(轻量级、重量级等等)来参加比赛的,在 Java 多线程中 锁(synchronized) 也会根据锁的竞争程度来升级为相关“高等级”锁,为了更好的理解 synchronized 加锁机…

Java多线程下——各类锁的详解

这里写目录标题 各类锁的详解常见的锁策略乐观锁 vs 悲观锁读写锁重量级锁 vs 轻量级锁自旋锁(Spin Lock)公平锁 vs 非公平锁可重入锁 vs 不可重入锁 CASSynchronized 原理偏向锁锁消除锁粗化 Callable 接口ReentrantLock线程池ExecutorService 和 Execu…

Java中的线程和锁机制

线程池 为什么使用线程池?线程池执行原理?线程池参数有哪些?线程池大小怎么设置?线程池的类型有哪些?适用场景? 进程线程 线程的生命周期讲一下线程中断?创建线程有哪几种方式?什么是…

【Java】中的多线程线程锁

多线程 文章目录 多线程线程的创建和启动sleep()stop() 线程的休眠和中断线程的优先级线程的礼让和加入yield()stop() 线程锁和线程同步synchronized 关键字 死锁概念 wait & notify methodThreadLocal的使用定时器 Timer守护线程再谈集合类parallelStreamforEachOrdered()…

Java多线程中 的各种锁

学习 java 多线程时,最头疼的知识点之一就是 java 中的锁了,什么互斥锁、排它锁、自旋锁、死锁、活锁等等,细分的话可以罗列出 20 种左右的锁,光是看着这些名字就足以让人望而却步了,更别说一个个去理解它们的含义了。…

Java——多线程和锁

多线程 前言:当我们打开一个网站时,不同部分的加载并不是先后出现的,是并行出现的,没有出现一个地方没加载完,别的地方就也加载不出来这种事。这个就是多线程并行运行。 当其中一个线程发生阻塞时,操作系统会自动执行…

Java-多线程中的“锁“

文章目录 Java多线程中的锁1. 什么是锁?2. 锁的作用3. 锁的类型4. 锁的使用示例5.乐观锁和悲观锁6. 锁的注意事项总结 Java多线程中的锁 在Java多线程编程中,锁是一种重要的同步机制,用于保护共享资源的访问。使用锁可以防止多个线程同时对共…

JAVA三种线程锁

内置锁:synchriozed,关键字,同步代码块,object.wait和object.notify/notifyall 显示锁:Lock,JUC包下的类,同步代码块,condition.await和condition.signal/signalall 原子类&#xff…

Java多线程中锁的理解与使用

1.简介 锁作为并发共享数据,保证一致性的工具,在JAVA平台有多种实现(如 synchronized 和 ReentrantLock等 ) 。 2.Java锁的种类 公平锁/非公平锁可重入锁独享锁/共享锁互斥锁/读写锁乐观锁/悲观锁分段锁偏向锁/轻量级锁/重量级锁自旋锁 上面是很多锁…

java多线程的15种锁

1 java锁分类 下面我们依照序号依次的介绍每一种锁 2 悲观锁和乐观锁 悲观锁和乐观锁是一种广义的概念,体现的是看待线程同步的不同的角度 悲观锁认为自己在使用数据的时候,一定有别的线程来修改数据,在获取数据的时候会先加锁&#xff0c…

Java多线程 - 锁

Java多线程 - 锁 三性 可见性 指的是线程之间的可见性,一个线程对状态的修改,对其他线程是可见的。在 Java中 volatile、synchronized 和 final 实现可见性。 原子性 如果一个操作是不可分割的,我们则称之为原子操作,也就是有原…

Java多线程与锁

前文中,我们已经了解了什么是线程,线程间常用通信方式,线程池以及其相关特性,可以看出锁在多线程环境中充当着重要作用,不管是线程间的数据通信,还是线程间的等待和唤醒,都依赖于锁,…

JAVA基础-多线程中锁机制

多线程锁 多线程锁机制锁的定义锁的分类公平锁/非公平锁可重入锁独享锁/共享锁互斥锁/读写锁乐观锁/悲观锁分段锁偏向锁/轻量级锁/重量级锁自旋锁 锁的使用AQSAQS框架展示AQS定义两种资源共享方式AQS常用的几种方法(自定义同步器实现时)自定义同步器实现…

多线程系列-Java中的锁(简介)

前言 Java提供了种类丰富的锁,每种锁因其特性的不同,在适当的场景下能够展现出非常高的效率。本文旨在对锁相关源码(本文中的源码来自JDK 8和Netty 3.10.6)、使用场景进行举例,为读者介绍主流锁的知识点,以…

JAVA如何在线程中加锁(四种方法)

JAVA多线程锁 线程的生命周期 ​ 总共六种状态,可归结为五种,线程的最终是死亡,阻塞不是最终状态,只是一个临时状态。只有调用了start方法,线程才进入就绪阶段。 //新生 ​ NEW, //运行​ RUNNABLE, //阻塞​ BLOCKE…

大数据平台_大数据应用场景有哪些

大数据时代的出现,简单的讲是海量数据同完美计算能力结合的结果,确切的说是移动互联网、物联网产生了海量的数据,大数据计算技术完美地解决了海量数据的收集、存储、计算、分析的问题。一些公司也成立了大数据部门,大数据得到了企…

银行业9大数据科学应用案例

在银行业中使用数据科学不仅仅是一种趋势,它已成为保持竞争的必要条件。 银行必须认识到, 大数据技术可以帮助他们有效地集中资源,做出更明智的决策并提高绩效。 以下我们罗列银行业使用的数据科学用例清单, 让您了解如何处理大量数据以及如何有效使用数据。 [TOC] 1 欺诈识…