synchronized和Lock有什么不同呢?
下文是日常面试中,常见的synchronized和Lock区别说明,如下所示
区别1:两者的使用方式不同
synchronized:
是java中的关键字(类似于if...else...)
synchronized获取锁以及释放锁由Java虚拟机(JVM)实现
ReentrantLock是类层面的实现:
锁获取以及锁释放由用户自己操作
注意事项:
ReentrantLock在lock()获取锁后
必须手动unlock()释放锁
释放锁的代码我们通常写在finally语句块中
例
/** 创建可重入锁 */
private static final ReentrantLock lock = new ReentrantLock();
public void demoSync() {
synchronized (lock) {
// 业务代码
}
}
public void demoLock() {
lock.lock();
try {
// 业务代码
} finally {
lock.unlock();
}
}
区别二:灵活性
synchronized使用简单
而
ReentrantLock锁机制给用户的使用提供了极大的灵活性。
ReentrantLock灵活性
我们可以在Hashtable和ConcurrentHashMap两个容器中查看
Hashtable中使用synchronized锁,对整张Hash表进行加锁
ConcurrentHashMap则使用ReentrantLock实现锁分离
锁只是segment(片段)
ConcurrentHashMap源码
/**
* Stripped-down version of helper class used in previous version,
* declared for the sake of serialization compatibility
*/
static class Segment<K,V> extends ReentrantLock implements Serializable {
private static final long serialVersionUID = 2249069246763182397L;
final float loadFactor;
Segment(float lf) { this.loadFactor = lf; }
}
/**
* Saves the state of the {@code ConcurrentHashMap} instance to a
* stream (i.e., serializes it).
* @param s the stream
* @throws java.io.IOException if an I/O error occurs
* @serialData
* the key (Object) and value (Object)
* for each key-value mapping, followed by a null Pair.
* The key-value mappings are emitted in no particular order.
*/
private void writeObject(java.io.ObjectOutputStream s)
throws java.io.IOException {
// For serialization compatibility
// Emulate segment calculation from previous version of this class
int sshift = 0;
int ssize = 1;
while (ssize < DEFAULT_CONCURRENCY_LEVEL) {
++sshift;
ssize <<= 1;
}
int segmentShift = 32 - sshift;
int segmentMask = ssize - 1;
@SuppressWarnings("unchecked")
Segment<K,V>[] segments = (Segment<K,V>[])
new Segment<?,?>[DEFAULT_CONCURRENCY_LEVEL];
for (int i = 0; i < segments.length; ++i)
segments[i] = new Segment<K,V>(LOAD_FACTOR);
s.putFields().put("segments", segments);
s.putFields().put("segmentShift", segmentShift);
s.putFields().put("segmentMask", segmentMask);
s.writeFields();
Node<K,V>[] t;
if ((t = table) != null) {
Traverser<K,V> it = new Traverser<K,V>(t, t.length, 0, t.length);
for (Node<K,V> p; (p = it.advance()) != null; ) {
s.writeObject(p.key);
s.writeObject(p.val);
}
}
s.writeObject(null);
s.writeObject(null);
segments = null; // throw away
}
区别三:锁策略
synchronized是不公平锁
而
ReentrantLock可指定锁是公平的还是非公平的
可使用ReentrantLock(boolean fair)构造方法fair指定公平策略
当使用公平排序策略
则fair参数为true
公平锁和非公平锁简介
公平锁
公平锁是指多个线程按照申请锁的顺序来获取锁
线程直接进入队列中排队,队列中的第一个线程才能获得锁
非公平锁
非公平锁是多个线程加锁时直接尝试获取锁
能抢到锁到直接占有锁
抢不到才会到等待队列的队尾等待
区别四:等待/通知机制
synchronized 实现等待/通知机制通知的线程是随机 ReentrantLock 实现等待/通知机制可以有选择性地通知。
区别五:锁自身信息
ReentrantLock 提供给用户多种方法用于获取锁的信息
如:
可以获取 Lock 是否被当前线程获得
Lock 被同一个线程调用了几次
Lock 是否被任意线程获取等等
synchronized由JVM维护,所以操作的空间比较小
也是由灵活性决定的
版权声明
本文仅代表作者观点,不代表本站立场。
本文系作者授权发表,未经许可,不得转载。


