

是时候来唠一唠synchronized关键字了,Java多线程的必问考点! - JavaBuild
source link: https://www.cnblogs.com/JavaBuild/p/18090903
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

在之前的博文中,我们介绍了volatile关键字,Java中的锁以及锁的分类,今天我们花5分钟时间,一起学习一下另一个关键字:synchronized。
synchronized是什么?
首先synchronized
是Java中的一个关键字,所谓关键字,就是Java中根据底层封装所赋予的一种具有特殊语义的单词,而synchronized译为同步之意,可保证在同一时刻,被它修饰的方法或代码块只能有一个线程执行,它的使用解决了并发多线程中的三大问题:原子性、可见性、顺序性。
很多小伙伴在过往的书籍中可能会看到说synchronized是一种重量级锁,性能差,不建议在代码中使用,其实这是早期的synchronized特点,自JDK1.6之后,synchronized 引入了大量的优化如自旋锁、适应性自旋锁、锁消除、锁粗化、偏向锁、轻量级锁等技术来减少锁操作的开销,这些优化让 synchronized 锁的效率提升了很多。因此, synchronized 还是可以在实际项目中使用的,像 JDK 源码、很多开源框架都大量使用了 synchronized 。
synchronized的使用
synchronized在Java中主要的3种使用方式:
- 修饰实例方法: 为当前对象实例加锁,进入同步方法需要先获取对象锁;
- 修饰静态方法: 为当前类加锁,锁定的是Class对象,进入同步方法需要先获取类锁;
- 修饰代码块: 为指定对象加锁,进入同步方法需要先获取指定对象的锁。
样例:
//修饰实例方法,为当前实例加锁synchronized void method() { //业务代码}//修饰静态方法,锁为当前Class对象synchronized static void method() { //业务代码}//修饰代码块,锁为括号里面的对象synchronized(this) { //业务代码}
写到这里,突然想到了3个面试可能会考的知识点,列举一下!
问题1:synchronized修饰代码块可以给类加锁吗?
当然可以!我们前面说了修饰代码块时,是给代码中的对象加锁,这里面的对象既可以是实例也可以是类。
问题2:静态 synchronized 方法和非静态 synchronized 方法之间的调用互斥么?
不互斥!如果线程A调用一个实例对象的非静态synchronized方法,线程B同时去调用这个实例对象所属类的静态synchronized方法并不会发生互斥,因为线程A此时拿到的是实例对象锁,而线程B拿到的是当前类的锁。
问题3:构造方法可以用 synchronized 修饰么?
不可以!构造方法本身就是线程安全的,在Java开发规范里也明确告诉我们
构造方法不能是抽象的(abstract)、静态的(static)、最终的(final)、同步的(synchronized)。
synchronized的底层原理
在synchronized的底层(JVM层面),针对方法与代码块的实现逻辑是不同的,因此我们在分析底层原理是也要分别来看。
1、当synchronized修饰方法时
public class Test { public synchronized void method() { System.out.println("synchronized 方法"); }}
我们通过对编译后的class文件进行反编译后,分析其底层实现。
知识点扩展:
我们通过javap命令进行反编译,javap是Java class文件分解器,可以反编译,也可以查看java编译器生成的字节码等。
javap参数如下:

使用方式,既可以在电脑的命令行提示符中使用,也可以通过idea的terminal终端使用,我这里采用idea中进行反汇编操作。参考命令:javap -c -v Test.class
【反汇编结果】

由上图可看出同步方法通过加 ACC_SYNCHRONIZED 标识实现线程的执行权的控制,如果修饰的是实例方法,JVM会获取对象锁,如果修饰的是静态方法,JVM会获取当前类锁。
2、当synchronized修饰代码块时
public class Test { public void method() { synchronized (this) { System.out.println("synchronized"); } }}
【反汇编结果】

