理解ReentrantLock
显式锁
协调共享对象的访问的三个关键词 synchronized 、volatile和lock
Lock and ReentrantLock
内置锁的局限性:
- 无法 中断一个正在等待获取锁的线程
- 无法 在请求获取一个锁时 无限等待下去
- 内置锁必须在获取该锁的代码块中释放,无法实现非阻塞结构的加锁规则
轮询锁和定时锁
同时获取两个锁时才进行操作 显式地索取和释放锁,那么在索取锁的时候可以设定一个超时时间,如果超过这个时间还没索取到锁,则不会继续堵塞而是放弃此次任务。 tryLock时设置
public boolean trySendOnSharedLine(String message,
long timeout, TimeUnit unit)
throws InterruptedException {
long nanosToLock = unit.toNanos(timeout)
- estimatedNanosToSend(message);
if (!lock.tryLock(nanosToLock, NANOSECONDS))
return false;
try {
return sendOnSharedLine(message);
} finally {
lock.unlock();
}
}
可中断的锁获取操作
lock.lockInterruptibly(); 能够在获取锁的同时保持对中断的响应,tryLock同样也能响应中断,适用于实现 一个定时和可中断的锁获取
public boolean sendOnSharedLine(String message)
throws InterruptedException {
lock.lockInterruptibly();
try {
return cancellableSendOnSharedLine(message);
} finally {
lock.unlock();
}
}
private boolean cancellableSendOnSharedLine(String message) throws InterruptedException {
/* send something */
return true;
}
非块结构的加锁(非阻塞?)
- 内置锁是基于块结构的加锁
- 锁分段技术,不同的线程可以独立的对链表的不同部分进行操作。 每个节点的锁将保护链接指针以及该节点中存储的数据,遍历或者修改时,获取当前节点的锁,直到获得下个节点的锁。 连锁式加锁
公平性
非公平锁和公平锁,非公平锁允许插队。插队是指 当一个线程请求非公平锁时,在发出请求的同时该锁的状态变为可用,那么可跳过队列中所有等待线程。
如何选择synchronized和ReentrantLock
在一些内置锁无法满足的情况下,ReentrantLock可以作为一种高级工具: 实现 可定时、可轮询和可中断的锁获取操作,公平队列,非块结构的锁。 否则优先使用synchronized。
读-写锁
放宽粒度 允许读-读操作,多个线程同时读。 读数据时确保读取最新数据,读数据时不会又其他线程修改数据。