Synchronized由什么样的缺陷? Java Lock是怎么弥补这些缺陷的?
Synchronized缺陷:
- 效率低:锁的释放情况少,只有代码执行完毕或者异常结束才会释放锁。不能中断一个正在使用锁的线程。
- 不够灵活:加锁和释放时机单一。
- 无法知道是否成功获得锁,lock可以拿到状态。
lock功能:
lock()
: 加锁unlock()
: 解锁tryLock()
: 尝试获取锁,返回一个boolean值tryLock(long,TimeUtil)
: 尝试获取锁,可以设置超时
Synchronized和Lock的对比,和选择?
- 存在层次
- Synchronized是一个关键字
- lock是一个接口
- 锁的释放
- Synchronized代码完成释放,发生异常释放。
- lock:在finally中释放锁。
- 锁的获取
- Synchronized前一个锁不释放后一个就拿不到
- lock,多个获取锁的方式,可以尝试获取锁,线程可以不一直等待
- 死锁产生使得释放
- Synchronized发生异常时自动释放获得的锁
- lock发生异常不主动释放,必须unlock释放,有可能会有死锁
- 锁的类型
- Synchronized可重入,不可中断非公平
- lock可重入 可判断状态 可公平可不公平
- 性能
- lock的同同步量可以更大。
-
用法
-
synchronized: 在需要同步的对象中加入此控制,synchronized可以加在方法上,也可以加在特定代码块中,括号中表示需要锁的对象。
-
Lock: 一般使用ReentrantLock类做为锁。在加锁和解锁处需要通过lock()和unlock()显示指出。所以一般会在finally块中写unlock()以防死锁。
-
- 底层实现
-
底层使用指令码方式来控制锁的,映射成字节码指令就是增加来两个指令:monitorenter和monitorexit。当线程执行遇到monitorenter指令时会尝试获取内置锁,如果获取锁则锁计数器+1,如果没有获取锁则阻塞;当遇到monitorexit指令时锁计数器-1,如果计数器为0则释放锁。
-
Lock: 底层是CAS乐观锁,依赖AbstractQueuedSynchronizer类,把所有的请求线程构成一个CLH队列。而对该队列的操作均通过Lock-Free(CAS)操作
-