Lock与ReentrantLock
来源:互联网 发布:禁闭岛影评 知乎 编辑:程序博客网 时间:2024/06/05 10:56
Lock提供了一种无条件的、可轮询的、定时的、可中断的锁获取操作,所有加锁和解锁的方法都是显式的。
Lock接口如下:
public interface Lock { void lock(); void lockInterruptibly() throws InterruptedException; boolean tryLock(); boolean tryLock(long time, TimeUnit unit) throws InterruptedException; void unlock(); Condition newCondition();}
ReentrantLock实现了Lock,提供了与Synchronized相同的互斥性和内存可见性。ReentrantLock提供了可重入的加锁语义。与Synchronized相比,它还为处理锁的不可用性问题提供了更高的灵活性。
内置锁的局限性:
1.无法中断一个正在等待获取锁的线程
2.无法再请求获取一个锁时无限地等待下去
3.必须在获取该锁的代码块中释放
4.无法实现非阻塞结构的加锁规则
5.死锁严重(恢复程序的唯一方法是重新启动程序,防止死锁的唯一方法是在构造程序时避免出现不一致的锁顺序)
使用ReentrantLock来保护对象状态
Lock lock = new ReentrantLock();...lock.lock();try{//更新对象状态//捕获异常,并在必要时恢复不变性条件}finally{lock.unlock(); //必须关闭,不然很危险}
必须在finally块中释放锁,否则,如果在被保护的代码中抛出了异常,那么这个锁永远都无法释放。当使用加锁时,还必须考虑在try块中抛出异常的情况,如果可能使对象处于某种不一致的状态,那么就需要更多的try-catch或try-finally代码块。
当忘记关闭时,将很难追踪到最初发生错误的位置,因为没有记录应该释放锁的位置和时间。
ReentrantLock不能完全替代Synchronized的原因:它更危险,可能忘记关闭锁。
ReentrantLock源代码基本如下:
public class ReentrantLock implements Lock, java.io.Serializable { private final Sync sync; abstract static class Sync extends AbstractQueuedSynchronizer { abstract void lock(); final boolean nonfairTryAcquire(int acquires) { final Thread current = Thread.currentThread(); int c = getState(); if (c == 0) { if (compareAndSetState(0, acquires)) { setExclusiveOwnerThread(current); return true; } } else if (current == getExclusiveOwnerThread()) { int nextc = c + acquires; if (nextc < 0) // overflow throw new Error("Maximum lock count exceeded"); setState(nextc); return true; } return false; } protected final boolean tryRelease(int releases) { int c = getState() - releases; if (Thread.currentThread() != getExclusiveOwnerThread()) throw new IllegalMonitorStateException(); boolean free = false; if (c == 0) { free = true; setExclusiveOwnerThread(null); } setState(c); return free; } protected final boolean isHeldExclusively() { // While we must in general read state before owner, // we don't need to do so to check if current thread is owner return getExclusiveOwnerThread() == Thread.currentThread(); } final ConditionObject newCondition() { return new ConditionObject(); } final Thread getOwner() { return getState() == 0 ? null : getExclusiveOwnerThread(); } final int getHoldCount() { return isHeldExclusively() ? getState() : 0; } final boolean isLocked() { return getState() != 0; } private void readObject(java.io.ObjectInputStream s) throws java.io.IOException, ClassNotFoundException { s.defaultReadObject(); setState(0); // reset to unlocked state } } static final class NonfairSync extends Sync { final void lock() { if (compareAndSetState(0, 1)) setExclusiveOwnerThread(Thread.currentThread()); else acquire(1); } protected final boolean tryAcquire(int acquires) { return nonfairTryAcquire(acquires); } } static final class FairSync extends Sync { final void lock() { acquire(1); } protected final boolean tryAcquire(int acquires) { final Thread current = Thread.currentThread(); int c = getState(); if (c == 0) { if (!hasQueuedPredecessors() && compareAndSetState(0, acquires)) { setExclusiveOwnerThread(current); return true; } } else if (current == getExclusiveOwnerThread()) { int nextc = c + acquires; if (nextc < 0) throw new Error("Maximum lock count exceeded"); setState(nextc); return true; } return false; } } public ReentrantLock() { sync = new NonfairSync(); } public ReentrantLock(boolean fair) { sync = fair ? new FairSync() : new NonfairSync(); } public void lock() { sync.lock(); } public void lockInterruptibly() throws InterruptedException { sync.acquireInterruptibly(1); } public boolean tryLock() { return sync.nonfairTryAcquire(1); } public boolean tryLock(long timeout, TimeUnit unit) throws InterruptedException { return sync.tryAcquireNanos(1, unit.toNanos(timeout)); } public void unlock() { sync.release(1); } public Condition newCondition() { return sync.newCondition(); } public int getHoldCount() { return sync.getHoldCount(); } public boolean isHeldByCurrentThread() { return sync.isHeldExclusively(); } public boolean isLocked() { return sync.isLocked(); } public final boolean isFair() { return sync instanceof FairSync; } protected Thread getOwner() { return sync.getOwner(); } public final boolean hasQueuedThreads() { return sync.hasQueuedThreads(); } public final boolean hasQueuedThread(Thread thread) { return sync.isQueued(thread); } public final int getQueueLength() { return sync.getQueueLength(); } protected Collection<Thread> getQueuedThreads() { return sync.getQueuedThreads(); } public boolean hasWaiters(Condition condition) { if (condition == null) throw new NullPointerException(); if (!(condition instanceof AbstractQueuedSynchronizer.ConditionObject)) throw new IllegalArgumentException("not owner"); return sync.hasWaiters((AbstractQueuedSynchronizer.ConditionObject)condition); } public int getWaitQueueLength(Condition condition) { if (condition == null) throw new NullPointerException(); if (!(condition instanceof AbstractQueuedSynchronizer.ConditionObject)) throw new IllegalArgumentException("not owner"); return sync.getWaitQueueLength((AbstractQueuedSynchronizer.ConditionObject)condition); } protected Collection<Thread> getWaitingThreads(Condition condition) { if (condition == null) throw new NullPointerException(); if (!(condition instanceof AbstractQueuedSynchronizer.ConditionObject)) throw new IllegalArgumentException("not owner"); return sync.getWaitingThreads((AbstractQueuedSynchronizer.ConditionObject)condition); } public String toString() { Thread o = sync.getOwner(); return super.toString() + ((o == null) ? "[Unlocked]" : "[Locked by thread " + o.getName() + "]"); }}
1.轮询锁与定时锁
轮询锁与定时锁是由tryLock方法实现的,与无条件的锁获取操作相比,它们具有更完善的错误恢复机制。它们可以避免死锁的发生。
通过tryLock来避免锁顺序死锁:使用tryLock来获取两个锁,如果不能同时获得,那么就回退并重新尝试。在休眠时间中包括固定部分和随机部分,从而降低发生活锁的可能性。如果在指定时间内不能获得所有需要的锁,那么transferMoney将返回一个失败状态,从而使该操作平缓地失败。
public boolean transferMoney(Account fromAcct,Account toAcct,DollarAmount amount,long timeout,TimeUnit unit) throws InsufficientFundsException,InterruptedException{long fixedDelay = getFixedDelayComponentNanos(timeout,unit);long randMod = getRandomDelayModulesNanos(timeout,unit);long stopTime = System.nanoTime() + unit.toNanos(timeout);while(true){if(fromAcct.lock.tryLock()){try{if(toAcct.lock.tryLock()){try{if(fromAcct.getBalances.compareTo(amount)<0){throw new InsufficientFundsException();}else{fromAcct.debit(amount);toAcct.credit(amount);return true;}}finally{toAcct.lock.unlock();}}}finally{fromAcct.lock.unlock();}} if(System.nanoTime()<stopTime){ return false; } NANOSECONDS.sleep(fixedDelay + rnd.nextLong() % randMod); }}带有时间限制的加锁
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();}}
2.可中断的锁获取操作
可中断的锁获取操作同样能在可取消的操作中使用加锁。
lockInterruptibly方法能够在获得锁的同时保持对中断的响应,并且由于它包含在Lock中,因此无需创建其它类型的不可中断阻塞机制。
可中断的锁获取操作的标准结构比普通的锁获取操作略微复杂一些,因为需要两个try块。(如果在可中断的锁获取操作中抛出了InterruptedException,那么可以使用标准的try-finally加锁模式。)
定时的tryLock同样能响应中断,因此当需要实现一个定时的和可中断的锁获取操作时,可以使用tryLock方法。
可中断的锁获取操作
public boolean sendOnSharedLine(String message) throws InterruptedException{lock.lockInterruptibly();try{return cancellableSendOnShareLine(message);}finally{lock.unlock();}}private boolean cancellableSendOnSharedLine (String message) throws InterruptedException{...}
3.非块结构的加锁
通过降低锁的粒度可以提高代码的可伸缩性。锁分段技术在基于散列的容器中实现了不同的散列链,以便使用不同的锁。我们可以通过采用类似的原则来降低链表中锁的粒度,即为每个链表节点使用一个独立的锁,使不同的线程能独立地对链表的不同部分进行操作。每个节点的锁将保护连接指针以及在该节点中存储的数据,因此当遍历或修改链表时,我们必须持有该节点上的这个锁,直到获得了下一个节点的锁,只有这样,才能释放前一个节点上的锁。
连锁式加锁(Hand-Over-Hand Locking)或锁耦合(Lock Coupling)
- Lock与ReentrantLock
- ReentrantLock解析,lock与unlock方法分析
- 《深入浅出 Java Concurrency》—锁机制(一)Lock与ReentrantLock
- 《深入浅出 Java Concurrency》—锁机制(一)Lock与ReentrantLock
- JAVA多线程-Lock的使用(一)-ReentrantLock与Condition
- 分析ReentrantLock之lock
- 显式锁Lock、ReentrantLock
- 码农小汪-ReentrantLock-lock方法
- sychronized、lock、reentrantLock分析
- sychronized、ReentrantLock、lock区别
- Lock的使用---ReentrantLock
- jdk源码解读-并发包-Lock-ReentrantLock(1)--lock()与unlock()方法走读
- ReentrantLock代码剖析之ReentrantLock.lock
- ReentrantLock代码剖析之ReentrantLock.lock
- Java Concurrent Lock ReentrantLock简介
- synchronized和lock(reentrantlock) 区别
- synchronized和lock(reentrantlock) 区别
- 显示锁Lock和ReentrantLock
- UGUI - 制作Slider进度条
- Spark2.0源码阅读环境搭建 开发环境搭建
- 数据结构实验之栈八:栈的基本操作
- 由于惰性加载一些页面,导致排序时,不能加载其它的页面。因此需要滚动才能加载。
- 算法优化二——如何提高人脸检测正确率
- Lock与ReentrantLock
- python 文件操作学习 Tkinter GUI
- jquery应用一(导航菜单)
- Gson解析
- Cent os 6.3上安装rlwrap
- [BZOJ4565][Haoi2016]字符合并(状压dp)
- gradle下载更新依赖库失败的解决办法 - 依赖库下载加速1000%
- UpdateDriverForPlugAndPlayDevices在64位操作系统执行失败解决方案
- Codeforces Round #366 (Div. 2)