点赞再看,养成习惯,微信搜索「小大白日志」关注这个搬砖人。

文章不定期同步公众号,还有各种一线大厂面试原题、我的学习系列笔记。

多线程加锁有两种方式

  • 利用Sychronized关键字
  • 利用Lock接口子类ReentrantLock类
Sychronized关键字与Lock接口比较
  • sychronized是java内置的关键字,查看不到线程是否获取到了锁;Lock接口是一个java接口,可以查看是否获取到了锁
  • synchronized可以加在方法、代码块上;Lock接口写在代码里;
  • synchronized无法判断是否获取锁的状态,Lock可以判断是否获取到锁;
  • synchronized加在方法、代码块上,同一时刻只能有一个线程使用这段代码,其他线程必须等待,并且其他线程不能响应中断(响应中断=中断等待的状态:将线程从等待状态变为就绪状态,以便线程能继续往下执行代码;线程响应中断后会抛出一个异常,业务代码必须手动处理该异常);而Lock接口可以响应中断
  • Lock接口必须手动调用unlock()释放锁,否则容易造成死锁想象,一般在finally中调用unlock();

    synchronized放弃锁只有两种情况:

    (1)线程执行完了同步代码块的内容

    (2)发生异常;而lock不同,它可以设定超时时间,也就是说他可以在获取锁时便设定超时时间,如果在你设定的时间内它还没有获取到锁,那么它会放弃获取锁然后响应中断操作。
  • lock锁适合大量同步的代码的同步问题,synchronized锁适合代码少量的同步问题。

synchronized锁升级

基础知识

每个【锁=锁对象】的对象头由两部分组成:Classpointer+Markword

(1)Classpointer=对象类型指针,JVM就是通过它来确定当前对象是属于哪个class实例

(2)Markword,32位的jvm中Markword是占4B=4byte=32b=32位,存放对象运行时的数据(对象gc时的分代年龄,对象hashcode,当前锁为偏向锁时的线程ID),synchronized锁机制与32位中的最后3位(1+2)密切相关,最后2位是普通锁位,倒数第三位是偏向锁位:



当锁对象被创建出来,此时锁对象为无锁状态,(偏向锁位,普通锁位)=(0,01),所有无锁对象都是可偏向的,即可以被任意线程加偏向锁,当第一个线程对该锁对象加锁时,会把偏向锁位由0变1代表偏向锁生效,同时把线程ID插入锁对象头的Markword中

synchronized锁升级的过程(无锁->...->重量级锁)

锁膨胀的过程:无锁(没有线程)->偏向锁(1个线程)->轻量级锁(有第二个及以上的线程竞争锁)->重量级锁(有三个及以上的线程竞争锁)

偏向锁

如何加锁:线程A第一次访问同步代码块中的代码时,先检查当前锁是否可偏向(偏向锁位为0),是则通过CAS获取锁,获取锁之后会在synchronized关键字对应的锁对象的对象头中,在Markword里记录本线程ID,线程A再次访问该同步代码块中的代码时,直接比较锁对象头的Markword的线程ID是否是本线程ID,若是则线程A可重入取锁进而直接访问同步代码块,否则说明是另外一个线程B想访问同步代码块,从而B竞争同一个【锁=锁对象】,此时锁升级

如何锁升级为轻量级锁:当线程B想访问synchronized同步代码块时,会检查synchronized关键字对应的锁对象的对象头中,Markword中线程ID是否为线程B的ID,若不是则B再检查锁对象头中记录的线程A是否还存活,不存活则直接把锁对象先置为无锁状态,再获取锁使其变为偏向锁;若存活则先暂停线程A,撤销偏向锁,再把【锁=锁对象】升级为轻量级锁,然后B线程自旋(不断循环调用cas获取锁,自旋会消耗cpu使得cpu空转,所以自旋有次数限制)

轻量级锁

如何升级为重量级锁:B线程在访问同步代码块时发现A线程正在占用锁对象,故把【锁=锁对象】升级为轻量级锁,然后B自旋了,这时又有C线程来,此时轻量级锁升级为重量级锁,同时除了得到锁的那个线程,其他线程均会被阻塞

synchronized由无锁状态膨胀为重量锁的特点
  • jvm默认延迟4s后才开启偏向锁,在这4s期间的(锁=锁对象)又叫匿名偏向锁,4s后才记录得到锁的线程,可通过【-XX:BiasedLockingStartUpDelay=0】取消延时,可通过【-XX:-UseBiasedLocking = false】设置不要偏向锁
  • 除了偏向锁可以降为无锁状态,其他锁只能升级,不能降级
  • 偏向锁和轻量级锁在用户态维护,而重量级锁在内核态维护

OK,如果文章哪里有错误或不足,欢迎各位留言。

创作不易,各位的「三连」是二少创作的最大动力!我们下期见!