与同步方法不同,同步代码块中使用了monitorenter 和 monitorexit 指令,其中 monitorenter 指令指向同步代码块的开始位置,monitorexit 指令则指明同步代码块的结束位置,并且monitorexit标识有2个,以保证在正常执行和异常情况下均可释放锁。
在命令执行到monitorenter时,线程会去尝试获取对象得锁,这里也可称之为对象所对应的monitor所有权。写到这里,我们又要做一个知识点扩展啦。
知识点扩展:
在JVM中monitor的底层基于C++实现,被称之为对象监视器,每个对象都会内置一个ObjectMonitor与之关联,关联的起始地址存于对象头的MarkWord中。

ObjectMonitor几个关键属性:
- _owner:指向持有ObjectMonitor对象的线程
- _WaitSet:存放处于wait状态的线程队列
- EntryList:存放处于等待锁block状态的线程队列
- recursions:锁的重入次数
- _count:用来记录该线程获取锁的次数
当多个线程同时访问同步代码时,会被放入EntryList中,根据线程优先级尝试获取对象锁,如果锁的计数器为 0 则表示锁可以被获取,获取到锁的线程进入owner区域,count加1,这里其实还有之前说的object中的wait/notify/notifyall的组合,也依赖monitor,所以他们才必须用在同步方法或代码块中。
对象锁的的拥有者线程才可以执行 monitorexit 指令来释放锁。在执行 monitorexit 指令后,将锁计数器设为 0,表明锁被释放,其他线程可以尝试获取锁。
关于synchronized的介绍其实远没有结束,还有很多细节可以值得学习,我们会在后面的文章中逐渐补充,避免文章过长,读者失去阅读的耐心!
如果本篇博客对您有一定的帮助,大家记得留言+点赞+收藏呀。原创不易,转载请联系Build哥!

如果您想与Build哥的关系更近一步,还可以关注“JavaBuild888”,在这里除了看到《Java成长计划》系列博文,还有提升工作效率的小笔记、读书心得、大厂面经、人生感悟等等,欢迎您的加入!
Recommend
-
31
微信订阅号改版“信息流”之后,不少网友都认为,这是功能上的退步,并纷纷表示要“取关”,并在知乎、豆瓣等各大社区平台上,也掀起了不少关于“微...
-
7
聊聊 Java 中绕不开的 Synchronized 关键字 Posted on 2021-06-20...
-
5
synchronized关键字 什么是synchronized JDK官网对synchronized关键字有个比较权威的解释。 Synchronized keyword enable a simple strategy for preventing thread interference and memory consistency errors: if an object...
-
4
记一次Synchronized关键字使用不合理,导致的多线程下线程阻塞问题排查 | HeapDump性能社区记一次Synchronized关键字使用不合理,导致的多线程下线程阻塞问题排查杭盖S...
-
5
多线程的同步机制对资源进行加锁,使得在同一个时间,只有一个线程可以进行操作,同步用以解决多个线程同时访问时可能出现的问题。 同步机制可以使用synchronized关键字实现。 当synchronized关键字修饰一个方法的时候...
-
7
想必在面试中经常会被问到Synchronized关键字,它有什么特性,原理什么 它的主要特性是同步锁、非公平锁、阻塞锁、可以保证线程安全(可见性、原子性、有序性) JDK1.6之后对Synchronized有优化,有个锁升级过程
-
7
作者:小牛呼噜噜 | https://xiaoniuhululu.com 计算机内功、JAVA底层、面试、职业成长相关资料等更多精彩文章在公众号「
-
11
从字节码看 synchronized 关键字是怎么工作的 2023-04-05 2023-04-07...
-
3
在之前的线程系列文章中,我们介绍了线程创建的几种方式以及常用的方法介绍。 今天我们接着聊聊多线程线程安全的问题,以及解决办法。 实际上,在多线程环境中,难免会出现多个线程对一个对象的实例变量进行同时访问和操作,如果编程处理不当,会产生
-
5
面试官:小伙子请聊一聊Java中的精灵线程? 我:什么?精灵线程?啥时候精灵线程? 面试官:精灵线程没听过?那守护线程呢? 我:守护线程知道,就是为普通线程服务的线程嘛。 面试官:没了?守护线程的特点,怎么使用,需要注意啥,Java中...
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK