Android调试工具与Windows驱动配置:Latest-adb-fastboot-installer-for-windows全攻略

核心内容摘要

建议收藏|35岁不是程序员危机!真正危险的是10年CRUD,却没一项不可替代的核心能力
【OpenAPI】OpenAPI 3.0x 文档智能解析与验证实战

Phi-3-mini-4k-instruct轻量体验:Ollama一键部署,实测写作与编程辅助效果

读锁详解读锁的获取看完了写锁再来看看读锁读锁不是独占式锁即同一时刻该锁可以被多个读线程获取也就是一种共享式锁。

按照之前对 AQS 的介绍实现共享式同步组件的同步语义需要通过重写 AQS 的 tryAcquireShared 方法和 tryReleaseShared 方法。

读锁的获取实现方法为protected final int tryAcquireShared(int unused) { /* * Walkthrough: *

If write lock held by another thread, fail. *

Otherwise, this thread is eligible for * lock wrt state, so ask if it should block * because of queue policy. If not, try * to grant by CASing state and updating count. * Note that step does not check for reentrant * acquires, which is postponed to full version * to avoid having to check hold count in * the more typical non-reentrant case. *

If step 2 fails either because thread * apparently not eligible or CAS fails or count * saturated, chain to version with full retry loop. */ Thread current Thread.currentThread(); int c getState(); //

如果写锁已经被获取并且获取写锁的线程不是当前线程的话当前 // 线程获取读锁失败返回-1 if (exclusiveCount(c) ! 0 getExclusiveOwnerThread() ! current) return -1; int r sharedCount(c); if (!readerShouldBlock() r MAX_COUNT //

当前线程获取读锁 compareAndSetState(c, c SHARED_UNIT)) { //

下面的代码主要是新增的一些功能比如getReadHoldCount()方法 //返回当前获取读锁的次数 if (r

{ firstReader current; firstReaderHoldCount 1; } else if (firstReader current) { firstReaderHoldCount; } else { HoldCounter rh cachedHoldCounter; if (rh null || rh.tid ! getThreadId(current)) cachedHoldCounter rh readHolds.get(); else if (rh.count

readHolds.set(rh); rh.count; } return 1; } //

处理在第二步中CAS操作失败的自旋已经实现重入性 return fullTryAcquireShared(current); }代码的逻辑请看注释需要注意的是当写锁被其他线程获取后读锁获取失败否则获取成功会利用 CAS 更新同步状态。

另外当前同步状态需要加上 SHARED_UNIT(1 SHARED_SHIFT)即 0x00010000的原因我们在上面也说过了同步状态的高 16 位用来表示读锁被获取的次数。

如果 CAS 失败或者已经获取读锁的线程再次获取读锁时是靠 fullTryAcquireShared 方法实现的。

读锁的释放读锁释放的实现主要通过方法 tryReleaseShared源码如下主要逻辑请看注释protected final boolean tryReleaseShared(int unused) { Thread current Thread.currentThread(); // 前面还是为了实现getReadHoldCount等新功能 if (firstReader current) { // assert firstReaderHoldCount 0; if (firstReaderHoldCount

firstReader null; else firstReaderHoldCount--; } else { HoldCounter rh cachedHoldCounter; if (rh null || rh.tid ! getThreadId(current)) rh readHolds.get(); int count rh.count; if (count

{ readHolds.remove(); if (count

throw unmatchedUnlockException(); } --rh.count; } for (;;) { int c getState(); // 读锁释放 将同步状态减去读状态即可 int nextc c - SHARED_UNIT; if (compareAndSetState(c, nextc)) // Releasing the read lock has no effect on readers, // but it may allow waiting writers to proceed if // both read and write locks are now free. return nextc 0; } }锁降级读写锁支持锁降级遵循按照获取写锁获取读锁再释放写锁的次序写锁能够降级成为读锁不支持锁升级关于锁降级下面的示例代码摘自 ReentrantWriteReadLock 源码void processCachedData() { rwl.readLock().lock(); if (!cacheValid) { // Must release read lock before acquiring write lock rwl.readLock().unlock(); rwl.writeLock().lock(); try { // Recheck state because another thread might have // acquired write lock and changed state before we did. if (!cacheValid) { data ... cacheValid true; } // Downgrade by acquiring read lock before releasing write lock rwl.readLock().lock(); } finally { rwl.writeLock().unlock(); // Unlock write, still hold read } } try { use(data); } finally { rwl.readLock().unlock(); } }这里的流程可以解释如下获取读锁首先尝试获取读锁来检查某个缓存是否有效。

检查缓存如果缓存无效则需要释放读锁因为在获取写锁之前必须释放读锁。

获取写锁获取写锁以便更新缓存。

此时可能还需要重新检查缓存状态因为在释放读锁和获取写锁之间可能有其他线程修改了状态。

更新缓存如果确认缓存无效更新缓存并将其标记为有效。

写锁降级为读锁在释放写锁之前获取读锁从而实现写锁到读锁的降级。

这样在释放写锁后其他线程可以并发读取但不能写入。

使用数据现在可以安全地使用缓存数据了。

释放读锁完成操作后释放读锁。

这个流程结合了读锁和写锁的优点确保了数据的一致性和可用性同时允许在可能的情况下进行并发读取。

使用读写锁的代码可能看起来比使用简单的互斥锁更复杂但它提供了更精细的并发控制可能会提高多线程应用程序的性能。

使用读写锁ReentrantReadWriteLock 的使用非常简单下面的代码展示了如何使用 ReentrantReadWriteLock 来实现一个线程安全的计数器public class Counter { private final ReentrantReadWriteLock rwl new ReentrantReadWriteLock(); private final Lock r rwl.readLock(); private final Lock w rwl.writeLock(); private int count 0; public int getCount() { r.lock(); try { return count; } finally { r.unlock(); } } public void inc() { w.lock(); try { count; } finally { w.unlock(); } } }当缓存无效时会先释放读锁然后获取写锁来更新缓存。

一旦缓存被更新就会进行写锁到读锁的降级允许其他线程并发读取但仍然排除写入。

这样的结构允许在确保数据一致性的同时实现并发读取的优势从而提高多线程环境下的性能。

9·1动漫免费版-9·1动漫免费版应用

百度百家号客服电话人工服务

123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123