synchronized锁及其锁升级的更多相关文章

  1. Synchronized锁性能优化偏向锁轻量级锁升级 多线程中篇(五)

    不止一次的提到过,synchronized是Java内置的机制,是JVM层面的,而Lock则是接口,是JDK层面的 尽管最初synchronized的性能效率比较差,但是随着版本的升级,synchro ...

  2. java架构之路(多线程)synchronized详解以及锁的膨胀升级过程

    上几次博客,我们把volatile基本都说完了,剩下的还有我们的synchronized,还有我们的AQS,这次博客我来说一下synchronized的使用和原理. synchronized是jvm内 ...

  3. 关于Synchronized的偏向锁,轻量级锁,重量级锁,锁升级过程,自旋优化,你该了解这些

    前言 相信大部分开发人员,或多或少都看过或写过并发编程的代码.并发关键字除了Synchronized(如有不懂请移至传送门,关于Synchronized的偏向锁,轻量级锁,重量级锁,锁升级过程,自旋优 ...

  4. synchronized中锁是怎么升级的

    在JDK1.6以前,使用synchronized就只有一种方式即重量级锁,而在JDK1.6以后,引入了偏向锁,轻量级锁,重量级锁,来减少竞争带来的上下文切换. 锁升级主要依赖对象头中的Mark Wor ...

  5. synchronized和 synchronized 了解偏向锁、轻量级锁、重量级锁的概念以及升级机制、以及和ReentrantLock的区别。

    并发 synchronized 了解偏向锁.轻量级锁.重量级锁的概念以及升级机制.以及和ReentrantLock的区别.       https://www.cnblogs.com/deltadeb ...

  6. Synchronized关键字和锁升级,详细分析偏向锁和轻量级锁的升级

    原文链接:https://blog.csdn.net/tongdanping/article/details/79647337 1.锁升级锁的4中状态:无锁状态.偏向锁状态.轻量级锁状态.重量级锁状态 ...

  7. 线程安全(中)--彻底搞懂synchronized(从偏向锁到重量级锁)

    接触过线程安全的同学想必都使用过synchronized这个关键字,在java同步代码快中,synchronized的使用方式无非有两个: 通过对一个对象进行加锁来实现同步,如下面代码. synchr ...

  8. synchronized底层实现原理&CAS操作&偏向锁、轻量级锁,重量级锁、自旋锁、自适应自旋锁、锁消除、锁粗化

    进入时:monitorenter 每个对象有一个监视器锁(monitor).当monitor被占用时就会处于锁定状态,线程执行monitorenter指令时尝试获取monitor的所有权,过程如下:1 ...

  9. 【转载】Java中的锁机制 synchronized & 偏向锁 & 轻量级锁 & 重量级锁 & 各自优缺点及场景 & AtomicReference

    参考文章: http://blog.csdn.net/chen77716/article/details/6618779 目前在Java中存在两种锁机制:synchronized和Lock,Lock接 ...

随机推荐

  1. java面试--360

    1题执行以下程序后的输出结果是()public class Test {public static void main(String[] args) {StringBuffer a = new Str ...

  2. Shell 脚本是什么?

    一个 Shell 脚本是一个文本文件,包含一个或多个命令.作为系统管理员,我们经常需要使用多个命令来完成一项任务,我们可以添加这些所有命令在一个文本文件(Shell 脚本)来完成这些日常工作任务.- ...

  3. http多路复用?

    Keep-Alive: Keep-Alive解决的核心问题:一定时间内,同一域名多次请求数据,只建立一次HTTP请求,其他请求可复用每一次建立的连接通道,以达到提高请求效率的问题.这里面所说的一定时间 ...

  4. Dubbo Monitor 实现原理?

    Consumer 端在发起调用之前会先走 filter 链:provider 端在接收到请求时也是 先走 filter 链,然后才进行真正的业务逻辑处理. 默认情况下,在 consumer 和 pro ...

  5. notify()和 notifyAll()有什么区别?

    当一个线程进入 wait 之后,就必须等其他线程 notify/notifyall,使用 notifyall,可 以唤醒所有处于 wait 状态的线程,使其重新进入锁的争夺队列中,而 notify 只 ...

  6. 基于CrawlSpider全栈数据爬取

    CrawlSpider就是爬虫类Spider的一个子类 使用流程 创建一个基于CrawlSpider的一个爬虫文件 :scrapy genspider -t crawl spider_name www ...

  7. 规范之“用流中的Stream.Of(arr1,arr2)将两个集合合并”

    案例:用流中的Stream.Of(arr1,arr2)将两个集合合并 /** * 功能描述: * 两个对象集合添加到一起 * 在用flatMap扁平化改为Stream<User> * 这样 ...

  8. IE中的编码位置

    进入设置 找到Editor 找到File Encodings

  9. 模型预测控制(MPC)简介

    1.引言 在当今过程控制中,PID当然是用的最多的控制方法,但MPC也超过了10%的占有率.MPC是一个总称,有着各种各样的算法.其动态矩阵控制(DMC)是代表作.DMC采用的是系统的阶跃响应曲线,其 ...

  10. 前端入门-day2(常见css问题及解答)

    写在前面 今天是入门前端的day2, 小伙伴们应该已经看了一些HTML的基础和CSS的基础了,是不是遇到了很多关于CSS的问题呢.因为HTML很少有太复杂的问题,所以直接写一篇关于CSS的常见问题及解 ...