知了堂Java | Java基础面试题(7)
23.Synchronized的原理是什么?
Synchronized是由JVM实现的一种实现互斥同步的方式,查看被Synchronized修饰过的程序块编译后的 字节码,会发现,被Synchronized修饰过的程序块,在编译前后被编译器生成了monitorenter和 monitorexit两个字节码指令。
在虚拟机执行到monitorenter指令时,首先要尝试获取对象的锁:如果这个对象没有锁定,或者当前线 程已经拥有了这个对象的锁,把锁的计数器+1; 当执行monitorexit指令时,将锁计数器-1;当计数器 为0时,锁就被释放了。
如果获取对象失败了,那当前线程就要阻塞等待,直到对象锁被另外一个线程 释放为止。 Java中Synchronize通过在对象头设置标志,达到了获取锁和释放锁的目的。
24.为什么说Synchronized是非公平锁?
非公平主要表现在获取锁的行为上,并非是按照申请锁的时间前后给等待线程分配锁的,每当锁被释放 后,任何一个线程都有机会竞争到锁,这样做的目的是为了提高执行性能,缺点是可能会产生线程饥饿 现象
25.Synchronized和ReentrantLock的异同?
synchronized:
是java内置的关键字,它提供了一种独占的加锁方式。synchronized的获取和释放锁 由JVM实现,用户不需要显示的释放锁,非常方便。然而synchronized也有一些问题: 当线程尝试获取 锁的时候,如果获取不到锁会一直阻塞。 如果获取锁的线程进入休眠或者阻塞,除非当前线程异常,否 则其他线程尝试获取锁必须一直等待
ReentrantLock:
ReentrantLock是Lock的实现类,是一个互斥的同步锁。ReentrantLock是JDK 1.5 之后提供的API层面的互斥锁,需要lock()和unlock()方法配合try/finally语句块来完成,等待可中断避 免,出现死锁的情况(如果别的线程正持有锁,会等待参数给定的时间,在等待的过程中,如果获取了 锁定,就返回true,如果等待超时,返回false) 公平锁与非公平锁多个线程等待同一个锁时,必须按照申请锁的时间顺序获得锁,Synchronized锁非公 平锁,ReentrantLock默认的构造函数是创建的非公平锁,可以通过参数true设为公平锁,但公平锁表 现的性能不是很好
从功能角度:
ReentrantLock 比 Synchronized的同步操作更精细(因为可以像普通对象一样使用), 甚至实现 Synchronized没有的高级功能 等待可中断当持有锁的线程长期不释放锁的时候,正在等待的线程可以选择放弃等待,对处理执行 时间非常长的同步块很有用。 带超时的获取锁尝试在指定的时间范围内获取锁,如果时间到了仍然无法获取则返回。 可以判断是否有线程在排队等待获取锁。 可以响应中断请求与Synchronized不同,当获取到锁的线程被中断时,能够响应中断,中断异常将会 被抛出,同时锁会被释放。 可以实现公平锁
从锁释放角度:
Synchronized在JVM层面上实现的,不但可以通过一些监控工具监控 Synchronized的 锁定,而且在代码执行出现异常时,JVM会自动释放锁定,但是使用Lock则不行,Lock是通过代码实现 的,要保证锁定一定会被释放,就必须将 unLock()放到 finally{}中
从性能角度:
Synchronized早期实现比较低效,对比 ReentrantLock,大多数场景性能都相差较大。但 是在Java6中对其进行了非常多的改进, 在竞争不激烈时:Synchronized的性能要优于 ReetrantLock 在高竞争情况下:Synchronized的性能会下降几十倍,但是 ReetrantLock的性能能维持常态
今日分享就到这啦。请持续关注我们,带你了解更多Java相关干货知识。