同步锁笔记

CAS(Compare and Set)

无锁算法,不使用锁的情况下实现多线程之间的变量同步,拿变量的原值和内存中的值进行比较,如果相同,则原值没有被修改过,那么就将原值修改为新值,失败的线程不会挂起,继续循环;

Java 中的 AtomicInteger 类就用了CAS操作。

比起锁来性能提升了许多,但是因为频繁循环,会照成系统开销增大。

ABA问题:如果值一开始是A,后来被改成了B又被改回了A,CAS会认为该变量没被修改过,不过 Java 也提供了带时间戳的类来解决这个问题。

AQS(AbstractQueuedSynchronizer)

抽象队列同步器,支持 独占(exclusive ) 与 共享(shared) 两种模式,维护一个整形的 volatile 变量 state 和队列来实现同步,通过 CAS来更新state值(线程个数一致),AQS 也支持自定义同步器同时实现独占和共享两种方式,如 ReentrantReadWriteLock

直接尝试占有,先判断state是否为0(可获取),然后将0累计加1,当前线程设置为锁持有( lock())线程,并返回成功;如果失败则依次排队,释放锁( unlock())state-1;

java很多同步框架都依赖于AQS,比如 CountDownLatch,ReentrantLock,Semaphore。

同步器基于模板方法模式,需要自定义模版继承 AbstractQueuedSynchronizer ,重写方法(state 的获取和释放), Semaphore(信号量)可以指定多个线程同时访问某个资源。

Semaphore

基于 AQS 实现,指定线程数量,当执行任务的线程数超出,多余的线程将会被放入阻塞队列。

CountDownLatch

基于 AQS 实现,是一次性的,计数器的值只能在构造方法中初始化一次。

CyclicBarrier

指定线程数量,线程到达一个屏障会被阻塞(变量标识计数),直到指定的最后一个线程也到达屏障时,屏障才会打开,然后线程继续运行,还可以指定到达屏障时,优先执行某些代码块。

ReentrantLock(公平锁/非公平锁)

依赖于AQS同步框架实现,可以指定构造函数的boolean类型来得到公平锁或非公平锁。

公平锁:先进先出,多个线程按照队列的规则依次排队。

非公平锁:多个线程去获取锁的时候,会直接去尝试获取,获取不到,再去进入等待队列。

对比公平锁更有机会抢占锁,性能高于公平锁,因为线程运行之间存在着延迟,非公平锁能更充分的利用时间碎片。

synchronized(同步锁)

表示只能有一个线程访问该对象,jdk6之前是操作系统的 mutex lock(互斥锁)实现,但是由于 mutex 性能上的问题,在线程挂起时会从用户状态切换到内核状态来;

切换代价消耗大,后面加入了CAS跟许多优化机制,所以性能跟 ReentrantLock 基本相等。

静态方法类需要注意,如果new不同对象调用同一个静态锁方法,此时对象间会共用一把锁,使该线程下方法里的代码块同步进行。

mutex

Linux 系统中称 mutex 为互斥体,是一种存取共享内存资源的机制,在数据被进程持有时不允许其它进程从共享内存中读取信息、也不允许同时读取操作。

可重入锁/不可重入锁

可重入锁:当线程获取某个锁后,还可以继续获取它,可以递归调用,而不会发生死锁,ReentrantLock 跟 synchronized 都是可重入锁。

不可重入锁:与可重入相反,获取锁后不能重复获取,否则会自己锁死自己。

独享锁/共享锁

独享锁:该锁每一次只能被一个线程所持有,比如 synchronized。

共享锁:该锁可被多个线程共有。

互斥锁/读写锁

互斥锁mutex lock,如果资源已经被加锁,其它线程进入阻塞,直到当前进程解锁,synchronized 为互斥锁。

读写锁:读写锁既是互斥锁,又是共享锁,读模式是共享,写是互斥,读读不互斥,读写互斥,写写互斥。

乐观锁/悲观锁

乐观锁:假设都是无锁状态。

悲观锁:假设都是上锁状态。

分段锁

是一种锁的设计,并不是具体的一种锁,ConcurrentHashMap 前期就是通过分段锁来实现高效的并发操作。

每一把锁都用于数据段,当多线程访问不同数据段的数据时,从而降低锁竞争,提高并发访问效率。

自旋锁

偏向锁/轻量级锁/重量级锁

不属于java锁,而是 Jvm 为了提高锁的获取与释放效率而做的优化。

偏向锁:某线程一直访问 synchronized 锁代码,那么该线程会自动获取锁,降低获取锁的代价。

轻量级锁:在偏向锁的基础上,另一个线程加入访问,偏向锁会自动升级为轻量级锁,其他线程就可以通过自旋的形式尝试获取锁而不被阻塞,以此提高性能。

重量级锁:在轻量级锁的基础上,另一个线程加入访问,处于自旋,当自旋一定次数还没有获取到锁,就会进入阻塞,该锁变为重量级锁,重量级锁会让其他申请的线程进入阻塞。

volatile

高速缓存:多核多线程操作(单核不会),会对数据进行缓存,修改后在设置回内存中,这样会导致写入数据时(会让其他线程缓存中的值过期,这样就必须重新获取最新的值)同步出错,volatile可以解决可见性问题,线程修改完值后其它线程立即可见。

