Lock锁及其常见子类
Lock
public interface Lock {
常用方法
// 获取锁
void lock();
// 释放锁
void unlock();
// 可以被中断的锁
void lockInterruptibly() throws InterruptedException;
// 尝试获取锁并返回当前锁的获取情况。
boolean tryLock();
// 尝试获取一段时间的锁并返回当前锁的情况
boolean tryLock(long time, TimeUnit unit) throws InterruptedException;
// 获取监听器 三个主要方法await()、signal()、signalAll()
Condition newCondition();
Lock和synchronized的区别?
- synchronized是java的关键字,Lock是一个接口
- synchronized无法判断锁的状态,Lock可以判断是否获取到锁
- synchronized会自动释放锁,Lock必须手动释放锁
- synchronized线程1(获得锁,阻塞)线程2(等待,继续等待),Lock有可能插队
- synchronized可重入锁、不可中断、非公平锁,Lock可重入锁、可中断、可以设置公平/非公平
- synchronize适合锁少量代码的同步问题,Lock适合锁大量代码的同步问题
ReentrantLock
public class ReentrantLock implements Lock, java.io.Serializable {
可重入锁,可以用来替换synchronized
synchronized是独占锁,开锁解锁自动进行。ReentrantLock也是独占锁,开锁解锁通过 lock/unlock
方法手动进行
synchronized是可重入的,ReentrantLock也是可重入的,但是加锁解锁的次数必须要一样
synchronized不可以响应中断,一个线程获取不到锁就一直阻塞着。ReentrantLock则可以响应中断。
ReentrantLock可以实现公平锁机制,通过构造器设置
Lock lock = new ReentrantLock(true)
lock.lock();
tryLock()
方法是非公平实现,所以就算是构造了公平的ReentrantLock锁,调用该方法也不能保证公平,如果要遵从公平规则可以使用tryLock(long timeout, TimeUnit unit)
ReentrantLock的lock()
方法就是调用他内部类Sync
下的lock()
,而lock()
中调用的acquire(1)
则是继承至 AbstractQueuedSynchronizer
ReentrantReadWriteLock
public class ReentrantReadWriteLock implements ReadWriteLock, java.io.Serializable {
读写锁,分为读锁和写锁。读锁允许同一时刻被多个读线程访问,写锁是独占锁使用时所有读线程和写线程都会被阻塞。
支持非公平性(默认)和公平的锁获取方式
支持重入,读锁获取后能再次获取读锁,写锁获取之后能够再次获取写锁,同时也能够获取读锁
锁降级,写锁能够降级成为读锁:获取写锁->获取读锁->释放写锁->释放读锁
不支持读锁升级为写锁
读锁其实就是调用的 acquireShared
和 releaseShared
共享锁
写锁其实就是调用的 acquire
和 release
public static void main(String[] args) {
ExecutorService executorService = Executors.newFixedThreadPool(20);
Cache cache = new Cache();
for (int i = 1; i <= 100; i++) {
final int temp = i;
executorService.submit(() -> {
cache.put(String.valueOf(temp), null);
});
}
for (int i = 1; i <= 100; i++) {
final int temp = i;
executorService.submit(() -> {
cache.get(String.valueOf(temp));
});
}
}
static class Cache{
ReadWriteLock lock = new ReentrantReadWriteLock();
private final Map<String, String> map = Maps.newHashMap();
public void put(String key, String value){
lock.writeLock().lock();
System.out.println(Thread.currentThread().getName() + "写线程占用");
map.put(key, value);
System.out.println(Thread.currentThread().getName() + "写线程释放");
lock.writeLock().unlock();
}
public void get(String key){
lock.readLock().lock();
System.out.println(Thread.currentThread().getName() + "读线程占用");
map.get(key);
System.out.println(Thread.currentThread().getName() + "读线程释放");
lock.readLock().unlock();
}
}