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

自己做网站需要哪些软件做网站那个好

自己做网站需要哪些软件,做网站那个好,江苏工信部网站备案,合肥市中小企业局网站文章目录 4、深入ReentrantReadWriteLock4.1 为什么要出现读写锁4.2 读写锁的实现原理4.3 写锁分析4.3.1 写锁加锁流程概述4.3.2 写锁加锁源码分析4.3.3 写锁释放锁流程概述释放锁源码 4.4 读锁分析4.4.1 读锁加锁流程概述4.4.1.1 基础读锁流程4.4.1.2 读锁重入流程4.4.1.… 文章目录 4、深入ReentrantReadWriteLock4.1 为什么要出现读写锁4.2 读写锁的实现原理4.3 写锁分析4.3.1 写锁加锁流程概述4.3.2 写锁加锁源码分析4.3.3 写锁释放锁流程概述释放锁源码 4.4 读锁分析4.4.1 读锁加锁流程概述4.4.1.1 基础读锁流程4.4.1.2 读锁重入流程4.4.1.3 读锁加锁的后续逻辑fullTryAcquireShared4.4.1.4 读线程在AQS队列获取锁资源的后续操作 4.4.2 读锁的释放锁流程 个人主页道友老李 欢迎加入社区道友老李的学习社区 4、深入ReentrantReadWriteLock 4.1 为什么要出现读写锁 synchronized和ReentrantLock都是互斥锁。 如果说有一个操作是读多写少的还要保证线程安全的话。如果采用上述的两种互斥锁效率方面很定是很低的。 在这种情况下咱们就可以使用ReentrantReadWriteLock读写锁去实现。 读读之间是不互斥的可以读和读操作并发执行。 但是如果涉及到了写操作那么还得是互斥的操作。 static ReentrantReadWriteLock lock new ReentrantReadWriteLock();static ReentrantReadWriteLock.WriteLock writeLock lock.writeLock();static ReentrantReadWriteLock.ReadLock readLock lock.readLock();public static void main(String[] args) throws InterruptedException {new Thread(() - {readLock.lock();try {System.out.println(子线程);try {Thread.sleep(500000);} catch (InterruptedException e) {e.printStackTrace();}} finally {readLock.unlock();}}).start();Thread.sleep(1000);writeLock.lock();try {System.out.println(主线程);} finally {writeLock.unlock();} }4.2 读写锁的实现原理 ReentrantReadWriteLock还是基于AQS实现的还是对state进行操作拿到锁资源就去干活如果没有拿到依然去AQS队列中排队。 读锁操作基于state的高16位进行操作。 写锁操作基于state的低16为进行操作。 ReentrantReadWriteLock依然是可重入锁。 写锁重入读写锁中的写锁的重入方式基本和ReentrantLock一致没有什么区别依然是对state进行1操作即可只要确认持有锁资源的线程是当前写锁线程即可。只不过之前ReentrantLock的重入次数是state的正数取值范围但是读写锁中写锁范围就变小了。 读锁重入因为读锁是共享锁。读锁在获取锁资源操作时是要对state的高16位进行 1操作。因为读锁是共享锁所以同一时间会有多个读线程持有读锁资源。这样一来多个读操作在持有读锁时无法确认每个线程读锁重入的次数。为了去记录读锁重入的次数每个读操作的线程都会有一个ThreadLocal记录锁重入的次数。 写锁的饥饿问题读锁是共享锁当有线程持有读锁资源时再来一个线程想要获取读锁直接对state修改即可。在读锁资源先被占用后来了一个写锁资源此时大量的需要获取读锁的线程来请求锁资源如果可以绕过写锁直接拿资源会造成写锁长时间无法获取到写锁资源。 读锁在拿到锁资源后如果再有读线程需要获取读锁资源需要去AQS队列排队。如果队列的前面需要写锁资源的线程那么后续读线程是无法拿到锁资源的。持有读锁的线程只会让写锁线程之前的读线程拿到锁资源 4.3 写锁分析 4.3.1 写锁加锁流程概述 4.3.2 写锁加锁源码分析 写锁加锁流程 // 写锁加锁的入口 public void lock() {sync.acquire(1); }// 阿巴阿巴 public final void acquire(int arg) {if (!tryAcquire(arg) acquireQueued(addWaiter(Node.EXCLUSIVE), arg))selfInterrupt(); }// 读写锁的写锁实现tryAcquire protected final boolean tryAcquire(int acquires) {// 拿到当前线程Thread current Thread.currentThread();// 拿到state的值int c getState();// 得到state低16位的值int w exclusiveCount(c);// 判断是否有线程持有着锁资源if (c ! 0) {// 当前没有线程持有写锁读写互斥告辞。// 有线程持有写锁持有写锁的线程不是当前线程不是锁重入告辞。if (w 0 || current ! getExclusiveOwnerThread())return false;// 当前线程持有写锁。 锁重入。if (w exclusiveCount(acquires) MAX_COUNT)throw new Error(Maximum lock count exceeded);// 没有超过锁重入的次数正常 1setState(c acquires);return true;}// 尝试获取锁资源if (writerShouldBlock() ||// CAS拿锁!compareAndSetState(c, c acquires))return false;// 拿锁成功设置占有互斥锁的线程setExclusiveOwnerThread(current);// 返回truereturn true; }// // 这个方法是将state的低16位的值拿到 int w exclusiveCount(c); state ((1 16) - 1) 00000000 00000000 00000000 00000001 1 00000000 00000001 00000000 00000000 1 16 00000000 00000000 11111111 11111111 (1 16) - 1 运算一个为0必然为0都为1才为1 // // writerShouldBlock方法查看公平锁和非公平锁的效果 // 非公平锁直接返回false执行CAS尝试获取锁资源 // 公平锁需要查看是否有排队的如果有排队的我是否是head的next4.3.3 写锁释放锁流程概述释放锁源码 释放的流程和ReentrantLock一致只是在判断释放是否干净时判断低16位的值 // 写锁释放锁的tryRelease方法 protected final boolean tryRelease(int releases) {// 判断当前持有写锁的线程是否是当前线程if (!isHeldExclusively())throw new IllegalMonitorStateException();// 获取state - 1int nextc getState() - releases;// 判断低16位结果是否为0如果为0free设置为trueboolean free exclusiveCount(nextc) 0;if (free)// 将持有锁的线程设置为nullsetExclusiveOwnerThread(null);// 设置给statesetState(nextc);// 释放干净返回true。 写锁有冲入这里需要返回false不去释放排队的Nodereturn free; }4.4 读锁分析 4.4.1 读锁加锁流程概述 分析读锁加速的基本流程分析读锁的可重入锁实现以及优化解决ThreadLocal内存泄漏问题读锁获取锁自后如果唤醒AQS中排队的读线程 4.4.1.1 基础读锁流程 针对上述简单逻辑的源码分析 // 读锁加锁的方法入口 public final void acquireShared(int arg) {// 竞争锁资源滴干活if (tryAcquireShared(arg) 0)// 没拿到锁资源去排队doAcquireShared(arg); }// 读锁竞争锁资源的操作 protected final int tryAcquireShared(int unused) {// 拿到当前线程Thread current Thread.currentThread();// 拿到stateint c getState();// 拿到state的低16位判断 ! 0有写锁占用着锁资源// 并且当前占用锁资源的线程不是当前线程if (exclusiveCount(c) ! 0 getExclusiveOwnerThread() ! current)// 写锁被其他线程占用无法获取读锁直接返回 -1去排队return -1;// 没有线程持有写锁、当前线程持有写锁// 获取读锁的信息state的高16位。int r sharedCount(c);// 公平锁就查看队列是由有排队的有排队的直接告辞进不去if后面也不用判断没人排队继续走// 非公平锁没有排队的直接抢。 有排队的但是读锁其实不需要排队如果出现这个情况大部分是写锁资源刚刚释放// 后续Node还没有来记得拿到读锁资源当前竞争的读线程可以直接获取if (!readerShouldBlock() // 判断持有读锁的临界值是否达到r MAX_COUNT // CAS修改state对高16位进行 1compareAndSetState(c, c SHARED_UNIT)) {// 省略部分代码return 1;}return fullTryAcquireShared(current); } // 非公平锁的判断 final boolean apparentlyFirstQueuedIsExclusive() {Node h, s;return (h head) ! null // head为null可以直接抢占锁资源(s h.next) ! null // head的next为null可以直接抢占锁资源!s.isShared() // 如果排在head后面的Node是共享锁可以直接抢占锁资源。s.thread ! null; // 后面排队的thread为null可以直接抢占锁资源 }4.4.1.2 读锁重入流程 重入操作 前面阐述过读锁为了记录锁重入的次数需要让每个读线程用ThreadLocal存储重入次数 ReentrantReadWriteLock对读锁重入做了一些优化操作 记录重入次数的核心 ReentrantReadWriteLock在内部对ThreadLocal做了封装基于HoldCount的对象存储重入次数在内部有个count属性记录而且每个线程都是自己的ThreadLocalHoldCounter所以可以直接对内部的count进行操作。 第一个获取读锁资源的重入次数记录方式 第一个拿到读锁资源的线程不需要通过ThreadLocal存储内部提供了两个属性来记录第一个拿到读锁资源线程的信息 内部提供了firstReader记录第一个拿到读锁资源的线程firstReaderHoldCount记录firstReader的锁重入次数 最后一个获取读锁资源的重入次数记录方式 最后一个拿到读锁资源的线程也会缓存他的重入次数这样起来更方便 基于cachedHoldCounter缓存最后一个拿到锁资源现成的重入次数 最后一个获取读锁资源的重入次数记录方式 重入次数的流程执行方式 1、判断当前线程是否是第一个拿到读锁资源的如果是直接将firstReader以及firstReaderHoldCount设置为当前线程的信息 2、判断当前线程是否是firstReader如果是直接对firstReaderHoldCount即可。 3、跟firstReader没关系了先获取cachedHoldCounter判断是否是当前线程。 3.1、如果不是获取当前线程的重入次数将cachedHoldCounter设置为当前线程。 3.2、如果是判断当前重入次数是否为0重新设置当前线程的锁从入信息到readHoldsThreadLocal中算是初始化操作重入次数是0 3.3、前面两者最后都做count 上述逻辑源码分析 protected final int tryAcquireShared(int unused) {Thread current Thread.currentThread();int c getState();if (exclusiveCount(c) ! 0 getExclusiveOwnerThread() ! current)return -1;int r sharedCount(c);if (!readerShouldBlock() r MAX_COUNT compareAndSetState(c, c SHARED_UNIT)) {// // 判断r 0当前是第一个拿到读锁资源的线程if (r 0) {// 将firstReader设置为当前线程firstReader current;// 将count设置为1firstReaderHoldCount 1;} // 判断当前线程是否是第一个获取读锁资源的线程else if (firstReader current) {// 直接。firstReaderHoldCount;} // 到这就说明不是第一个获取读锁资源的线程else {// 那获取最后一个拿到读锁资源的线程HoldCounter rh cachedHoldCounter;// 判断当前线程是否是最后一个拿到读锁资源的线程if (rh null || rh.tid ! getThreadId(current))// 如果不是设置当前线程为cachedHoldCountercachedHoldCounter rh readHolds.get();// 当前线程是之前的cacheHoldCounterelse if (rh.count 0)// 将当前的重入信息设置到ThreadLocal中readHolds.set(rh);// 重入的rh.count;}// return 1;}return fullTryAcquireShared(current); }4.4.1.3 读锁加锁的后续逻辑fullTryAcquireShared // tryAcquireShard方法中如果没有拿到锁资源走这个方法尝试再次获取逻辑跟上面基本一致。 final int fullTryAcquireShared(Thread current) {// 声明当前线程的锁重入次数HoldCounter rh null;// 死循环for (;;) {// 再次拿到stateint c getState();// 当前如果有写锁在占用锁资源并且不是当前线程返回-1走排队策略if (exclusiveCount(c) ! 0) {if (getExclusiveOwnerThread() ! current)return -1;} // 查看当前是否可以尝试竞争锁资源公平锁和非公平锁的逻辑else if (readerShouldBlock()) {// 无论公平还是非公平只要进来就代表要放到AQS队列中了先做一波准备// 在处理ThreadLocal的内存泄漏问题if (firstReader current) {// 如果当前当前线程是之前的firstReader什么都不用做} else {// 第一次进来是null。if (rh null) {// 拿到最后一个获取读锁的线程rh cachedHoldCounter;// 当前线程并不是cachedHoldCounter没到拿到if (rh null || rh.tid ! getThreadId(current)) {// 从自己的ThreadLocal中拿到重入计数器rh readHolds.get();// 如果计数器为0说明之前没拿到过读锁资源if (rh.count 0)// remove避免内存泄漏readHolds.remove();}}// 前面处理完之后直接返回-1if (rh.count 0)return -1;}}// 判断重入次数是否超出阈值if (sharedCount(c) MAX_COUNT)throw new Error(Maximum lock count exceeded);// CAS尝试获取锁资源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; // cache for release}return 1;}} }4.4.1.4 读线程在AQS队列获取锁资源的后续操作 1、正常如果都是读线程来获取读锁资源不需要使用到AQS队列的直接CAS操作即可 2、如果写线程持有着写锁这是读线程就需要进入到AQS队列排队可能会有多个读线程在AQS中。 当写锁释放资源后会唤醒head后面的读线程当head后面的读线程拿到锁资源后还需要查看next节点是否也是读线程在阻塞如果是直接唤醒 源码分析 // 读锁需要排队的操作 private void doAcquireShared(int arg) {// 声明Node类型是共享锁并且扔到AQS中排队final Node node addWaiter(Node.SHARED);boolean failed true;try {boolean interrupted false;for (;;) {// 拿到上一个节点final Node p node.predecessor();// 如果prev节点是head直接可以执行tryAcquireSharedif (p head) {int r tryAcquireShared(arg);if (r 0) {// 拿到读锁资源后需要做的后续处理setHeadAndPropagate(node, r);p.next null; // help GCif (interrupted)selfInterrupt();failed false;return;}}// 找到prev有效节点将状态设置为-1挂起当前线程if (shouldParkAfterFailedAcquire(p, node) parkAndCheckInterrupt())interrupted true;}} finally {if (failed)cancelAcquire(node);} }private void setHeadAndPropagate(Node node, int propagate) {// 拿到head节点Node h head; // 将当前节点设置为head节点setHead(node);// 第一个判断更多的是在信号量有处理JDK1.5 BUG的操作。if (propagate 0 || h null || h.waitStatus 0 || (h head) null || h.waitStatus 0) {// 拿到当前Node的next节点Node s node.next;// 如果next节点是共享锁直接唤醒next节点if (s null || s.isShared())doReleaseShared();} }4.4.2 读锁的释放锁流程 1、处理重入以及state的值 2、唤醒后续排队的Node 源码分析 // 读锁释放锁流程 public final boolean releaseShared(int arg) {// tryReleaseShared处理state的值以及可重入的内容if (tryReleaseShared(arg)) {// AQS队列的事doReleaseShared();return true;}return false; }// 1、 处理重入问题 2、 处理state protected final boolean tryReleaseShared(int unused) {// 拿到当前线程Thread current Thread.currentThread();// 如果是firstReader直接干活不需要ThreadLocalif (firstReader current) {// assert firstReaderHoldCount 0;if (firstReaderHoldCount 1)firstReader null;elsefirstReaderHoldCount--;} // 不是firstReader从cachedHoldCounter以及ThreadLocal处理else {// 如果是cachedHoldCounter正常--HoldCounter rh cachedHoldCounter;// 如果不是cachedHoldCounter从自己的ThreadLocal中拿if (rh null || rh.tid ! getThreadId(current))rh readHolds.get();int count rh.count;// 如果为1或者更小当前线程就释放干净了直接remove避免value内存泄漏if (count 1) {readHolds.remove();// 如果已经是0没必要再unlock扔个异常if (count 0)throw unmatchedUnlockException();}// -- 走你。--rh.count;}for (;;) {// 拿到state高16位-1成功后返回state是否为0int c getState();int nextc c - SHARED_UNIT;if (compareAndSetState(c, nextc))return nextc 0;} }// 唤醒AQS中排队的线程 private void doReleaseShared() {// 死循环for (;;) {// 拿到头Node h head;// 说明有排队的if (h ! null h ! tail) {// 拿到head的状态int ws h.waitStatus;// 判断是否为 -1 if (ws Node.SIGNAL) {// 到这说明后面有挂起的线程先基于CAS将head的状态从-1改为0if (!compareAndSetWaitStatus(h, Node.SIGNAL, 0))continue; // 唤醒后续节点unparkSuccessor(h);}// 这里不是给读写锁准备的在信号量里说。。。else if (ws 0 !compareAndSetWaitStatus(h, 0, Node.PROPAGATE))continue;}// 这里是出口if (h head) break;} }
http://www.w-s-a.com/news/619405/

