前言
最近面试经常遇到过几次的一个问题就是,synchronized与Lock的区别?
感觉每次答得都不够全面,不是漏了这就是漏了那的,为了加深记忆特地追加一篇博客来记录(我可真是个小机灵鬼)。
为了详细的列举出这俩货的异同,这里分一下几个角度来对比:
一、存在层次上
synchronized:就是Java在JVM层次上提供的一个关键字,能直接拿来在方法或者代码块上面用,此时被标注的方法称为同步方法,被标注的代码块则被称为同步代码块。
Lock:是Java并发包下的一个接口,下面有它的一堆实现类,其中最典型的就是ReentrantLock了。
二、获取锁的方式
synchronized:标注在方法或者代码块上,就能获得指定对象的对象锁,假设A线程先通过synchronized获得了锁,B线程再想去获得改对象的锁就得阻塞等待。
Lock:相对与synchronized就有千奇百怪获取锁的的方式,举例如下:
// 获取锁,没获取到阻塞
public void lock()
// 尝试获取锁,获取到返回true,没获取到立刻返回false,不阻塞
public boolean tryLock():
// 尝试获取锁,在等待指定时间获取到返回true,没获取到返回false
public boolean tryLock(long timeout, TimeUnit unit)
// 尝试获取锁,若未获取到可响应中断,只是设置一个中断标识
public void lockInterruptibly()
可见与synchronized相比Lock还是灵活许多。
三、释放锁的方式
synchronized:JVM比较贴心的帮我们处理了这步,只要程序正常走出同步方法或者同步代码块,JVM就会自动帮我们释放该线程持有的对象锁。
Lock:这就需要我们主动去释放了,为了防止有时候因为程序异常退出导致程序没有走到释放掉锁的那一步导致线程死锁,我们一般得在获取锁的代码块或者方法上套异常try-catch-finally,并在finally块中做释放锁的动作。
四、锁的状态
synchronized:是无法知道该线程有没有获取到锁的
Lock:可以通过下面方法来判断:
final boolean isLocked()
五、锁的类型
synchronized:
1、可重入(也就是可以重复获得锁)
2、不可中断(获取锁被阻塞时不可从外部中断)
3、非公平(无法保证线程获取锁的的顺序)
Lock:
1、可重入
2、可中断
3、可公平
六、适用场景
synchronized:基于悲观锁的概念,在JDK1.6之前直接给对象上锁,跑完同步方法或者同步代码块再解锁等着下一个线程上锁。到了JDK1.6之后再其基础上做了一些优化,即提出无锁、偏向锁、轻量级锁、重量级锁的概念(篇幅有限,这四种锁类别得等到下一篇博客再细说了),降低了加锁解锁的频率。一定程度上提示了它的性能。适用高并发的线程冲突高的场景,可以进过锁膨胀之后直接上锁然后进行有序处理。
Lock:基于乐观锁的概念,底层是基于CAS机制来实现的,即需要不断轮询判断自己是否满足获取到锁的条件。在低并发下可能没其他线程跟当前线程抢占锁,所以一次轮询就获得锁了,但是高并发下可能需要轮询很久才能获得,这时候就比较占CPU了。所以Lock一般则被用在低并发的场景。
总结
如有错漏,敬请指出,万分感谢