并发编程之java锁的升级与对比
欢迎来到阿八个人博客网站。本 阿八个人博客 网站提供最新的站长新闻,各种互联网资讯。 喜欢本站的朋友可以收藏本站,或者加QQ:我们大家一起来交流技术! URL链接:https://www.abboke.com/jsh/2019/0906/111493.html
前言:
在并发编程中,经常用到synchronized关键词,总是感觉使用它会很重。随着Java SE 1.6对synchronize进行了各种优化,引入了偏向锁和轻量级锁,在某些情况下,减少了获得锁和释放锁带来得性能消耗。
一、文章导图
进入java文件所在目录,通过命令行进行编译:javac SynchronizedDemo.java java SE 1.6引入偏向锁与轻量级锁后,锁一共有4中状态,级别从低到高依次是:无锁状态、偏向锁状态、轻量级锁和重量级锁状态。且锁会随着竞争情况逐步升级,但不可降级(基于JVM的一个假定:“假定一旦破坏了上一级锁的升级,就认为该假定以后也不成立”)。 为了让线程获取锁的代价更低而引入偏向锁,因为多线程中,有些情况下,获取锁的线程同时只会有一个。 线程1访问同步代码块,确定锁的标志为01(偏向锁升级或偏向锁关闭),进行获取轻量级锁,线程2同理线程1分配本线程栈的锁记录空间,并拷贝锁对象的Mark Word到当前线程栈的锁记录中线程2分配本线程栈的锁记录空间,并拷贝锁对象的Mark Word到当前线程栈的锁记录中线程1尝试使用CAS替换锁对象头的Mark Word指向锁记录的指针,成功后,线程1获取到轻量级锁线程2尝试使用CAS替换锁对象头的Mark Word指向锁记录的指针,失败,因为线程1获得锁,此时线程2自旋线程2自旋一定次数后,失败,锁膨胀为重量级锁,并阻塞本线程(线程2)线程1同步方法体执行完,CAS替换Mark Word,失败,因为线程2在竞争锁资源线程1释放锁并唤醒等待的线程,等待的线程2被唤醒,重新争夺访问同步块。 内置锁在java中被抽象为监视器锁(monitor),对于重量级锁,监视器锁直接对应底层操作系统中的互斥量(mutex),这种同步成本非常高,包括系统调用引起的内核态与用户态切换、线程阻塞造成的线程切换等。 关于不同锁的优缺点对比,如下所示
然后同目录下通过如下命令,进行查看编译后字节码的详细信息:javap -verbose SynchronizedDemo.class 3、偏向锁
如下,线程1演示了偏向锁初始化的流程,线程2协助演示了偏向锁撤销的流程。5、重量级锁
锁 有点 缺点 使用场景 偏向锁加锁和解锁不需要额外的消耗,和执行非同步方法时相比仅存在纳秒级的差距;毕竟仅第一执行CAS操作如果线程间存在锁竞争,会带来额外的锁撤销的消耗适用于只有一个线程访问同步的场景轻量级锁竞争的线程不会阻塞,提高了程序的响应速度;相比偏向锁,获取和释放锁均执行一次CAS操作如果使用得不到锁竞争的线程,会使用自旋会消耗CPU资源追求响应时间,同步块执行速度非常快重量级锁线程竞争不使用自旋,不会消耗CPU线程阻塞,响应时间缓慢追求吞吐量,同步块执行速度较长