众所周知 synchronized 关键字是解决并发问题常用解决方案,有以下三种使用方式:

  • 同步普通方法,锁的是当前对象。
  • 同步静态方法,锁的是当前 Class 对象。
  • 同步块,锁的是 () 中的对象。

实现原理: JVM 是通过进入、退出对象监视器( Monitor )来实现对方法、同步块的同步的。

具体实现是在编译之后在同步方法调用前加入一个 monitor.enter 指令,在退出方法和异常处插入 monitor.exit 的指令。

其本质就是对一个对象监视器( Monitor )进行获取,而这个获取过程具有排他性从而达到了同一时刻只能一个线程访问的目的。

而对于没有获取到锁的线程将会阻塞到方法入口处,直到获取锁的线程 monitor.exit 之后才能尝试继续获取锁。

流程图如下:

通过一段代码来演示:

    public static void main(String[] args) {synchronized (Synchronize.class){System.out.println("Synchronize");}}

使用 javap -c Synchronize 可以查看编译之后的具体信息。

public class com.crossoverjie.synchronize.Synchronize {public com.crossoverjie.synchronize.Synchronize();Code:0: aload_01: invokespecial #1                  // Method java/lang/Object."<init>":()V4: returnpublic static void main(java.lang.String[]);Code:0: ldc           #2                  // class com/crossoverjie/synchronize/Synchronize2: dup3: astore_1**4: monitorenter**5: getstatic     #3                  // Field java/lang/System.out:Ljava/io/PrintStream;8: ldc           #4                  // String Synchronize10: invokevirtual #5                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V13: aload_1**14: monitorexit**15: goto          2318: astore_219: aload_120: monitorexit21: aload_222: athrow23: returnException table:from    to  target type5    15    18   any18    21    18   any
}

可以看到在同步块的入口和出口分别有 monitorenter,monitorexit 指令。

锁优化

synchronized 很多都称之为重量锁,JDK1.6 中对 synchronized 进行了各种优化,为了能减少获取和释放锁带来的消耗引入了偏向锁轻量锁

轻量锁

当代码进入同步块时,如果同步对象为无锁状态时,当前线程会在栈帧中创建一个锁记录(Lock Record)区域,同时将锁对象的对象头中 Mark Word 拷贝到锁记录中,再尝试使用 CAS 将 Mark Word 更新为指向锁记录的指针。

如果更新成功,当前线程就获得了锁。

如果更新失败, JVM 会先检查锁对象的 Mark Word 是否指向当前线程的锁记录。

如果是则说明当前线程拥有锁对象的锁,可以直接进入同步块。

不是则说明有其他线程抢占了锁,如果存在多个线程同时竞争一把锁,轻量锁就会膨胀为重量锁

解锁

轻量锁的解锁过程也是利用 CAS 来实现的,会尝试锁记录替换回锁对象的 Mark Word 。如果替换成功则说明整个同步操作完成,失败则说明有其他线程尝试获取锁,这时就会唤醒被挂起的线程(此时已经膨胀为重量锁)

轻量锁能提升性能的原因是:

认为大多数锁在整个同步周期都不存在竞争,所以使用 CAS 比使用互斥开销更少。但如果锁竞争激烈,轻量锁就不但有互斥的开销,还有 CAS 的开销,甚至比重量锁更慢。

偏向锁

为了进一步的降低获取锁的代价,JDK1.6 之后还引入了偏向锁。

偏向锁的特征是:锁不存在多线程竞争,并且应由一个线程多次获得锁。

当线程访问同步块时,会使用 CAS 将线程 ID 更新到锁对象的 Mark Word 中,如果更新成功则获得偏向锁,并且之后每次进入这个对象锁相关的同步块时都不需要再次获取锁了。

释放锁

当有另外一个线程获取这个锁时,持有偏向锁的线程就会释放锁,释放时会等待全局安全点(这一时刻没有字节码运行),接着会暂停拥有偏向锁的线程,根据锁对象目前是否被锁来判定将对象头中的 Mark Word 设置为无锁或者是轻量锁状态。

偏向锁可以提高带有同步却没有竞争的程序性能,但如果程序中大多数锁都存在竞争时,那偏向锁就起不到太大作用。可以使用 -XX:-userBiasedLocking=false 来关闭偏向锁,并默认进入轻量锁。

其他优化

适应性自旋

在使用 CAS 时,如果操作失败,CAS 会自旋再次尝试。由于自旋是需要消耗 CPU 资源的,所以如果长期自旋就白白浪费了 CPUJDK1.6加入了适应性自旋:

如果某个锁自旋很少成功获得,那么下一次就会减少自旋。

