最近看到一个面试题,包括我自己也经常遇到面试官问Synchronized关键字的用法和底层原理。今天就来总结一下相关的问题和答案。
1、Synchronized关键字的作用
我想但凡用Java的开发者肯定都知道这个关键字,它是JDK提供给大家使用的同步关键字,用于在多线程场景下对关键资源的加锁,以保障数据不会因为多线程而紊乱。包括在Java很多内置的函数里面也都是使用的该关键字,比如JDK1.5里面的HashMap就是靠Synchronized关键字修饰的类方法来实现的线程安全。
2、Synchronized的用法
Synchronized主要有三种用法,分别是:修饰方法、修饰代码块、修饰静态方法。
2.1修饰对象方法,主要是将这个对象方法进行加锁,这样其他现场在调用这个对象时就无法访问了,但是该对象的其他方法仍然是可以被其他线程访问获取的。
2.2修饰代码块,常常以Synchronized(this){代码块;}这种方式出现在代码证,这种情况下这一整块代码就可以被视作是一个整体,只能同时被一个线程所持有锁,进行资源访问,而其他线程只能被阻塞等待。
2.3修饰静态方法,修饰静态变量也十分好理解,例如public static void synchronized get(int s){} ;这种情况下这个类方法的调用者,都会被锁控制。
3、Synchronized底层的实现机制
该关键字的底层其实是依靠Monitor管程对象来实现的,一旦该对象或者方法被加了关键字,那么在底层就会有MonitorEnter和MonitorExit这对命令来包裹。当然底层现在使用的是ACC_SYNCHRONIZED关键字,通过将JavaC编译过的文件进行反编译就可以得出该结论。
4、Synchronized的优化
目前自从Java1.6之后,JVM就大大优化了对于该关键字的性能,使用了一系列的偏向所、轻量级所、自旋锁、重量级锁等一系列的锁集合机制。
偏向锁是基于一个规律,多数获取了这个锁的线程,下次获取的还是这个锁。所以对于上个持有的锁就进行了偏向性优化,如果校验得到还是原来的那个线程来获取这个锁,则直接得到锁,无需做任何同步和锁申请的操作。
轻量级锁:是相比于重量级锁而言的,其依据是“绝大多数锁,在同步期间都不会发生冲突”。
自旋锁:自旋锁主要是依据“所有获取锁的线程很快就释放了这个锁“,由于CPU调度时从用户态到核心态开销很大,所以宁愿让这个线程自旋转一会儿(也就是空执行一段时间)来等待所需求的锁,而不至于立马挂起。