当前位置: 首页 > news >正文

外贸网站建设 全球搜谷歌浏览器官方app下载

外贸网站建设 全球搜,谷歌浏览器官方app下载,济南天桥区网站建设公司,营销型网站审定标准ReentrantReadWriteLock 提供了读写分离的锁机制#xff0c;允许多个线程同时获取读锁#xff0c;但写锁是独占的。它支持可重入、公平/非公平策略、锁降级等高级特性。 内部类结构 Sync#xff1a;抽象同步器#xff0c;基于 AbstractQueuedLongSynchronizerReadLock/Wr…ReentrantReadWriteLock 提供了读写分离的锁机制允许多个线程同时获取读锁但写锁是独占的。它支持可重入、公平/非公平策略、锁降级等高级特性。 内部类结构 Sync抽象同步器基于 AbstractQueuedLongSynchronizerReadLock/WriteLock分别封装读写锁操作FairSync/NonfairSync公平性策略实现 线程安全保证 使用 CAS 操作保证状态更新的原子性基于 AQS 的等待队列管理阻塞线程通过 volatile 变量和内存屏障保证可见性 1. 核心能力概述 读写分离机制 读锁共享多个线程可以同时持有读锁写锁独占只有一个线程可以持有写锁读写互斥读锁和写锁不能同时被持有 2. 关键特性详解 2.1 可重入性 // 支持同一线程多次获取同一类型的锁 if (firstReader current) {firstReaderHoldCount; } else {// 通过 HoldCounter 记录每个线程的持有次数rh.count; }2.2 公平性策略 非公平模式默认NonfairSync final boolean writerShouldBlock() {return false; // 写线程可以直接抢占 }公平模式FairSync  final boolean writerShouldBlock() {return hasQueuedPredecessors(); // 检查是否有等待更久的线程 }2.3 锁降级支持 支持从写锁降级到读锁但不支持从读锁升级到写锁 // 典型的锁降级模式 rwl.writeLock().lock(); try {// 更新数据rwl.readLock().lock(); // 在释放写锁前获取读锁 } finally {rwl.writeLock().unlock(); // 释放写锁仍持有读锁 }状态编码设计 使用一个 long 型变量同时记录读写锁状态 static final int SHARED_SHIFT 32; static final long SHARED_UNIT (1L SHARED_SHIFT); static final long EXCLUSIVE_MASK (1L SHARED_SHIFT) - 1;// 高32位读锁计数 static int sharedCount(long c) { return (int)(c SHARED_SHIFT); } // 低32位写锁计数 static int exclusiveCount(long c) { return (int)(c EXCLUSIVE_MASK); }写锁获取逻辑 写锁 (tryAcquire) 的逻辑相对简单 独占性: 写锁是独占的任何时候最多只有一个线程可以持有写锁。状态检查: 如果当前没有锁 (state 0)则尝试通过 CAS 获取锁。如果失败比如因为公平策略 writerShouldBlock() 返回 true或者 CAS 竞争失败tryAcquire 直接返回 false。后续的排队和唤醒逻辑由 AQS 框架处理。如果当前已有锁 (state ! 0) 如果存在读锁 (写计数 w 为 0)则获取失败。如果存在写锁但持有者不是当前线程则获取失败。如果当前线程已持有写锁重入则直接增加写锁计数。 重入处理: 写锁的重入计数直接记录在 state 的低位。判断重入和增加计数相对直接。AQS 框架: 对于获取失败的情况例如锁被其他线程持有或 CAS 失败AQS 框架会自动处理线程的入队、阻塞和后续的唤醒重试。tryAcquire 只需要负责单次尝试获取的逻辑。 因此写锁的 tryAcquire 方法已经能够完整地处理单次尝试获取锁的各种情况包括重入。如果一次 tryAcquire 失败AQS 会负责后续的流程不需要一个额外的 full 版本来进行内部循环重试或处理更复杂的重入逻辑。 protected final boolean tryAcquire(long acquires) {Thread current Thread.currentThread();long c getState();long w exclusiveCount(c);if (c ! 0) {// 1. 如果有读锁或其他线程持有写锁失败if (w 0 || current ! getExclusiveOwnerThread())return false;// 2. 重入检查if (w exclusiveCount(acquires) MAX_COUNT)throw new Error(Maximum lock count exceeded);setState(c acquires);return true;}// 3. 尝试获取写锁if (writerShouldBlock() || !compareAndSetState(c, c acquires))return false;setExclusiveOwnerThread(current);return true; }readHolds 和 cachedHoldCounter  位于 ReentrantReadWriteLock.java 中 Sync 类内部。 这两个字段都与读锁的重入计数有关。ReentrantReadWriteLock 允许同一个线程多次获取读锁或写锁这种行为称为重入。 readHolds: ReentrantReadWriteLock.java /*** The number of reentrant read locks held by current thread.* Initialized only in constructor and readObject.* Removed whenever a threads read hold count drops to 0.*/private transient ThreadLocalHoldCounter readHolds;类型: readHolds 是一个 ThreadLocalHoldCounter 类型的成员变量。ThreadLocalHoldCounter 继承自 ThreadLocalHoldCounter。这意味着每个线程都有自己独立的 HoldCounter 副本。HoldCounter: 这个内部类非常简单它包含两个字段 int count: 表示当前线程持有读锁的重入次数。final long tid: 当前线程的ID用于避免在 HoldCounter 对象生命周期结束后依然持有对 Thread 对象的引用从而防止内存泄漏。 /*** A counter for per-thread read hold counts.* Maintained as a ThreadLocal; cached in cachedHoldCounter.*/ static final class HoldCounter {int count; // initially 0// Use id, not reference, to avoid garbage retentionfinal long tid LockSupport.getThreadId(Thread.currentThread()); }/*** ThreadLocal subclass. Easiest to explicitly define for sake* of deserialization mechanics.*/ static final class ThreadLocalHoldCounterextends ThreadLocalHoldCounter {public HoldCounter initialValue() {return new HoldCounter();} }作用: readHolds 的核心作用是精确地追踪和管理每个线程获取读锁的重入次数。当一个线程第一次获取读锁时会为其创建一个 HoldCounter 并存入其线程本地存储中之后每次重入获取读锁对应 HoldCounter 的 count 就会增加每次释放读锁count 就会减少。当一个线程的 HoldCounter 的 count 降为0时表示该线程不再持有读锁此时会从 ThreadLocal 中移除这个 HoldCounter。 cachedHoldCounter: ReentrantReadWriteLock.java /*** The hold count of the last thread to successfully acquire* readLock. This saves ThreadLocal lookup in the common case* where the next thread to release is the last one to* acquire. This is non-volatile since it is just used* as a heuristic, and would be great for threads to cache.** pCan outlive the Thread for which it is caching the read* hold count, but avoids garbage retention by not retaining a* reference to the Thread.** pAccessed via a benign data race; relies on the memory* models final field and out-of-thin-air guarantees.*/private transient HoldCounter cachedHoldCounter;类型: cachedHoldCounter 是一个 HoldCounter 类型的成员变量。作用: 这是一个性能优化的手段。它缓存了最后一个成功获取读锁的线程的 HoldCounter。优化原理: 在很多情况下一个线程获取读锁后紧接着就会释放该读锁。如果下一个释放读锁的线程恰好是上一个获取读锁的线程那么就可以直接使用 cachedHoldCounter 中缓存的 HoldCounter而无需通过 readHolds.get() 进行 ThreadLocal 的查找。ThreadLocal 的查找相对而言会有一些开销通过这种缓存机制可以减少这种开销尤其是在读锁竞争不激烈或者单个线程连续操作读锁的场景下。非 volatile: 注释中明确指出它是非 volatile 的因为它仅仅作为一个启发式的缓存。即使存在数据竞争benign data race最坏的情况也只是缓存失效需要回退到 ThreadLocal 查找不影响正确性。避免内存泄漏: 和 HoldCounter 内部使用 tid 而不是直接引用 Thread 对象一样cachedHoldCounter 也只持有 HoldCounter而 HoldCounter 内部通过 tid 间接关联线程从而避免了因为缓存导致线程对象无法被垃圾回收的问题。 读锁获取逻辑 tryAcquireShared 的设计目标是快速路径 它尝试以最小的开销处理最常见的情况非重入或简单重入 (当前线程是 firstReader)。一次 CAS 成功。它故意推迟了对复杂重入情况非 firstReader 的重入需要访问 ThreadLocal的处理以避免在常见路径上产生 ThreadLocal.get() 的开销。 protected final long tryAcquireShared(long unused) {Thread current Thread.currentThread();long c getState();// 1. 检查是否有其他线程持有写锁if (exclusiveCount(c) ! 0 getExclusiveOwnerThread() ! current)return -1L;// 2. 尝试获取读锁int r sharedCount(c);if (!readerShouldBlock() r MAX_COUNT compareAndSetState(c, c SHARED_UNIT)) {// 成功获取更新持有计数return 1L;}return fullTryAcquireShared(current); }当 tryAcquireShared 的快速路径失败时例如 CAS 失败或者需要处理复杂的重入逻辑就会调用 fullTryAcquireShared。这个方法包含了更完整的逻辑 循环重试 (CAS Misses): for (;;) 循环允许在 CAS 操作失败后进行重试。这是因为多个读线程可能同时尝试增加读锁计数导致 CAS 竞争。完整的重入处理: 它能正确处理所有线程的读锁重入包括查找和更新 ThreadLocal 中的 HoldCounter。 ReentrantReadWriteLock.java // ...HoldCounter rh null; // rh 会在需要时从 readHolds 或 cachedHoldCounter 获取for (;;) {long c getState();if (exclusiveCount(c) ! 0) { // 检查写锁if (getExclusiveOwnerThread() ! current)return -1; // 其他线程持有写锁失败// else we hold the exclusive lock; blocking here// would cause deadlock. (当前线程持有写锁允许获取读锁 - 锁降级)} else if (readerShouldBlock()) { // 根据策略判断是否应阻塞// Make sure were not acquiring read lock reentrantly// 如果需要阻塞但当前是重入读则不应该阻塞。// 这里的逻辑是确保如果 readerShouldBlock() 为 true// 并且当前不是重入即 rh.count 0则获取失败。if (firstReader current) {// assert firstReaderHoldCount 0;} else {if (rh null) { // 首次进入或 rh 未初始化rh cachedHoldCounter;if (rh null ||rh.tid ! LockSupport.getThreadId(current)) {rh readHolds.get(); // 从 ThreadLocal 获取if (rh.count 0) // 如果 ThreadLocal 中计数为0说明之前没有正确移除或状态异常readHolds.remove();}}if (rh.count 0) // 如果当前线程的读锁计数为0并且 readerShouldBlock() 为 true则获取失败return -1L;}}if (sharedCount(c) MAX_COUNT) // 读锁数量超限throw new Error(Maximum lock count exceeded);if (compareAndSetState(c, c SHARED_UNIT)) { // 尝试CAS增加读锁计数// ... 成功获取后更新 firstReader/firstReaderHoldCount 或 rh.count ...return 1L; // 成功}}处理锁降级: 在循环中如果发现写锁被持有 (exclusiveCount(c) ! 0)它会检查是否是当前线程持有。如果是则允许继续尝试获取读锁这是锁降级的关键。更细致的策略检查: 在循环的每次迭代中都会检查 readerShouldBlock()。 readerShouldBlock 非公平情况下会检查第一个是不是读锁。 公平情况下会检查前面有没有头节点之外的节点这意味着第二个读线程可以通过这个判断然后第三个。。。。直到一个写节点加入。 writerShouldBlock writerShouldBlock() 是 ReentrantReadWriteLock.Sync 类中的一个抽象方法它在两个具体的子类 FairSync 和 NonfairSync 中有不同的实现。这个方法的核心作用是判断当前尝试获取写锁的线程是否应该因为特定的策略公平性策略而被阻塞即使锁当前可能没有被其他线程持有。 来看一下它在 ReentrantReadWriteLock.Sync 类中的 tryAcquire 方法中是如何被使用的 OverrideReservedStackAccessprotected final boolean tryAcquire(long acquires) {// ... (省略了检查是否已有读锁或写锁被其他线程持有的逻辑) ...Thread current Thread.currentThread();long c getState();long w exclusiveCount(c);if (c ! 0) {// ... (处理已有锁的情况包括重入) ...}// 当 c 0 时表示当前没有任何锁既没有读锁也没有写锁// 此时即使锁是可用的也需要根据策略判断是否应该阻塞if (writerShouldBlock() || // --- 在这里被调用!compareAndSetState(c, c acquires))return false; // 如果 writerShouldBlock() 返回 true则获取失败线程需要去排队setExclusiveOwnerThread(current);return true;}当 tryAcquire 方法执行到 c 0 的分支时意味着当前锁是自由的没有线程持有读锁或写锁。在这种情况下 调用 writerShouldBlock(): 这个方法的返回值决定了当前线程是否应该“礼让”其他可能在等待队列中的线程。如果 writerShouldBlock() 返回 true即使锁是可用的tryAcquire 也会返回 false。这意味着当前线程获取写锁的尝试失败了它将被 AQS 框架放入等待队列中。如果 writerShouldBlock() 返回 false则当前线程可以继续尝试通过 compareAndSetState (CAS) 来获取写锁。 compareAndSetState(c, c acquires): 如果 writerShouldBlock() 返回 false则会尝试通过 CAS 操作来原子地更新锁的状态从而获取写锁。如果 CAS 失败例如在非公平模式下另一个线程恰好在此时也尝试获取锁并成功了tryAcquire 同样返回 false。 不同子类中的实现 NonfairSync (非公平同步器): ReentrantReadWriteLock.java static final class NonfairSync extends Sync {// ...final boolean writerShouldBlock() {return false; // writers can always barge}// ... }在非公平模式下writerShouldBlock() 总是返回 false。这意味着尝试获取写锁的线程总是可以“插队”或“闯入”barge它会直接尝试通过 CAS 获取锁而不会检查等待队列中是否有其他线程。 FairSync (公平同步器): static final class FairSync extends Sync {// ...final boolean writerShouldBlock() {return hasQueuedPredecessors();}// ... }在公平模式下writerShouldBlock() 调用 hasQueuedPredecessors()。这个方法继承自 AQS会检查当前线程在同步队列中是否有前驱节点即是否有其他线程比它更早开始等待获取锁。 如果 hasQueuedPredecessors() 返回 true表示队列中有等待时间更长的线程那么当前线程就应该阻塞让等待时间长的线程先获取锁以保证公平性。如果返回 false表示当前线程是队列的头部或者队列为空它可以尝试获取锁。 持有计数优化 使用多级缓存机制优化读锁计数 // 第一个读线程的快速路径 private transient Thread firstReader; private transient int firstReaderHoldCount;// 最近访问线程的缓存 private transient HoldCounter cachedHoldCounter;// 线程本地存储 private transient ThreadLocalHoldCounter readHolds;使用场景 适用于读多写少的并发场景如 缓存系统的读写操作配置信息的访问和更新统计数据的查询和修改 通过读写分离ReentrantReadWriteLock 相比普通的互斥锁能显著提升读并发性能。
http://www.dnsts.com.cn/news/183543.html

