Java面试题之多线程 在Java中Lock接口比synchronized块的优势是什么?你需要实现一个高效的缓存,它允许多个用户读,但只允许一个用户写,以此来保持它的完整性,你会怎样去实现它?
在Java中,Lock
接口相较于synchronized
块有几个显著的优势:
灵活性:Lock
接口提供了更灵活的锁定机制。你可以选择在不同的时间点获取和释放锁,而synchronized
块是隐式的,必须在代码块结束时自动释放锁。
可中断性:使用Lock
可以实现可中断的锁请求。你可以在尝试获取锁时设置一个超时时间,或者在等待锁的过程中响应中断,而synchronized
块则不支持这种特性。
公平性:Lock
接口可以选择公平性策略,确保线程按照请求锁的顺序获取锁,而synchronized
块是非公平的,可能导致某些线程长时间得不到锁。
读写锁:Lock
接口提供了ReadWriteLock
,允许多个线程同时读取,但在写入时会独占锁,这对于读多写少的场景非常有效。
为了实现一个高效的缓存,允许多个用户读,但只允许一个用户写,我们可以使用ReadWriteLock
。以下是一个简单的实现示例:
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
public class Cache<K, V> {
private final Map<K, V> cache = new HashMap<>();
private final ReadWriteLock lock = new ReentrantReadWriteLock();
// 读取缓存
public V get(K key) {
lock.readLock().lock(); // 获取读锁
try {
return cache.get(key);
} finally {
lock.readLock().unlock(); // 释放读锁
}
}
// 写入缓存
public void put(K key, V value) {
lock.writeLock().lock(); // 获取写锁
try {
cache.put(key, value);
} finally {
lock.writeLock().unlock(); // 释放写锁
}
}
// 清空缓存
public void clear() {
lock.writeLock().lock(); // 获取写锁
try {
cache.clear();
} finally {
lock.writeLock().unlock(); // 释放写锁
}
}
}
读操作:在get
方法中,我们获取读锁,这样多个线程可以同时读取缓存数据,而不会互相阻塞。
写操作:在put
和clear
方法中,我们获取写锁,这样在写入或清空缓存时,其他线程的读操作会被阻塞,确保数据的一致性。
异常处理:在finally
块中释放锁,确保即使在发生异常时也能正确释放锁,避免死锁。
这种实现方式能够有效地支持高并发的读操作,同时保证写操作的安全性和完整性。