相关文章:

  • 做网站搞笑口号wordpress全屏动画
  • 怎么可以建网站小程序代理项目
  • 怎样做软件网站哪个网站用帝国cms做的
  • 网站开发编程的工作方法wordpress dux-plus
  • 廊坊电子商务网站建设公司网站进不去qq空间
  • 南宁网站推广费用创意网页设计素材模板
  • 深圳技术支持 骏域网站建设wordpress 酒主题
  • 东莞网站建设+旅游网站改版数据来源表改怎么做
  • 手机端做的优秀的网站设计企业做网站大概多少钱
  • 优化网站使用体验手机网站解析域名
  • 网站制作 商务做网站的软件名字全拼
  • 阿里巴巴网官方网站温州网站建设设计
  • 传奇购买域名做网站国外网站设计 网址
  • 西安凤城二路网站建设seo网站是什么
  • 网站后台如何更换在线qq咨询代码在线种子资源网
  • 东莞网站优化制作免费中文wordpress主题下载
  • 东莞建筑设计院排名网络优化论文
  • 做牙工作网站郑州前端开发培训机构
  • 温州专业建站网站制作的管理
  • 公司网站开发策划书有没有专门做教程的网站
  • 江苏省工程建设信息网站一天赚1000块钱的游戏
  • 制作响应式网站报价品牌建设整体体系包括什么
  • 网站推广策划报告目前做win7系统最好的网站
  • 东莞网站建设咨询公江西网站建设平台
  • 什么是网站功能源码下载站
  • 石家庄制作网站的公司双柏县住房和城乡建设局网站
  • 影视vip网站建设教程ppt模板免费下载 素材红色
  • 内蒙古城乡建设部网站首页平台网站建设ppt
  • 集约化网站建设项目官方网站建设
  • 原创先锋 北京网站建设网站开发电脑内存要多少