相关文章:

  • 长春火车站现在正常通车吗域名备案怎么关闭网站
  • 墙绘网站建设推广wordpress 多语言站点
  • 潍坊市城乡建设局网站多语言外贸网站制作
  • 长安网站设计seo现在还有前景吗
  • 芜湖网站建设推广公司3d自学网站
  • 网站的规划和建设做涂鸦的网站
  • 做教育招生网站wordpress适合建什么网站吗
  • 国家工商网站查询wordpress 返回顶部
  • 做民宿注册的网站目前国内有哪些网站做家具回收
  • 做传销网站违法吗网站建设工具最简洁的
  • 怎样做网站关键字长沙营销网站设计
  • 内蒙古网站seo优化镇江网页设计哪家好
  • 湖南省网站集约化建设实施方案推广关键词排名方法
  • 济南做网站0531sosowordpress搭建淘客
  • 创可贴网站怎么做图片大全点样用外网访问自己做的网站
  • 佛山专业网站建设价格一站式建设
  • 房地产做网站不西安网站建设第一品牌
  • wordpress游记主题seo是干嘛的
  • 营销类型的公司网站如何制作个人公众号
  • 彩票网站开发 合法青岛logo设计价格
  • 建网站金坛哪家强?网站作业
  • 新民正规网站建设价格咨询wordpress文章自动更新方法
  • 建筑规范网站电子商务网站系统详细设计的内容
  • 网站开发3687474企鹅做网站设计挣钱吗
  • 做网站的经费一般建设企业网站的费用
  • 站长素材做网站美工要学什么
  • 如何学建设网站app服务器搭建教程
  • 徐州建设网站公司网页搜索打不开网页
  • 药品在哪些网站做推广四川航霖企业管理咨询有限公司
  • 企业网站推广有哪些方式莱芜做网站的商家有哪些