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

湖北建设工程造价协会网站简单建站

湖北建设工程造价协会网站,简单建站,用那个程序做网站收录好,iis 5 新建网站目录 1、ReentrantReadWriteLock 入门1.1、概念1.2、案例1.2.1、写写互斥1.2.2 锁降级 2、ReentrantReadWriteLock 源码解析2.1、属性2.2、构造方法2.3、内部类2.4、读写状态的设计 —— 按位切割使用2.5、【写锁】加锁方法 lock() —— ReentrantReadWriteLock.WriteLock2.4.1… 目录 1、ReentrantReadWriteLock 入门1.1、概念1.2、案例1.2.1、写写互斥1.2.2 锁降级 2、ReentrantReadWriteLock 源码解析2.1、属性2.2、构造方法2.3、内部类2.4、读写状态的设计 —— 按位切割使用2.5、【写锁】加锁方法 lock() —— ReentrantReadWriteLock.WriteLock2.4.1、acquire() 方法 —— AQS2.4.1.1、tryAcquire() 方法 —— AQS由 ReentrantReadWriteLock.Sync 实现2.4.1.1.1 writerShouldBlock() 方法 —— ReentrantReadWriteLock.Sync由子类实现 2.6、【写锁】解锁方法 unlock() —— ReentrantReadWriteLock.WriteLock2.6.1、release() 方法 —— AQS2.6.1.1、tryRelease() 方法 —— AQS由 ReentrantReadWriteLock.Sync 实现 2.7、【读锁】加锁方法 lock() —— ReentrantReadWriteLock.ReadLock2.7.1、acquireShared() 方法 —— AQS2.7.1.1、tryAcquireShared() 方法 —— AQS由 ReentrantReadWriteLock.Sync 实现2.7.1.1.1、readerShouldBlock() 方法 —— ReentrantReadWriteLock.Sync由子类实现2.7.1.1.1.1、apparentlyFirstQueuedIsExclusive() 方法 —— AQS 2.7.1.1.2、fullTryAcquireShared() 方法 —— ReentrantReadWriteLock.Sync 2.8、【读锁】解锁方法 unlock() —— ReentrantReadWriteLock.ReadLock 1、ReentrantReadWriteLock 入门 1.1、概念 ReentrantReadWriteLock读写锁。它表示两个锁一个是读操作相关的锁称为共享锁一个是写相关的锁称为排他锁。适用于读多写少的场景如果用独占锁效率及其低下提高并发性能但也需要更多的内存和处理器时间来维护状态信息 在没有写操作的情况下多个线程同时读一个资源没有任何问题所以应该允许多个线程同时读取共享资源但是如果一个线程想去写这些共享资源就不应该允许其他线程对该资源进行读和写的操作了 并发读读互斥读写、写读、写写 ReentrantLock 与 ReentrantReadWriteLock 区别 ReentrantLock互斥锁它允许同一线程对共享资源进行重入即该线程在获得锁后可以再次获得该锁而不被阻塞ReentrantReadWriteLock由一个读锁和一个写锁组成它允许多个线程同时读取共享资源但只允许一个线程写入共享资源 当前线程获取读锁的条件 没有其它线程的写锁没有写请求或者有写请求但当前线程和持有锁的线程是同一个线程 当前线程获取写锁的条件 没有其它线程的读锁没有其它线程的写锁 三个重要的特性 公平选择性支持非公平默认和公平的锁获取方式吞吐量还是非公平优于公平可重入读锁和写锁都支持线程重入。读线程获取读锁后能够再次获取读锁但是不能获取写锁写线程在获取写锁之后能够再次获取写锁同时也可以获取读锁锁降级线程获取写锁之后获取读锁再释放写锁这样实现了写锁变为读锁也叫锁降级 1.2、案例 1.2.1、写写互斥 public class Test {private static MapString, Object map new HashMap();private static ReentrantReadWriteLock lock new ReentrantReadWriteLock();public static void put(String key, Object value) throws InterruptedException {System.out.println(开始---- Thread.currentThread().getName());lock.writeLock().lock();try {System.out.println(执行------ Thread.currentThread().getName());map.put(key, value);Thread.sleep(1000);} finally {lock.writeLock().unlock();System.out.println(结束------ Thread.currentThread().getName());}}public static Object get(String key) {System.out.println(开始---- Thread.currentThread().getName());lock.readLock().lock();try {System.out.println(执行------ Thread.currentThread().getName());return map.get(key);} finally {lock.readLock().unlock();System.out.println(执行------ Thread.currentThread().getName());}}public static void main(String[] args) throws InterruptedException {Runnable writeTask () - {try {put(1, 1);} catch (InterruptedException e) {throw new RuntimeException(e);}};new Thread(writeTask).start();new Thread(writeTask).start();} }执行结果 开始----Thread-1 开始----Thread-0 执行------Thread-1 结束------Thread-1 执行------Thread-0 结束------Thread-0根据结果可以线程 1、0 同时执行但线程 1 获取写锁后线程 0 阻塞直至线程 1 执行完释放写锁之后线程 0 获取写锁执行最后释放写锁 当然读者也可以去测试 读写、读读 等。 1.2.2 锁降级 锁降级 先获取写锁然后再获取读锁最后释放写锁的过程。在这个过程中线程可以先访问共享资源然后放弃写权限转而访问读资源【可以避免写操作期间读操作的阻塞提高并发性能由写锁降为读锁释放写锁后仍然持有读锁】。 还是上述那个例子 public static void put(String key, Object value) {lock.writeLock().lock();try {map.put(key, value);// 获取读锁lock.readLock().lock();} finally {lock.writeLock().unlock();// 此处如果不释放读锁其他线程获取写锁时将被阻塞//lock.readLock().unlock();} }2、ReentrantReadWriteLock 源码解析 2.1、属性 public class ReentrantReadWriteLock implements ReadWriteLock {// 读锁private final ReentrantReadWriteLock.ReadLock readerLock;// 写锁private final ReentrantReadWriteLock.WriteLock writerLock;// 同步机制final Sync sync; }2.2、构造方法 public ReentrantReadWriteLock() {this(false); }public ReentrantReadWriteLock(boolean fair) {sync fair ? new FairSync() : new NonfairSync();readerLock new ReadLock(this);writerLock new WriteLock(this); }默认非公平机制 2.3、内部类 // AQS分公平、非公平 abstract static class Sync extends AbstractQueuedSynchronizer {// 尝试获取锁protected final boolean tryAcquire(int acquires) {}// 尝试释放锁protected final boolean tryRelease(int releases) {}protected final int tryAcquireShared(int unused) {}// 写锁是否应该阻塞abstract boolean writerShouldBlock();abstract boolean readerShouldBlock();// 每个读线程持有的计数Sync 构造函数中初始化读线程计数为 0 时删除private transient ThreadLocalHoldCounter readHolds;// 缓存最后一个读锁的计数private transient HoldCounter cachedHoldCounter;// 记录第一个读锁private transient Thread firstReader null;// 第一个读锁的计数器private transient int firstReaderHoldCount;// 内部类继承了 ThreadLocal和当前线程绑定static final class ThreadLocalHoldCounter extends ThreadLocalHoldCounter {public HoldCounter initialValue() {return new HoldCounter();}}// 内部类读线程的计数器static final class HoldCounter {int count 0;final long tid getThreadId(Thread.currentThread());} }// 非公平 static final class NonfairSync extends Sync {final boolean writerShouldBlock() {return false;} }// 公平 static final class FairSync extends Sync {final boolean writerShouldBlock() {return hasQueuedPredecessors();} }// 读锁 public static class ReadLock implements Lock { }// 写锁 public static class WriteLock implements Lock {private final Sync sync;// 加锁通过 Sync#acquire() 方法加锁public void lock() {} }2.4、读写状态的设计 —— 按位切割使用 在分析 ReentrantLock 的时候Sync 内部类类是继承于 AQS以 int state 为线程加锁状态state 0 表示未加锁state 0 表示已加锁 同样ReentrantReadWriteLock 也是继承于 AQS 来实现同步那 int state 是如何同时来区分读锁和写锁的呢 如果要用一个变量维护多种状态需要采用 “按位切割使用” 的方式来维护这个变量将其切分为两部分高 16 为表示读低 16 为表示写 查看 Sync 类中的静态变量 abstract static class Sync extends AbstractQueuedSynchronizer {// 高16位为读锁低16位为写锁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;// 获取读锁的数量【高 16 位移位】static int sharedCount(int c) { return c SHARED_SHIFT; }// 获取写锁的数量【 与运算】static int exclusiveCount(int c) { return c EXCLUSIVE_MASK; }}移位操作符在二进制下进行移位【十进制转化为二进制】 左移。如果左移过程中超过了 32 位高位就会舍弃低位补零【最终结果十进制数 * (2 ^ n)】。如3 2 3 * (2 ^ 2) 12右移。低位会舍弃高位补零【最终结果十进制数 / (2 ^ n)】右移零填充运算符【用来执行无符号位移的位运算符】将一个数的二进制表示向右移动并用 0 填充左侧的空位 所以通过移位操作符 state【高 16读低 16写】00000000 00000000 00000000 00000000SHARED_UNIT                         00000000 00000001 00000000 00000000MAX_COUNT                            00000000 00000000 11111111  11111111EXCLUSIVE_MASK                  00000000 00000000 11111111 11111111 2.5、【写锁】加锁方法 lock() —— ReentrantReadWriteLock.WriteLock public void lock() {sync.acquire(1); }调用 AQS#acquire() 方法【Sync 没有重写此方法父类有】 2.4.1、acquire() 方法 —— AQS public final void acquire(int arg) {if (!tryAcquire(arg) acquireQueued(addWaiter(Node.EXCLUSIVE), arg)) {selfInterrupt();} }acquire() 方法在之前的文章 六ReentrantLock —— 可重入锁 中已经分析过只有 tryAcquire() 方法供子类实现。这里实现的子类是 ReentrantReadWriteLock.Sync 2.4.1.1、tryAcquire() 方法 —— AQS由 ReentrantReadWriteLock.Sync 实现 // 尝试获取写锁 protected final boolean tryAcquire(int acquires) { Thread current Thread.currentThread();// 获取 state 的值int c getState();// 获取写锁的数量int w exclusiveCount(c);if (c ! 0) {// 要么就是读锁要么就是写锁// 1.如果没有写锁【有读锁】不管是否当前线程是持有锁线程直接返回【持有读锁线程无法再持有写锁读写互斥】// 2.如果是写锁但是不是当前持有锁线程直接返回【写写互斥】if (w 0 || current ! getExclusiveOwnerThread()) {return false;}// 是写锁且是当前线程if (w exclusiveCount(acquires) MAX_COUNT) {throw new Error(Maximum lock count exceeded);}// 重入setState(c acquires);return true;}// 没有读锁、写锁竞争写锁if (writerShouldBlock() || !compareAndSetState(c, c acquires)) {return false;}setExclusiveOwnerThread(current);return true; }2.4.1.1.1 writerShouldBlock() 方法 —— ReentrantReadWriteLock.Sync由子类实现 分公平锁、非公平锁 公平锁由 AQS#hasQueuedPredecessors() 方法决定【同步等待队列中有线程等待返回 true则不竞争锁直接返回 false否则竞争写锁进行 CAS 操作返回 true】非公平锁直接抢占进行 CAS 操作返回 true 2.6、【写锁】解锁方法 unlock() —— ReentrantReadWriteLock.WriteLock public void unlock() {sync.release(1); }调用 AQS#release() 方法【Sync 没有重写此方法父类有】 2.6.1、release() 方法 —— AQS public final boolean release(int arg) {if (tryRelease(arg)) {Node h head;if (h ! null h.waitStatus ! 0)unparkSuccessor(h);return true;}return false; }tryRelease() 方法被 Sync 类实现 2.6.1.1、tryRelease() 方法 —— AQS由 ReentrantReadWriteLock.Sync 实现 protected final boolean tryRelease(int releases) {if (!isHeldExclusively()) {// 如果当前线程不是持有锁线程则抛异常throw new IllegalMonitorStateException();} int nextc getState() - releases;// boolean free (exclusiveCount(nextc) 0);// 判断写锁数量是否为 0【重入】boolean free exclusiveCount(nextc) 0;if (free) {setExclusiveOwnerThread(null);}setState(nextc);return free; }2.7、【读锁】加锁方法 lock() —— ReentrantReadWriteLock.ReadLock public void lock() {sync.acquireShared(1); }调用 AQS#acquireShared() 方法 2.7.1、acquireShared() 方法 —— AQS public final void acquireShared(int arg) {if (tryAcquireShared(arg) 0) {doAcquireShared(arg);} }2.7.1.1、tryAcquireShared() 方法 —— AQS由 ReentrantReadWriteLock.Sync 实现 protected final int tryAcquireShared(int unused) {Thread current Thread.currentThread();int c getState();if (exclusiveCount(c) ! 0 getExclusiveOwnerThread() ! current) {// 如果有写锁且当前线程不是持有写锁线程则返回 -1【写读互斥】return -1;}int r sharedCount(c);// 如果获取到读锁则返回 1// 1.readerShouldBlock() 方法// 公平锁有线程排队返回 true直接跳过否则返回 false// 非公平锁为防止写线程饥饿问题所以判断 head 节点的后驱节点是否为写锁如果是返回 true直接跳过否则返回 false// 2.compareAndSetState(c, c SHARED_UNIT)CAS 操作 state 的高 16 位读锁if (!readerShouldBlock() r MAX_COUNT compareAndSetState(c, c SHARED_UNIT)) {if (r 0) {// 如果之前没有读锁则这是第一个线程获取读锁计数器记为 1且用 firstReader 执向firstReader current;firstReaderHoldCount 1;} else if (firstReader current) {// 如果之前有读锁且当前线程等于 firstReader第一个获取读锁的线程则自加firstReaderHoldCount;} else {// 缓存最后一个读线程的计数HoldCounter rh cachedHoldCounter;// 我是第 2 个拿到读锁的rh null| 我是第 NN 2个拿到读锁的且当前线程不是最后一个线程那么将 cachedHoldCounter 设置为最后一个线程if (rh null || rh.tid ! getThreadId(current)) {cachedHoldCounter rh readHolds.get();} else if (rh.count 0) {// 我是第 NN 2个拿到读锁的当前线程是最后一个线程且计数器为 0 【读锁释放】readHolds.set(rh);}// 计数器自增rh.count;}return 1;}// 用于 CAS 操作失败【N N 2个线程同时执行 CAS 操作】return fullTryAcquireShared(current); }如果写锁被其它线程持有则获取读锁失败返回 -1判断是否因同步队列策略而阻塞【公平锁有线程排队跳过逻辑否则执行逻辑非公平锁为防止写线程饥饿问题所以判断 head 节点的后驱节点是否为写锁如果是跳过逻辑否则执行逻辑】。如果不阻塞就执行 CAS 操作更新 state如果步骤 2 失败因为线程显然不符合条件【CAS 失败或计数饱和】则使用完整的重试循环链接到版本 2.7.1.1.1、readerShouldBlock() 方法 —— ReentrantReadWriteLock.Sync由子类实现 公平锁由 hasQueuedPredecessors() 方法决定【同步等待队列中有线程等待返回 true则不竞争锁直接返回 false否则竞争写锁进行 CAS 操作返回 true】 final boolean readerShouldBlock() {return hasQueuedPredecessors(); }非公平锁由 apparentlyFirstQueuedIsExclusive() 方法决定【如果同步等待队列中不为空且 head 节点的后继节点为【独占式】节点则返回 true否则返回 false如果有读锁写锁是无法获取的防止写线程饥饿一直阻塞读锁是共享的可以一直获取】 final boolean readerShouldBlock() {return apparentlyFirstQueuedIsExclusive(); }2.7.1.1.1.1、apparentlyFirstQueuedIsExclusive() 方法 —— AQS final boolean apparentlyFirstQueuedIsExclusive() {Node h, s;return (h head) ! null (s h.next) ! null !s.isShared() s.thread ! null; }如果同步等待队列中不为空且 head 节点的后继节点为【独占式】节点则返回 true否则返回 false 2.7.1.1.2、fullTryAcquireShared() 方法 —— ReentrantReadWriteLock.Sync final int fullTryAcquireShared(Thread current) {HoldCounter rh null;// 自旋for (;;) {int c getState();// 是否存在写锁if (exclusiveCount(c) ! 0) {if (getExclusiveOwnerThread() ! current) {// 如果存在写锁且当前线程不是持有写锁的线程返回 -1如果是就会去持有读锁return -1;}// 公平有排队的进入逻辑没排队的过// 非公平head 的 next 是写不是进入逻辑如果不是过} else if (readerShouldBlock()) {if (firstReader current) {// assert firstReaderHoldCount 0;} else {// 需要阻塞去掉最后一个计数为 0 的if (rh null) {rh cachedHoldCounter;if (rh null || rh.tid ! getThreadId(current)) {rh readHolds.get();if (rh.count 0) {readHolds.remove();}}}if (rh.count 0) {return -1;}}}if (sharedCount(c) MAX_COUNT) {throw new Error(Maximum lock count exceeded);}// 尝试获取读锁if (compareAndSetState(c, c SHARED_UNIT)) {if (sharedCount(c) 0) {// 第一次获取读锁firstReader current;firstReaderHoldCount 1;} else if (firstReader current) {firstReaderHoldCount;} else {if (rh null) {rh cachedHoldCounter;}if (rh null || rh.tid ! getThreadId(current)) {rh readHolds.get(); } else if (rh.count 0)readHolds.set(rh);rh.count;cachedHoldCounter rh;}return 1;}} }2.8、【读锁】解锁方法 unlock() —— ReentrantReadWriteLock.ReadLock protected final boolean tryReleaseShared(int unused) {Thread current Thread.currentThread();if (firstReader current) {if (firstReaderHoldCount 1)firstReader null;elsefirstReaderHoldCount--;} else {HoldCounter rh cachedHoldCounter;if (rh null || rh.tid ! getThreadId(current))rh readHolds.get();int count rh.count;if (count 1) {readHolds.remove();if (count 0)throw unmatchedUnlockException();}--rh.count;}for (;;) {int c getState();int nextc c - SHARED_UNIT;if (compareAndSetState(c, nextc))return nextc 0;} }判断当前线程是否是第一个获取读锁的线程。如果是它将检查读锁的持有次数如果持有次数为1则将第一个读者置为null否则将持有次数减1如果当前线程不是第一个获取读锁的线程则会尝试从缓存中获取HoldCounter对象该对象记录了线程持有的读锁次数。如果缓存中的HoldCounter对象与当前线程不匹配则从readHolds中获取与当前线程对应的HoldCounter对象。接着它将该对象的持有次数减1并在线程持有次数不大于1时从readHolds中移除该对象。如果持有次数小于等于0会抛出一个异常最后该函数进入一个循环不断尝试将锁的状态减去SHARED_UNIT表示读锁的单位并使用compareAndSetState方法原子地更新锁的状态。如果更新成功它会检查更新后的状态是否为0如果是则返回true表示成功释放了读锁
http://www.pierceye.com/news/126685/

相关文章:

  • 南通网站建设团队wordpress广告产检
  • 做网站刷赞qq怎么赚钱邢台路桥建设总公司没有网站吗
  • 网站仿站教程常用外贸网站
  • 南昌市有帮做网站的吗纵横天下网站开发
  • pc网站直接转换成移动端的网站黑果云免费虚拟主机
  • 网站建设用什么科目wordpress当前分类链接地址
  • 做一万个网站网站做下载功能
  • 佛山建站模板制作wordpress加上live2d
  • 樟木头网站仿做深圳网站开发公司
  • 孙俪做的网站广告微信如何修改wordpress
  • 有什么手机做网站的免费ppt模板下载花
  • 网站建设团队技术介绍县级网站
  • 深圳营销型网站建设价格网站建设文化如何
  • 提交网站的入口地址网站建设灬金手指下拉十五
  • 连云港建设局网站学校网站建设管理相关规定
  • 什么网站做玩具的外贸网站监控系统
  • 从事网站美工建设厦门网站制作企业
  • 网站后台传图片南昌做网站要多少钱
  • 网站包括什么国内最大的域名交易平台
  • 做营销型网站 公司哈尔滨展览设计公司
  • 网站设计费用多少钱产品网页设计教程
  • 深圳公司网站建设设计网站推广的意义和方法
  • 网站需要哪些费用免费营销型网站模版
  • 如何做购物网站的教程wordpress酷炫插件
  • 建设信用卡网站登录网站建设和微信小程序
  • 邓州企业网站艺术设计方案
  • 广州市住房住建局网站永久免费的云电脑
  • 建设网站后如何上线不用服务器做网站
  • 建站服务论坛国外做外贸哪个网站好些
  • 营销型网站试运营调忧仿别人网站