synchronized与ReenTranLock的区别
1.synchronized 回顾
- 表示原子性和可见性
- 原子性:一次只有一个线程能执行lock保护的代码
- 可见性:线程更新了变量后会将其更新到主内存里面
volatile可以实现可见性,不能实现原子性
2.对 synchronized 的改进
在最近的 JVM 中,没有争用的同步(一个线程拥有锁的时候,没有其他线程企图获得锁)的性能成本还是很低的。(也不总是这样;早期 JVM 中的同步还没有优化,所以让很多人都这样认为,但是现在这变成了一种误解,人们认为不管是不是争用,同步都有很高的性能成本。)
2.1.ReentrantLock 类
重入锁意味着什么呢?简单来说,它有一个与锁相关的获取计数器,如果拥有锁的某个线程再次得到锁,那么获取计数器就加1,然后锁需要被释放两次才能获得真正释放。这模仿了 synchronized 的语义;如果线程进入由线程已经拥有的监控器保护的 synchronized 块,就允许线程继续进行,当线程退出第二个(或者后续) synchronized 块的时候,不释放锁,只有线程退出它进入的监控器保护的第一个 synchronized 块时,才释放锁。
用 ReentrantLock 保护代码块。
Lock lock=new ReentrantLock(); try { lock.lock(); } finally { lock.unlock(); }
可以看到 Lock 和 synchronized 有一点明显的区别 —— lock 必须在 finally 块中释放。否则,如果受保护的代码将抛出异常,锁就有可能永远得不到释放!这一点区别看起来可能没什么,但是实际上,它极为重要。除此之外,与目前的 synchronized 实现相比,争用下的 ReentrantLock 实现更具可伸缩性。(在未来的 JVM 版本中,synchronized 的争用性能很有可能会获得提高。)这意味着当许多线程都在争用同一个锁时,使用 ReentrantLock 的总体开支通常要比 synchronized 少得多。
Condition 的方法与 wait 、 notify 和 notifyAll 方法类似,分别命名为 await 、 signal 和 signalAll,因为它们不能覆盖 Object 上的对应方法。
公平锁
如果查看 Javadoc,您会看到, ReentrantLock 构造器的一个参数是 boolean 值,它允许您选择想要一个 公平(fair)锁,还是一个 不公平(unfair)锁。公平锁使线程按照请求锁的顺序依次获得锁;而不公平锁则允许直接获取锁,在这种情况下,线程有时可以比先请求锁的其他线程先得到锁。
3.要不要抛弃synchronized
- 不用释放锁
- 方便调试,能标记死锁或其他异常行为的来源