指令重排:CPU在执行代码时(编译器也会),不一定是我们编写的顺序去执行,为了提高效率,会对这些先后顺序无关紧要的代码(数据无依赖关系)进行重新排序,导致有的初始化完成但是还没赋值,下一个线程操作时就会异常,volatile会告诉CPU禁止对它重排。

使用volatile会屏蔽掉JVM中的一些优化,效率上比较低,因此必要时使用。

Original: https://www.cnblogs.com/LiuZhen/p/15964885.html
Author: 翻滚的咸鱼
Title: 同步锁笔记

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/580326/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

  • 看Spring源码不得不会的@Enable模块驱动实现原理讲解

    这篇文章我想和你聊一聊 spring的@Enable模块驱动的实现原理。 在我们平时使用spring的过程中,如果想要加个定时任务的功能,那么就需要加注解@EnableSchedu…

    Java 2023年6月16日
    0102
  • 就从这里开始吧

    之前有人论断说,今后工程师不再是一种职业,而是一种生存所必须掌握的技能,就像驾照一样。也就是说,在未来,不管是卖吃的,卖穿的,卖玩的,还是搞文化活动的,都免不了需要做点开发工作,而…

    Java 2023年6月7日
    092
  • 「Java分享客栈」随时用随时翻:微服务链路追踪之zipkin搭建

    前言 微服务治理方案中,链路追踪是必修课,SpringCloud的组件其实使用很简单,生产环境中真正令人头疼的往往是软件维护,接口在微服务间的调用究竟哪个环节出现了问题,哪个环节耗…

    Java 2023年6月9日
    079
  • 第一个java,Hello,world!

    环境部署 下载安装JDK1.8 配置环境变量 JAVA_HOME变量 Path添加%JAVA_HOME%\bin %JAVA_HOME%\jre\bin 打开CMD,输入java …

    Java 2023年6月9日
    067
  • Hexo 博客部署至腾讯云

    一.安装环境 推荐购买腾讯云活动的轻应用服务器 2C2G 就可以啦,我买的是 45 一年的:点我购买 以下命令默认在 ubuntu 系统上执行 安装 nginx apt-get i…

    Java 2023年6月8日
    088
  • 程序员如何利用技术能力变现

    本文节选左耳朵耗子相关文章,与读者共勉! 本质上来说,程序员是手艺人,有手艺的人就能做出别人做不出来的东西,而付费也是一件很自然的事了。那么,这个问题就成了,如何让自己的&#822…

    Java 2023年6月6日
    083
  • HUST-计算机网络实验-socket编程

    随笔—HUST计网实验:socket编程 博主大三在读,第一次写随笔,水平有限,就当记录一下学习的过程,顺便面试前复习项目的时候看看。 实验要求: 编写一个 Web 服…

    Java 2023年6月5日
    087
  • Spring Boot打包的jar包指定配置文件启动

    Spring Boot会按照下列优先级来加载application.properties配置文件,由高到低依次为: jar包同级目录下的config目录下的application….

    Java 2023年6月16日
    060
  • Javaweb-文件上传和邮件发送

    1.文件上传 新建空项目 准备工作 在maven仓库里下载commons io 和 commons fileupload两个jar包 实用类介绍 文件上传注意事项 为保证服务器安全…

    Java 2023年6月13日
    080
  • 基于easyx的小时钟

    #include #include #include #define PI 3.141592654 void Draw_Dial(); void Draw_Hand(int hou…

    Java 2023年6月9日
    090
  • 超越iTerm! 号称下一代终端神器,功能贼强大!

    程序员的一生,用的最多的两个工具,一个是代码编辑器(Code Editor),另外一个就是命令行终端工具(Terminal)。这两个工具对于提高开发效率至关重要。 代码编辑器在过去…

    Java 2023年6月9日
    064
  • 原来你是这样的JAVA[05]–String

    1.从概念上讲,java字符串就是Unicode字符串。2.字符串拼接用指定分隔符拼接字符串数组时,使用StringJoiner或者String.join()更方便;用String…

    Java 2023年5月29日
    0103
  • SimpleDateFormat线程不安全的5种解决方案

    1.什么是线程不安全? 线程不安全也叫非线程安全,是指多线程执行中,程序的执行结果和预期的结果不符的情况就叫着线程不安全。 线程不安全的代码 SimpleDateFormat 就是…

    Java 2023年5月30日
    083
  • Java入门

    一、Java 1.1 为什么Java是平台无关性(可以跨平台) 二、Java环境 2.1、JRE 2.2、JDK 2.3、JVM 三、Java编译和运行的机制 四、Java基础 4…

    Java 2023年6月7日
    0112
  • 利用docker部署oxidized网络设备备份系统

    随着网络设备的增多,通过人手备份网络设备倍感压力,而且效率低。有编程基础的人可能会通过Python的parimiko 或者netmiko 连接到设备操作 把文件通过ftp 上传到F…

    Java 2023年6月8日
    0167
  • OpenJDK 发行版本(国内和国外)

    发行版本 OpenJDK 发行版 公司 主页 亚马逊 腾讯 阿里 微软 华为 Zulu JDK Azul The Eclipse Temurin eclipse Amazon Co…

    Java 2023年6月9日
    080
亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球