synchronized 关键字原理相关推荐

  1. synchronized关键字原理

    认识synchronized 对于写多线程程序的人来说,经常碰到的就是并发问题,对于容易出现并发问题的地方价格synchronized基本上就搞定 了,如果说不考虑性能问题的话,这一操绝对能应对百分之 ...

  2. Java并发编程学习笔记——volatile与synchronized关键字原理及使用

    Java代码在编译后会变成Java字节码,字节码被类加载器加载到JVM里,JVM执行字节码,最终需要转化为汇编指令在CPU上执行,Java中所使用的并发机制依赖于JVM的实现和CPU的指令. 一.vo ...

  3. synchronized原理_面试必备—Synchronized 关键字使用、底层原理

    在并发编程中存在线程安全问题,主要原因有: 1.存在共享数据 2.多线程共同操作共享数据 关键字synchronized可以保证在同一时刻,只有一个线程可以执行某个方法或某个代码块,同时synchro ...

  4. synchronized关键字的底层原理以及JDK1.6之后的底层优化

    synchronized关键字底层原理属于JVM层面. 1. synchronized关键字修饰同步代码块,synchronized同步代码块的实现使用的是monitorenter和monitorex ...

  5. synchronized 关键字的底层原理

    synchronized关键字实现了多个线程之间访问资源的同步性,保证了被它修饰的方法或代码块在任意时刻最多只有一个线程执行. synchronized关键字是通过JVM底层实现的. 按使用位置分,同 ...

  6. synchronized底层原理_你用过synchronized吗?它的底层原理是什么?Java经典面试题来了...

    并发编程已经成为程序员必备技能 作为Java程序员,不懂得并发编程显然已经不能满足市场需求了,尤其是在面试过程中将处于被动地位,也有可能面试将就此终结. 那么作为Java开发者的你,日常虽然可以基于J ...

  7. Java并发:明白Synchronized实现原理,锁什么?

    最近看到synchronized的知识点,做些简单记录. 一.Synchronized的基本使用 Synchronized是Java中解决并发问题的一种最常用的方法,也是最简单的一种方法.Synchr ...

  8. Java多线程闲聊(六):synchronized关键字

    Java多线程闲聊(六):synchronized关键字 前言 这篇文章我会在博客置顶,为什么呢?因为,三篇引用的文章写得太好了,我害怕后面找不到,看不到,然后忘了! 让我想想,感觉昨天的前言把最近肚 ...

  9. synchronized()_这篇文章带你彻底理解synchronized关键字

    Synchronized关键字一直是工作和面试中的重点.这篇文章准备彻彻底底的从基础使用到原理缺陷等各个方面来一个分析,这篇文章由于篇幅比较长,但是如果你有时间和耐心,相信会有一个比较大的收获,所以, ...

最新文章

  1. 【js】common.jsp的使用
  2. 干货!链家二手房数据抓取及内容解析要点
  3. 科大讯飞与优刻得、寒武纪等联合设立合肥智能语音创新发展有限公司
  4. 玩远程 可视对讲系统几大新兴应用分析
  5. VTK:Utilities之FileOutputWindow
  6. centos查看当前目录下文件大小_centos Linux 统计某个文件夹占用空间大小
  7. final+static
  8. PHP中文乱码解决办法
  9. Apollo进阶课程㊴丨Apollo安装过程概述
  10. 复制网页中的表格格式后导入到excel、markdown、数据库、json中,并转换表格格式
  11. 华为回应关于“获政府巨额补贴”报道;最高法:微信微博聊天记录可作为证据;GoLand 2020.1 路线图公布 | 极客头条...
  12. [转]详细解说:简单CSS3实现炫酷读者墙
  13. Wifi万能钥匙已经被淘汰了!Github这个开源工具太好用了!
  14. JSP程序设计第二版--附带实验代码
  15. 数据挖掘(七) DBSCAN聚类算法
  16. 论文中出现的 cf. i.e. s.t. e.g. w.r.t. et al. etc等英文缩写是什么意思
  17. CENTOS6 安装配置 pptpd 心得
  18. 【Altium Designer】PCB的泪滴化
  19. evernote印象笔记导出的enex文件转换markdown文档
  20. github上的html项目怎么运行,GitHub搭建简单的项目“Hello HTML”

热门文章

  1. APT团伙是如何利用Windows热修复的?
  2. 03-spring_配置bean
  3. 设计模式学习笔记(9)——代理模式
  4. linux小白-基础命令-ls
  5. sql 删除用户失败
  6. unix网络编程——ioctl 函数的用法详解
  7. libuv 中文编程指南
  8. deepin--更改最低亮度
  9. 无法启动程序,因为计算机中丢失msvcr.dll
  10. 游戏里的角色都什么格式图片_为什么这游戏里别人的都是大白鲨,我却是小金鱼?...