`
edgar108
  • 浏览: 33417 次
  • 性别: Icon_minigender_1
社区版块
存档分类
最新评论

ReentrantReadWriteLock获取写锁和锁降级

阅读更多
      由于在AbstractQueuedSynchronizer中用 int state 表示锁状态,ReentrantReadWriteLock要在一个变量上维护读和写2个锁状态,ReentrantReadWriteLock把state 切分为2个部分,高16位表示读,低16位表示写,即
 
0000000000000000      0000000000000000
高16位读状态                低16位写状态
 
       同步状态通过位运算维护状态,假设当前同步状态为S,写状态等于S & 0x0000FFFF (低16位全为1,高16位全抹去),读状态等于S>>>16(无符号补零右移16位)
在 ReentrantReadWriteLock源码中:
static final int SHARED_SHIFT   = 16;
static final int SHARED_UNIT = (1 << SHARED_SHIFT);
static final int MAX_COUNT = (1 << SHARED_SHIFT) - 1;
static final int EXCLUSIVE_MASK = (1 << SHARED_SHIFT) - 1;

/** Returns the number of shared holds represented in count */
static int sharedCount(int c) { return c >>> SHARED_SHIFT; }
/** Returns the number of exclusive holds represented in count */
static int exclusiveCount(int c) { return c & EXCLUSIVE_MASK; }

0x0000FFFF 对应EXCLUSIVE_MASK, sharedCount(int c) 返回当前读状态,exclusiveCount返回当前写状态,和上面的计算方法一样。由此得出: S不等于0时,当写状态(S & 0x0000FFFF)等于0时,读状态(S>>>16)大于0,即读锁已被读取。
1   写锁的获取
ReentrantReadWriteLock.WriteLock的lock()方法:
public void lock() {
sync.acquire(1);
}
       调用内部Sync.acquire(int arg),即AbstractQueuedSynchronizer中的acquire(int  arg),之前已经对该方法分析过,该方法为模板方法,独占式获取锁,内部调用子类(ReentrantReadWriteLock.Sync)的tryAcquire(int arg):
protected final boolean tryAcquire(int acquires) {
/*
* Walkthrough:
* 1. If read count nonzero or write count nonzero
* and owner is a different thread, fail.
* 2. If count would saturate, fail. (This can only
* happen if count is already nonzero.)
* 3. Otherwise, this thread is eligible for lock if
* it is either a reentrant acquire or
* queue policy allows it. If so, update state
* and set owner.
*/
Thread current = Thread.currentThread();
int c = getState();
int w = exclusiveCount(c);
if (c != 0) {
// (Note: if c != 0 and w == 0 then shared count != 0)
if (w == 0 || current != getExclusiveOwnerThread())
return false;
if (w + exclusiveCount(acquires) > MAX_COUNT)
throw new Error("Maximum lock count exceeded");
// Reentrant acquire
setState(c + acquires);
return true;
}
if (writerShouldBlock() ||
!compareAndSetState(c, c + acquires))
return false;
setExclusiveOwnerThread(current);
return true;
}
该方法先获取同步状态c和写状态w。
(1)当c!=0 并且w = 0时 表示当前读锁被读取,以及当前线程不是获取写锁的线程时,则不能获取写锁。原因在于:读写锁要确保写锁的操作对读锁课件,如果允许读锁在已被获取的情况下获取写锁,那么正在运行的其他读线程就无法感知到写线程的操作。因此,只有等待其他读线程都释放了读锁,写锁才能被当前线程获取,一旦写锁被获取,其他读写线程的后续访问均被阻塞。
(2)当前线程为已获取写锁的线程时,更新state,返回成功。
(3)当c=0时,表示没有读写锁和写锁,获取写锁。
 
2 锁降级
       锁降级是指写锁降级为读锁。如果当前线程拥有写锁,然后将其释放,最后再获取读锁,这种分段完成的过程不叫锁降级。锁降级是指把持住(当前拥有)写锁,再获取到读锁,然后释放(先前拥有的)写锁的过程。锁降级中读锁的获取是否有必要呢?答案是必要的。主要是为了保证数据的可见性,如果当前线程不获取读锁而是直接释放写锁,假设此刻另一个线程T获取了写锁了并修改了数据,那么当前线程无法感知到线程T的数据更新。如果当前线程获取读锁,即遵循锁降级的步骤,则线程T将会被阻塞,直到当前线程使用数据并释放读锁之后,线程T才能获取写锁进行数据更新。
ReentrantReadWriteLock并不支持锁升级(把持读锁,获取写锁,最后释放读锁的过程)。目的也是保证数据可见性。如果读锁已经被多个线程获取,其中任意线程成功获取了写锁并更新了数据,则其更新数其他获取到读锁的线程是不可见的。
 

分享到:
评论

相关推荐

    8、读写锁ReentrantReadWriteLock&StampLock详解.pdf

    - **锁降级**:支持从写锁降级到读锁的操作。 ### 二、ReentrantReadWriteLock详解 #### 2.1 ReentrantReadWriteLock的实现 `ReentrantReadWriteLock`是Java并发库中提供的一个可重入的读写锁实现。它通过两个独立...

    深入浅出ReentrantReadWriteLock源码解析.docx

    此外,ReentrantReadWriteLock还提供了一些高级特性,如公平锁和非公平锁的选择,以及读写锁的升级和降级操作,使得在某些场景下能够实现更灵活的并发控制。 总之,ReentrantReadWriteLock是Java并发编程中非常重要...

    计算机软件-商业源码-利用读写锁保持线程同步.zip

    - **升级与降级**:某些高级读写锁支持读锁到写锁的升级或写锁到读锁的降级,这在某些复杂场景中很有用。 5. **Java中的ReentrantReadWriteLock**: Java的`ReentrantReadWriteLock`提供了可重入的读写锁功能,...

    行业分类-设备装置-双模式读写锁.zip

    这意味着一个已经持有读锁的线程在需要进行写操作时,可以不释放读锁直接升级为写锁,完成写操作后再降级回读锁。这样的设计可以在某些场景下减少锁竞争,提高效率。 在实际应用中,双模式读写锁广泛应用于数据库...

    23 按需上锁—ReadWriteLock详解.pdf

    - **锁降级**:如果一个线程持有了写锁,然后在不释放写锁的情况下获取读锁,这个过程称为锁降级。ReadWriteLock支持锁降级,意味着在完成写操作后,可以安全地切换到读模式,继续共享资源。 - **锁升级**:相反,...

    Java 读写锁实现原理浅析

    ReentrantReadWriteLock 是 Java 中的一个读写锁实现,它提供了公平性选择、可重入、可降级等特性。ReentrantReadWriteLock 的核心是由一个基于 AQS 的同步器 Sync 组成,然后由其扩展出 ReadLock(共享锁)和 ...

    java多线程-读写锁原理

    `ReentrantReadWriteLock`实现了完全的可重入性,这意味着线程在获取锁时,会检查当前线程是否已经持有锁,如果是,则增加锁的计数,而不是阻塞线程。释放锁时,会减少计数,只有当计数归零时才真正释放锁。 8. **...

    举例说明Java多线程编程中读写锁的使用

    - **公平性**:默认情况下,`ReentrantReadWriteLock`是非公平的,这意味着线程获取锁的顺序不是基于它们请求锁的时间顺序。如果需要公平性,可以通过构造函数传递`true`来创建公平锁。 - **活锁和饥饿**:虽然读写...

    Java多线程 ReentrantReadWriteLock原理及实例详解

    ReentrantReadWriteLock的可重入性允许线程在持有读锁或写锁时,能够升级或降级为另一种类型的锁,而不会造成死锁。 ### 6. 注意事项 - **解锁**:确保在每个获取锁的操作后都有对应的解锁操作,以避免死锁和资源...

    homework-ReadWriteLock-KristampsW-main.zip

    - **升级与降级**:从读锁到写锁的转换称为锁升级,从写锁到读锁的转换称为锁降级。Java的`ReentrantReadWriteLock`支持这样的操作。 2. **ReentrantReadWriteLock**: - `ReentrantReadWriteLock`是Java提供的可...

    多线程编程的核心思想.doc

    Java 中的 ReentrantReadWriteLock 类支持锁降级和锁升级。 七、AQS 底层实现 AQS(AbstractQueuedSynchronizer)是 Java 中的同步器框架,提供了一个队列来存储等待的线程。AQS 底层实现了 Lock 接口和 Condition...

    reader and writer

    5. **异常处理**:在尝试获取锁和释放锁的操作中,我们通常使用`try-catch-finally`块来确保在任何情况下都能正确释放锁,防止死锁。 在提供的源代码`线程 读者和写者的应用`中,可能包含了具体的实现细节,例如...

    【BAT必备】并发编程锁面试题

    公平锁保证线程获取锁的顺序,而非公平锁则不保证顺序性。 - **条件变量**:ReentrantLock提供了Condition接口,可以实现更复杂的同步逻辑。 **2.3 ReentrantReadWriteLock详解** - **声明与初始化**:`...

    multithreading:多线程示例。 辅助线程可以读取或写入,但要面对读写锁定,这会施加某些条件

    这些示例可能涵盖了如何创建线程、如何使用`ReentrantReadWriteLock`类、如何在代码中适当地获取和释放锁,以及如何处理可能的并发问题,如死锁和活锁等。 总的来说,理解和掌握多线程以及读/写锁的概念和使用是...

    第15讲 synchronized和ReentrantLock有什么区别呢?1

    ReentrantLock的一个关键特性是可设置公平性,这意味着线程可以按照它们请求锁的顺序来获取锁,而synchronized则是非公平的。此外,ReentrantLock还支持条件变量,允许更复杂的同步控制,如等待队列的管理。 性能...

    readwritelock.zip

    - **升级与降级**:从读锁升级到写锁或从写锁降级到读锁时需要特别注意,以防止死锁。在Java中,可以先释放当前锁再请求新锁来实现升级或降级。 - **锁的状态检查**:在尝试获取锁之前,可以检查当前锁的状态,避免...

    reader_writer:RICM4 - TP SE - 读写器

    2. **非公平性**:默认情况下,`ReentrantReadWriteLock`是非公平的,这意味着线程获取锁的顺序并不保证,可能会导致某些线程长时间等待。 3. **升级与降级**:线程可以从读锁升级到写锁(如果当前没有其他写锁或读...

    互联网高频Java后端面试题20道(适合1~3年)V1.0.81.docx

    Zookeeper 可以通过临时顺序节点实现分布式锁,创建节点的客户端会获得锁,当节点被删除时,Zookeeper 会通知其他等待的客户端,使它们有机会获取锁。 问题 12:谈谈你对 Spring Cloud Gateway 的理解,它有哪些...

    Java8新特性之StampedLock_动力节点Java学院整理

    `Lock`接口是在Java 5中引入的,它的出现提供了更细粒度的控制,例如支持尝试获取锁、定时等待和中断等待。其中`ReentrantLock`是其最常见的实现,它具有可重入性,允许线程多次获取同一锁。`ReentrantReadWriteLock...

Global site tag (gtag.js) - Google Analytics