?!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> Java多线E系?-“JUC锁?8?׃n锁和ReentrantReadWriteLock-南软g开发|׃软g开?南赢dU技软g开发公?/title> <meta name="keywords" content="Java多线E系?-“JUC锁?8?׃n锁和ReentrantReadWriteLock"/> <meta name="description" content="概要Java的JUC(java.util.concurrent)包中的锁包括"独占?quot;?quot;׃n?quot;。在“Java多线E系?-“JUC锁?2之互斥锁ReentrantLock”中Q对Java的独占锁q行了说明。本章对Java的“共享锁”进行介l,JUC中的׃n锁有Coun"/> <link href="/css/style.css" rel="stylesheet" type="text/css" /> <meta http-equiv="Cache-Control" content="no-transform" /> <meta http-equiv="Cache-Control" content="no-siteapp" /> </head> <body> <div style="position:fixed;left:-9000px;top:-9000px;"><wbr id="vebt5"><option id="vebt5"><var id="vebt5"><p id="vebt5"></p></var></option></wbr><listing id="vebt5"><object id="vebt5"><nobr id="vebt5"></nobr></object></listing><ol id="vebt5"></ol><pre id="vebt5"><em id="vebt5"><input id="vebt5"></input></em></pre><form id="vebt5"><big id="vebt5"><li id="vebt5"></li></big></form><pre id="vebt5"><em id="vebt5"><kbd id="vebt5"><label id="vebt5"></label></kbd></em></pre><mark id="vebt5"></mark><legend id="vebt5"></legend><noscript id="vebt5"></noscript><div id="vebt5"></div><center id="vebt5"><small id="vebt5"><track id="vebt5"><rp id="vebt5"></rp></track></small></center><tr id="vebt5"><option id="vebt5"><acronym id="vebt5"></acronym></option></tr><track id="vebt5"></track><tt id="vebt5"></tt><track id="vebt5"><form id="vebt5"><pre id="vebt5"><em id="vebt5"></em></pre></form></track><wbr id="vebt5"></wbr><nav id="vebt5"><blockquote id="vebt5"><dd id="vebt5"></dd></blockquote></nav><noscript id="vebt5"></noscript><mark id="vebt5"></mark><div id="vebt5"><menuitem id="vebt5"><wbr id="vebt5"></wbr></menuitem></div><menu id="vebt5"><samp id="vebt5"><meter id="vebt5"><dfn id="vebt5"></dfn></meter></samp></menu><kbd id="vebt5"></kbd><track id="vebt5"><form id="vebt5"><source id="vebt5"></source></form></track><u id="vebt5"></u><var id="vebt5"><cite id="vebt5"><div id="vebt5"></div></cite></var><track id="vebt5"><form id="vebt5"><u id="vebt5"></u></form></track><option id="vebt5"></option><samp id="vebt5"></samp><address id="vebt5"></address><samp id="vebt5"></samp><noframes id="vebt5"></noframes><strong id="vebt5"></strong><progress id="vebt5"><kbd id="vebt5"><div id="vebt5"></div></kbd></progress><s id="vebt5"></s><ins id="vebt5"></ins><table id="vebt5"><strong id="vebt5"><noframes id="vebt5"></noframes></strong></table><listing id="vebt5"></listing><bdo id="vebt5"><nav id="vebt5"><table id="vebt5"><span id="vebt5"></span></table></nav></bdo><samp id="vebt5"></samp><strike id="vebt5"><video id="vebt5"><samp id="vebt5"></samp></video></strike><ruby id="vebt5"></ruby><optgroup id="vebt5"></optgroup><option id="vebt5"><wbr id="vebt5"><p id="vebt5"><rp id="vebt5"></rp></p></wbr></option><sup id="vebt5"><acronym id="vebt5"><tt id="vebt5"><dfn id="vebt5"></dfn></tt></acronym></sup><progress id="vebt5"></progress><tbody id="vebt5"><table id="vebt5"><legend id="vebt5"><dl id="vebt5"></dl></legend></table></tbody><ins id="vebt5"></ins><code id="vebt5"><menu id="vebt5"><sub id="vebt5"><meter id="vebt5"></meter></sub></menu></code><listing id="vebt5"><div id="vebt5"><center id="vebt5"><wbr id="vebt5"></wbr></center></div></listing><dfn id="vebt5"></dfn> <table id="vebt5"><span id="vebt5"><dl id="vebt5"><object id="vebt5"></object></dl></span></table><form id="vebt5"><code id="vebt5"><em id="vebt5"></em></code></form><xmp id="vebt5"></xmp><cite id="vebt5"><div id="vebt5"><code id="vebt5"><em id="vebt5"></em></code></div></cite><address id="vebt5"></address><meter id="vebt5"><source id="vebt5"><table id="vebt5"><ruby id="vebt5"></ruby></table></source></meter><dfn id="vebt5"><option id="vebt5"><dd id="vebt5"><p id="vebt5"></p></dd></option></dfn><strike id="vebt5"></strike><b id="vebt5"></b><kbd id="vebt5"></kbd><sup id="vebt5"><acronym id="vebt5"><delect id="vebt5"><b id="vebt5"></b></delect></acronym></sup><cite id="vebt5"><xmp id="vebt5"><center id="vebt5"><small id="vebt5"></small></center></xmp></cite><optgroup id="vebt5"><xmp id="vebt5"><center id="vebt5"></center></xmp></optgroup><ol id="vebt5"></ol><u id="vebt5"><s id="vebt5"><cite id="vebt5"><ins id="vebt5"></ins></cite></s></u><rp id="vebt5"></rp><dl id="vebt5"></dl><em id="vebt5"></em><big id="vebt5"></big><code id="vebt5"><i id="vebt5"><optgroup id="vebt5"></optgroup></i></code><rp id="vebt5"><big id="vebt5"><s id="vebt5"></s></big></rp><track id="vebt5"><form id="vebt5"><u id="vebt5"></u></form></track><dd id="vebt5"><bdo id="vebt5"><tbody id="vebt5"><table id="vebt5"></table></tbody></bdo></dd><dl id="vebt5"></dl><tr id="vebt5"><option id="vebt5"><acronym id="vebt5"></acronym></option></tr><pre id="vebt5"></pre><center id="vebt5"><small id="vebt5"><track id="vebt5"><rp id="vebt5"></rp></track></small></center><video id="vebt5"></video><dfn id="vebt5"></dfn><dd id="vebt5"><bdo id="vebt5"><th id="vebt5"><address id="vebt5"></address></th></bdo></dd><cite id="vebt5"></cite><center id="vebt5"><small id="vebt5"><noscript id="vebt5"></noscript></small></center><meter id="vebt5"></meter><strong id="vebt5"><input id="vebt5"><th id="vebt5"></th></input></strong><nobr id="vebt5"></nobr><dfn id="vebt5"><font id="vebt5"><dd id="vebt5"></dd></font></dfn><dd id="vebt5"><bdo id="vebt5"><tbody id="vebt5"><video id="vebt5"></video></tbody></bdo></dd><mark id="vebt5"><bdo id="vebt5"><b id="vebt5"><table id="vebt5"></table></b></bdo></mark><output id="vebt5"><ol id="vebt5"><bdo id="vebt5"></bdo></ol></output><strong id="vebt5"><track id="vebt5"><nav id="vebt5"><pre id="vebt5"></pre></nav></track></strong><thead id="vebt5"></thead><mark id="vebt5"><td id="vebt5"><tbody id="vebt5"><video id="vebt5"></video></tbody></td></mark><p id="vebt5"></p><ins id="vebt5"></ins><form id="vebt5"></form><span id="vebt5"><tt id="vebt5"><object id="vebt5"><font id="vebt5"></font></object></tt></span><delect id="vebt5"><tbody id="vebt5"><table id="vebt5"><legend id="vebt5"></legend></table></tbody></delect><optgroup id="vebt5"></optgroup><tbody id="vebt5"><table id="vebt5"><legend id="vebt5"></legend></table></tbody><big id="vebt5"></big> <ruby id="vebt5"></ruby><bdo id="vebt5"><tbody id="vebt5"><table id="vebt5"><span id="vebt5"></span></table></tbody></bdo><b id="vebt5"><output id="vebt5"><dd id="vebt5"></dd></output></b><listing id="vebt5"><ins id="vebt5"><center id="vebt5"></center></ins></listing><table id="vebt5"><strong id="vebt5"><noframes id="vebt5"><th id="vebt5"></th></noframes></strong></table><em id="vebt5"></em><strike id="vebt5"><menu id="vebt5"><samp id="vebt5"><meter id="vebt5"></meter></samp></menu></strike><i id="vebt5"><span id="vebt5"><tt id="vebt5"></tt></span></i><pre id="vebt5"><strong id="vebt5"><input id="vebt5"><thead id="vebt5"></thead></input></strong></pre><ins id="vebt5"></ins><nobr id="vebt5"><sub id="vebt5"><button id="vebt5"></button></sub></nobr><acronym id="vebt5"><tt id="vebt5"><dfn id="vebt5"><font id="vebt5"></font></dfn></tt></acronym><nobr id="vebt5"><mark id="vebt5"><td id="vebt5"><dfn id="vebt5"></dfn></td></mark></nobr><track id="vebt5"></track><dl id="vebt5"><code id="vebt5"><sup id="vebt5"><sub id="vebt5"></sub></sup></code></dl><del id="vebt5"></del><track id="vebt5"></track><video id="vebt5"></video><ol id="vebt5"></ol><track id="vebt5"></track><th id="vebt5"><menuitem id="vebt5"><wbr id="vebt5"><listing id="vebt5"></listing></wbr></menuitem></th><del id="vebt5"></del><sub id="vebt5"></sub><big id="vebt5"></big><b id="vebt5"></b><address id="vebt5"><progress id="vebt5"><noscript id="vebt5"></noscript></progress></address><del id="vebt5"><i id="vebt5"><optgroup id="vebt5"></optgroup></i></del><delect id="vebt5"></delect><dl id="vebt5"></dl><li id="vebt5"></li><tr id="vebt5"><option id="vebt5"><ol id="vebt5"><delect id="vebt5"></delect></ol></option></tr><th id="vebt5"><address id="vebt5"><wbr id="vebt5"><rt id="vebt5"></rt></wbr></address></th><strike id="vebt5"></strike><strike id="vebt5"></strike><noscript id="vebt5"></noscript><p id="vebt5"></p><dl id="vebt5"></dl><progress id="vebt5"><rt id="vebt5"><th id="vebt5"></th></rt></progress><tt id="vebt5"><object id="vebt5"><menu id="vebt5"><sub id="vebt5"></sub></menu></object></tt><menu id="vebt5"></menu><span id="vebt5"><noframes id="vebt5"><tr id="vebt5"></tr></noframes></span><form id="vebt5"></form><video id="vebt5"><span id="vebt5"><tt id="vebt5"></tt></span></video><b id="vebt5"></b><video id="vebt5"></video><center id="vebt5"><small id="vebt5"><noscript id="vebt5"><div id="vebt5"></div></noscript></small></center><cite id="vebt5"><xmp id="vebt5"><code id="vebt5"><small id="vebt5"></small></code></xmp></cite><pre id="vebt5"></pre><i id="vebt5"><ruby id="vebt5"><tt id="vebt5"></tt></ruby></i><font id="vebt5"><mark id="vebt5"><td id="vebt5"></td></mark></font></div> <div class="head"> <div class="top"><span><a href="/html/sitemap.xml">XML</a> | <a href="/html/sitemap.html">HTML</a> | <a href="/sitemap.txt">TXT</a></span></div> <div class="bank"> <div class="logo"> <h1><strong><a href="http://www.cabanatime.com" style="margin-right:10px">南软g开?/a></strong><strong><a href="http://www.cabanatime.com">׃软g开?/a></strong></h1> </div> <div class="contact-top"></div> </div> <div class="menu"> <ul> <li><a href="/">?#160;   ?/a></li> <li><a href="/About/">关于我们</a></li> <li><a href="/Advantage/">开发优?/a></li> <li><a href="/Products/">产品展示</a></li> <li><a href="/Cooperation/">合作企业</a></li> <li><a href="/News/">新闻动?/a></li> <li><a href="/Contact/">联系我们</a></li> </ul> </div> <div class="banner"><img src="/images/banner.jpg" width="1000" height="341"/></div> </div> <div id="position"><div>您当前位|:<a href="/">软g开?/a> >> <a href="/News/">新闻动?/a> >> <a href="/News/Technology/">软g开发技?/a> >> 览文章</div></div> <div class="youshi_f1" id="youshi_tdyx"> <div class="youshi01"> <h1 class="article_title">Java多线E系?-“JUC锁?8?׃n锁和ReentrantReadWriteLock</h1> <div class="article_author">d旉Q?016-12-20 17:17:30 文章作者:<a href="/">南软g开?/a> 览ơ数Q?Script Language="Javascript" Src="/item/GetHits.asp?Action=Count&GetFlag=0&m=1&ID=3072"></Script></div> <div class="article_main"><div id="MyContent"><p style="margin-top: 0px; margin-bottom: 0px; padding: 15px 0px 0px; line-height: 30px; font-family: 宋体; color: rgb(51, 51, 51); font-size: 13.3333px; white-space: normal; background-color: rgb(241, 241, 241);">概要</p><p>Java的JUC(java.util.concurrent)包中的锁包括"独占?quot;?quot;׃n?quot;。在“Java多线E系?-“JUC锁?2?互斥锁ReentrantLock ”中Q对Java的独占锁q行了说明。本章对Java的“共享锁”进行介l,JUC中的׃n锁有CountDownLatch, CyclicBarrier, Semaphore, ReentrantReadWriteLock{;本章会以ReentrantReadWriteLock本对׃n锁进行说明。内容包括:</p><p>ReadWriteLock ?ReentrantReadWriteLock介绍</p><p>ReadWriteLock ?ReentrantReadWriteLock函数列表</p><p>参考代?ZJDK1.7.0_40)</p><p>  获取׃n?/p><p>  释放׃n?/p><p>  公^׃n锁和非公q_享锁</p><p>ReentrantReadWriteLockCZ</p><p> </p><p> </p><p> </p><p>ReadWriteLock ?ReentrantReadWriteLock介绍</p><p>ReadWriteLockQ顾名思义Q是d锁。它l护了一对相关的???“读取锁”和“写入锁”,一个用于读取操作,另一个用于写入操作?/p><p>“读取锁”用于只L作,它是“共享锁”,能同时被多个U程获取?/p><p>“写入锁”用于写入操作,它是“独占锁”,写入锁只能被一个线E锁获取?/p><p>注意Q不能同时存在读取锁和写入锁Q?/p><p>ReadWriteLock是一个接口。ReentrantReadWriteLock是它的实现类QReentrantReadWriteLock包括子类ReadLock和WriteLock?/p><p> </p><p> </p><p> </p><p>ReadWriteLock ?ReentrantReadWriteLock函数列表</p><p>ReadWriteLock函数列表</p><p> </p><p>// q回用于d操作的锁?/p><p>Lock readLock()</p><p>// q回用于写入操作的锁?/p><p>Lock writeLock()</p><p> </p><p> </p><p>ReentrantReadWriteLock函数列表</p><p> </p><p>复制代码</p><p>// 创徏一个新?ReentrantReadWriteLockQ默认是采用“非公^{略”?/p><p>ReentrantReadWriteLock()</p><p>// 创徏一个新?ReentrantReadWriteLockQfair是“公q策略”。fair为trueQ意味着公^{略Q否则,意味着非公q策略?/p><p>ReentrantReadWriteLock(boolean fair)</p><p> </p><p>// q回当前拥有写入锁的U程Q如果没有这LU程Q则q回 null?/p><p>protected Thread getOwner()</p><p>// q回一?collectionQ它包含可能正在{待获取d锁的U程?/p><p>protected Collection<Thread> getQueuedReaderThreads()</p><p>// q回一?collectionQ它包含可能正在{待获取d或写入锁的线E?/p><p>protected Collection<Thread> getQueuedThreads()</p><p>// q回一?collectionQ它包含可能正在{待获取写入锁的U程?/p><p>protected Collection<Thread> getQueuedWriterThreads()</p><p>// q回{待获取d或写入锁的线E估计数目?/p><p>int getQueueLength()</p><p>// 查询当前U程在此锁上保持的重入读取锁数量?/p><p>int getReadHoldCount()</p><p>// 查询为此锁保持的d锁数量?/p><p>int getReadLockCount()</p><p>// q回一?collectionQ它包含可能正在{待与写入锁相关的给定条件的那些U程?/p><p>protected Collection<Thread> getWaitingThreads(Condition condition)</p><p>// q回正等待与写入锁相关的l定条g的线E估计数目?/p><p>int getWaitQueueLength(Condition condition)</p><p>// 查询当前U程在此锁上保持的重入写入锁数量?/p><p>int getWriteHoldCount()</p><p>// 查询是否l定U程正在{待获取d或写入锁?/p><p>boolean hasQueuedThread(Thread thread)</p><p>// 查询是否所有的U程正在{待获取d或写入锁?/p><p>boolean hasQueuedThreads()</p><p>// 查询是否有些U程正在{待与写入锁有关的给定条件?/p><p>boolean hasWaiters(Condition condition)</p><p>// 如果此锁公qx设|ؓ tureQ则q回 true?/p><p>boolean isFair()</p><p>// 查询是否某个U程保持了写入锁?/p><p>boolean isWriteLocked()</p><p>// 查询当前U程是否保持了写入锁?/p><p>boolean isWriteLockedByCurrentThread()</p><p>// q回用于d操作的锁?/p><p>ReentrantReadWriteLock.ReadLock readLock()</p><p>// q回用于写入操作的锁?/p><p>ReentrantReadWriteLock.WriteLock writeLock()</p><p>复制代码</p><p> </p><p> </p><p>参考代?ZJDK1.7.0_40)</p><p>ReentrantReadWriteLock的完?a target="_blank" style="margin: 0px; padding: 0px; color: rgb(51, 51, 51); text-decoration: none;">源码</a></p><p> </p><p> View Code</p><p> </p><p> </p><p>AQS的完整源?/p><p> </p><p> View Code</p><p> </p><p> </p><p>其中Q共享锁源码相关的代码如下:</p><p> </p><p>复制代码</p><p>public static class ReadLock implements Lock, java.io.Serializable {</p><p>    private static final long serialVersionUID = -5992448646407690164L;</p><p>    // ReentrantReadWriteLock的AQS对象</p><p>    private final Sync sync;</p><p> </p><p>    protected ReadLock(ReentrantReadWriteLock lock) {</p><p>        sync = lock.sync;</p><p>    }</p><p> </p><p>    // 获取“共享锁?/p><p>    public void lock() {</p><p>        sync.acquireShared(1);</p><p>    }</p><p> </p><p>    // 如果U程是中断状态,则抛Z场,否则试获取׃n锁?/p><p>    public void lockInterruptibly() throws InterruptedException {</p><p>        sync.acquireSharedInterruptibly(1);</p><p>    }</p><p> </p><p>    // 试获取“共享锁?/p><p>    public  boolean tryLock() {</p><p>        return sync.tryReadLock();</p><p>    }</p><p> </p><p>    // 在指定时间内Q尝试获取“共享锁?/p><p>    public boolean tryLock(long timeout, TimeUnit unit)</p><p>            throws InterruptedException {</p><p>        return sync.tryAcquireSharedNanos(1, unit.toNanos(timeout));</p><p>    }</p><p> </p><p>    // 释放“共享锁?/p><p>    public  void unlock() {</p><p>        sync.releaseShared(1);</p><p>    }</p><p> </p><p>    // 新徏条g</p><p>    public Condition newCondition() {</p><p>        throw new UnsupportedOperationException();</p><p>    }</p><p> </p><p>    public String toString() {</p><p>        int r = sync.getReadLockCount();</p><p>        return super.toString() +</p><p>            "[Read locks = " + r + "]";</p><p>    }</p><p>}</p><p>复制代码</p><p>说明Q?/p><p>ReadLock中的sync是一个Sync对象QSyncl承于AQSc,即Sync是一个锁。ReentrantReadWriteLock中也有一个Sync对象Q而且ReadLock中的sync和ReentrantReadWriteLock中的sync是对应关pR即ReentrantReadWriteLock和ReadLock׃n同一个AQS对象Q共享同一把锁?/p><p>ReentrantReadWriteLock中Sync的定义如下:</p><p> </p><p>final Sync sync;</p><p>下面Q分别从“获取共享锁”和“释攑օ享锁”两个方面对׃n锁进行说明?/p><p> </p><p> </p><p> </p><p>获取׃n?/p><p>获取׃n锁的思想(即lock函数的步?Q是先通过tryAcquireShared()试获取׃n锁。尝试成功的话,则直接返回;试p|的话Q则通过doAcquireShared()不断的@环ƈ试获取锁,若有需要,则阻塞等待。doAcquireShared()在@环中每次试获取锁时Q都是通过tryAcquireShared()来进行尝试的。下面看看“获取共享锁”的详细程?/p><p> </p><p>1. lock()</p><p> </p><p>lock()在ReadLock中,源码如下Q?/p><p> </p><p>public void lock() {</p><p>    sync.acquireShared(1);</p><p>}</p><p> </p><p> </p><p>2. acquireShared()</p><p> </p><p>Syncl承于AQSQacquireShared()定义在AQS中。源码如下:</p><p> </p><p>public final void acquireShared(int arg) {</p><p>    if (tryAcquireShared(arg) < 0)</p><p>        doAcquireShared(arg);</p><p>}</p><p>说明QacquireShared()首先会通过tryAcquireShared()来尝试获取锁?/p><p>试成功的话Q则不再做Q何动?因ؓ已经成功获取到锁??/p><p>试p|的话Q则通过doAcquireShared()来获取锁。doAcquireShared()会获取到锁了才返回?/p><p> </p><p> </p><p> </p><p>3. tryAcquireShared()</p><p> </p><p>tryAcquireShared()定义在ReentrantReadWriteLock.java的Sync中,源码如下Q?/p><p> </p><p>复制代码</p><p>protected final int tryAcquireShared(int unused) {</p><p>    Thread current = Thread.currentThread();</p><p>    // 获取“锁”的状?/p><p>    int c = getState();</p><p>    // 如果“锁”是“互斥锁”,q且获取锁的U程不是currentU程Q则q回-1?/p><p>    if (exclusiveCount(c) != 0 &&</p><p>        getExclusiveOwnerThread() != current)</p><p>        return -1;</p><p>    // 获取“读取锁”的׃n计数</p><p>    int r = sharedCount(c);</p><p>    // 如果“不需要阻塞等待”,q且“读取锁”的׃n计数于MAX_COUNTQ?/p><p>    // 则通过CAS函数更新“锁的状态”,“读取锁”的׃n计数+1?/p><p>    if (!readerShouldBlock() &&</p><p>        r < MAX_COUNT &&</p><p>        compareAndSetState(c, c + SHARED_UNIT)) {</p><p>        // W?ơ获取“读取锁”?/p><p>        if (r == 0) { </p><p>            firstReader = current;</p><p>            firstReaderHoldCount = 1;</p><p>        // 如果惌获取锁的U程(current)是第1个获取锁(firstReader)的线E?/p><p>        } else if (firstReader == current) { </p><p>            firstReaderHoldCount++;</p><p>        } else {</p><p>            // HoldCounter是用来统计该U程获取“读取锁”的ơ数?/p><p>            HoldCounter rh = cachedHoldCounter;</p><p>            if (rh == null || rh.tid != current.getId())</p><p>                cachedHoldCounter = rh = readHolds.get();</p><p>            else if (rh.count == 0)</p><p>                readHolds.set(rh);</p><p>            // 该U程获取“读取锁”的ơ数+1?/p><p>            rh.count++;</p><p>        }</p><p>        return 1;</p><p>    }</p><p>    return fullTryAcquireShared(current);</p><p>}</p><p>复制代码</p><p>说明QtryAcquireShared()的作用是试获取“共享锁”?/p><p>如果在尝试获取锁Ӟ“不需要阻塞等待”ƈ且“读取锁的共享计数小于MAX_COUNT”,则直接通过CAS函数更新“读取锁的共享计数”,以及“当前线E获取读取锁的次?1”?/p><p>否则Q通过fullTryAcquireShared()获取d锁?/p><p> </p><p> </p><p> </p><p>4. fullTryAcquireShared()</p><p> </p><p>fullTryAcquireShared()在ReentrantReadWriteLock中定义,源码如下Q?/p><p> </p><p>复制代码</p><p>final int fullTryAcquireShared(Thread current) {</p><p>    HoldCounter rh = null;</p><p>    for (;;) {</p><p>        // 获取“锁”的状?/p><p>        int c = getState();</p><p>        // 如果“锁”是“互斥锁”,q且获取锁的U程不是currentU程Q则q回-1?/p><p>        if (exclusiveCount(c) != 0) {</p><p>            if (getExclusiveOwnerThread() != current)</p><p>                return -1;</p><p>        // 如果“需要阻塞等待”?/p><p>        // (01) 当“需要阻塞等待”的U程是第1个获取锁的线E的话,则l往下执行?/p><p>        // (02) 当“需要阻塞等待”的U程获取锁的ơ数=0Ӟ则返?1?/p><p>        } else if (readerShouldBlock()) {</p><p>            // 如果惌获取锁的U程(current)是第1个获取锁(firstReader)的线E?/p><p>            if (firstReader == current) {</p><p>            } else {</p><p>                if (rh == null) {</p><p>                    rh = cachedHoldCounter;</p><p>                    if (rh == null || rh.tid != current.getId()) {</p><p>                        rh = readHolds.get();</p><p>                        if (rh.count == 0)</p><p>                            readHolds.remove();</p><p>                    }</p><p>                }</p><p>                // 如果当前U程获取锁的计数=0,则返?1?/p><p>                if (rh.count == 0)</p><p>                    return -1;</p><p>            }</p><p>        }</p><p>        // 如果“不需要阻塞等待”,则获取“读取锁”的׃nl计敎ͼ</p><p>        // 如果׃nl计数超qMAX_COUNTQ则抛出异常?/p><p>        if (sharedCount(c) == MAX_COUNT)</p><p>            throw new Error("Maximum lock count exceeded");</p><p>        // 线E获取“读取锁”的ơ数+1?/p><p>        if (compareAndSetState(c, c + SHARED_UNIT)) {</p><p>            // 如果是第1ơ获取“读取锁”,则更新firstReader和firstReaderHoldCount?/p><p>            if (sharedCount(c) == 0) {</p><p>                firstReader = current;</p><p>                firstReaderHoldCount = 1;</p><p>            // 如果惌获取锁的U程(current)是第1个获取锁(firstReader)的线E,</p><p>            // 则将firstReaderHoldCount+1?/p><p>            } else if (firstReader == current) {</p><p>                firstReaderHoldCount++;</p><p>            } else {</p><p>                if (rh == null)</p><p>                    rh = cachedHoldCounter;</p><p>                if (rh == null || rh.tid != current.getId())</p><p>                    rh = readHolds.get();</p><p>                else if (rh.count == 0)</p><p>                    readHolds.set(rh);</p><p>                // 更新U程的获取“读取锁”的׃n计数</p><p>                rh.count++;</p><p>                cachedHoldCounter = rh; // cache for release</p><p>            }</p><p>            return 1;</p><p>        }</p><p>    }</p><p>}</p><p>复制代码</p><p>说明QfullTryAcquireShared()会根据“是否需要阻塞等待”,“读取锁的共享计数是否超q限制”等{进行处理。如果不需要阻塞等待,q且锁的׃n计数没有过限制Q则通过CAS试获取锁,q返??/p><p> </p><p> </p><p> </p><p>5. doAcquireShared()</p><p> </p><p>doAcquireShared()定义在AQS函数中,源码如下Q?/p><p> </p><p>复制代码</p><p>private void doAcquireShared(int arg) {</p><p>    // addWaiter(Node.SHARED)的作用是Q创建“当前线E”对应的节点Qƈ该U程d到CLH队列中?/p><p>    final Node node = addWaiter(Node.SHARED);</p><p>    boolean failed = true;</p><p>    try {</p><p>        boolean interrupted = false;</p><p>        for (;;) {</p><p>            // 获取“node”的前一节点</p><p>            final Node p = node.predecessor();</p><p>            // 如果“当前线E”是CLH队列的表_则尝试获取共享锁?/p><p>            if (p == head) {</p><p>                int r = tryAcquireShared(arg);</p><p>                if (r >= 0) {</p><p>                    setHeadAndPropagate(node, r);</p><p>                    p.next = null; // help GC</p><p>                    if (interrupted)</p><p>                        selfInterrupt();</p><p>                    failed = false;</p><p>                    return;</p><p>                }</p><p>            }</p><p>            // 如果“当前线E”不是CLH队列的表_则通过shouldParkAfterFailedAcquire()判断是否需要等待,</p><p>            // 需要的话,则通过parkAndCheckInterrupt()q行d{待。若d{待q程中,U程被中断过Q则讄interrupted为true?/p><p>            if (shouldParkAfterFailedAcquire(p, node) &&</p><p>                parkAndCheckInterrupt())</p><p>                interrupted = true;</p><p>        }</p><p>    } finally {</p><p>        if (failed)</p><p>            cancelAcquire(node);</p><p>    }</p><p>}</p><p>复制代码</p><p>说明QdoAcquireShared()的作用是获取׃n锁?/p><p>它会首先创徏U程对应的CLH队列的节点,然后该节点d到CLH队列中。CLH队列是管理获取锁的等待线E的队列?/p><p>如果“当前线E”是CLH队列的表_则尝试获取共享锁Q否则,则需要通过shouldParkAfterFailedAcquire()判断是否d{待Q需要的话,则通过parkAndCheckInterrupt()q行d{待?/p><p>doAcquireShared()会通过for循环Q不断的q行上面的操作;目的是获取׃n锁。需要注意的是:doAcquireShared()在每一ơ尝试获取锁Ӟ是通过tryAcquireShared()来执行的Q?/p><p> </p><p>若读者对CLH队列QshouldParkAfterFailedAcquire(), parkAndCheckInterrupt(){内容的l节感兴,可以参考?a target="_blank" style="margin: 0px; padding: 0px; color: rgb(51, 51, 51); text-decoration: none;">Java</a>多线E系?-“JUC锁?2?互斥锁ReentrantLock”?/p><p> </p><p> </p><p> </p><p>释放׃n?/p><p>释放׃n锁的思想Q是先通过tryReleaseShared()试释放׃n锁。尝试成功的话,则通过doReleaseShared()唤醒“其他等待获取共享锁的线E”,q返回trueQ否则的话,q回flase?/p><p> </p><p>1. unlock()</p><p> </p><p>public  void unlock() {</p><p>    sync.releaseShared(1);</p><p>}</p><p>说明Q该函数实际上调用releaseShared(1)释放׃n锁?/p><p> </p><p> </p><p> </p><p>2. releaseShared()</p><p> </p><p>releaseShared()在AQS中实玎ͼ源码如下Q?/p><p> </p><p>复制代码</p><p>public final boolean releaseShared(int arg) {</p><p>    if (tryReleaseShared(arg)) {</p><p>        doReleaseShared();</p><p>        return true;</p><p>    }</p><p>    return false;</p><p>}</p><p>复制代码</p><p>说明QreleaseShared()的目的是让当前线E释攑֮所持有的共享锁?/p><p>它首先会通过tryReleaseShared()d试释攑օ享锁。尝试成功,则直接返回;试p|Q则通过doReleaseShared()去释攑օ享锁?/p><p> </p><p> </p><p> </p><p>3. tryReleaseShared()</p><p> </p><p>tryReleaseShared()定义在ReentrantReadWriteLock中,源码如下Q?/p><p> </p><p>复制代码</p><p>protected final boolean tryReleaseShared(int unused) {</p><p>    // 获取当前U程Q即释放׃n锁的U程?/p><p>    Thread current = Thread.currentThread();</p><p>    // 如果惌释放锁的U程(current)是第1个获取锁(firstReader)的线E,</p><p>    // q且“第1个获取锁的线E获取锁的次数?1Q则讄firstReader为nullQ?/p><p>    // 否则Q将“第1个获取锁的线E的获取ơ数?1?/p><p>    if (firstReader == current) {</p><p>        // assert firstReaderHoldCount > 0;</p><p>        if (firstReaderHoldCount == 1)</p><p>            firstReader = null;</p><p>        else</p><p>            firstReaderHoldCount--;</p><p>    // 获取rh对象Qƈ更新“当前线E获取锁的信息”?/p><p>    } else {</p><p> </p><p>        HoldCounter rh = cachedHoldCounter;</p><p>        if (rh == null || rh.tid != current.getId())</p><p>            rh = readHolds.get();</p><p>        int count = rh.count;</p><p>        if (count <= 1) {</p><p>            readHolds.remove();</p><p>            if (count <= 0)</p><p>                throw unmatchedUnlockException();</p><p>        }</p><p>        --rh.count;</p><p>    }</p><p>    for (;;) {</p><p>        // 获取锁的状?/p><p>        int c = getState();</p><p>        // 锁的获取次?1?/p><p>        int nextc = c - SHARED_UNIT;</p><p>        // 通过CAS更新锁的状态?/p><p>        if (compareAndSetState(c, nextc))</p><p>            return nextc == 0;</p><p>    }</p><p>}</p><p>复制代码</p><p>说明QtryReleaseShared()的作用是试释放׃n锁?/p><p> </p><p> </p><p> </p><p>4. doReleaseShared()</p><p> </p><p>doReleaseShared()定义在AQS中,源码如下Q?/p><p> </p><p>复制代码</p><p>private void doReleaseShared() {</p><p>    for (;;) {</p><p>        // 获取CLH队列的头节点</p><p>        Node h = head;</p><p>        // 如果头节点不为nullQƈ且头节点不等于tail节点?/p><p>        if (h != null && h != tail) {</p><p>            // 获取头节点对应的U程的状?/p><p>            int ws = h.waitStatus;</p><p>            // 如果头节点对应的U程是SIGNAL状态,则意味着“头节点的下一个节Ҏ对应的线E”需要被unpark唤醒?/p><p>            if (ws == Node.SIGNAL) {</p><p>                // 讄“头节点对应的线E状态”ؓI状态。失败的话,则l@环?/p><p>                if (!compareAndSetWaitStatus(h, Node.SIGNAL, 0))</p><p>                    continue;</p><p>                // 唤醒“头节点的下一个节Ҏ对应的线E”?/p><p>                unparkSuccessor(h);</p><p>            }</p><p>            // 如果头节点对应的U程是空状态,则设|“文件点对应的线E所拥有的共享锁”ؓ其它U程获取锁的I状态?/p><p>            else if (ws == 0 &&</p><p>                     !compareAndSetWaitStatus(h, 0, Node.PROPAGATE))</p><p>                continue;                // loop on failed CAS</p><p>        }</p><p>        // 如果头节点发生变化,则l@环。否则,退出@环?/p><p>        if (h == head)                   // loop if head changed</p><p>            break;</p><p>    }</p><p>}</p><p>复制代码</p><p>说明QdoReleaseShared()会释䏀共享锁”。它会从前往后的遍历CLH队列Q依ơ“唤醒”然后“执行”队列中每个节点对应的线E;最l的目的是让q些U程释放它们所持有的锁?/p><p> </p><p> </p><p> </p><p>公^׃n锁和非公q_享锁</p><p>和互斥锁ReentrantLock一PReadLock也分为公q锁和非公^锁?/p><p> </p><p>公^锁和非公q锁的区别,体现在判断是否需要阻塞的函数readerShouldBlock()是不同的?/p><p>公^锁的readerShouldBlock()的源码如下:</p><p> </p><p>final boolean readerShouldBlock() {</p><p>    return hasQueuedPredecessors();</p><p>}</p><p> </p><p> </p><p>在公q_享锁中,如果在当前线E的前面有其他线E在{待获取׃n锁,则返回trueQ否则,q回false?/p><p>非公q锁的readerShouldBlock()的源码如下:</p><p> </p><p>final boolean readerShouldBlock() {</p><p>    return apparentlyFirstQueuedIsExclusive();</p><p>}</p><p>在非公^׃n锁中Q它会无视当前线E的前面是否有其他线E在{待获取׃n锁。只要该非公q_享锁对应的线E不为nullQ则q回true?/p><p> </p><p> </p><p> </p><p>ReentrantReadWriteLockCZ</p><p>复制代码</p><p> 1 import java.util.concurrent.locks.ReadWriteLock; </p><p> 2 import java.util.concurrent.locks.ReentrantReadWriteLock; </p><p> 3 </p><p> 4 public class ReadWriteLockTest1 { </p><p> 5 </p><p> 6     public static void main(String[] args) { </p><p> 7         // 创徏账户</p><p> 8         MyCount myCount = new MyCount("4238920615242830", 10000); </p><p> 9         // 创徏用户Qƈ指定账户</p><p>10         User user = new User("Tommy", myCount); </p><p>11 </p><p>12         // 分别启动3个“读取̎户金钱”的U程 ?3个“设|̎户金钱”的U程</p><p>13         for (int i=0; i<3; i++) {</p><p>14             user.getCash();</p><p>15             user.setCash((i+1)*1000);</p><p>16         }</p><p>17     } </p><p>18 } </p><p>19 </p><p>20 class User {</p><p>21     private String name;            //用户?nbsp;</p><p>22     private MyCount myCount;        //所要操作的账户 </p><p>23     private ReadWriteLock myLock;   //执行操作所需的锁对象 </p><p>24 </p><p>25     User(String name, MyCount myCount) {</p><p>26         this.name = name; </p><p>27         this.myCount = myCount; </p><p>28         this.myLock = new ReentrantReadWriteLock();</p><p>29     }</p><p>30 </p><p>31     public void getCash() {</p><p>32         new Thread() {</p><p>33             public void run() {</p><p>34                 myLock.readLock().lock(); </p><p>35                 try {</p><p>36                     System.out.println(Thread.currentThread().getName() +" getCash start"); </p><p>37                     myCount.getCash();</p><p>38                     Thread.sleep(1);</p><p>39                     System.out.println(Thread.currentThread().getName() +" getCash end"); </p><p>40                 } catch (InterruptedException e) {</p><p>41                 } finally {</p><p>42                     myLock.readLock().unlock(); </p><p>43                 }</p><p>44             }</p><p>45         }.start();</p><p>46     }</p><p>47 </p><p>48     public void setCash(final int cash) {</p><p>49         new Thread() {</p><p>50             public void run() {</p><p>51                 myLock.writeLock().lock(); </p><p>52                 try {</p><p>53                     System.out.println(Thread.currentThread().getName() +" setCash start"); </p><p>54                     myCount.setCash(cash);</p><p>55                     Thread.sleep(1);</p><p>56                     System.out.println(Thread.currentThread().getName() +" setCash end"); </p><p>57                 } catch (InterruptedException e) {</p><p>58                 } finally {</p><p>59                     myLock.writeLock().unlock(); </p><p>60                 }</p><p>61             }</p><p>62         }.start();</p><p>63     }</p><p>64 }</p><p>65 </p><p>66 class MyCount {</p><p>67     private String id;         //账号 </p><p>68     private int    cash;       //账户余额 </p><p>69 </p><p>70     MyCount(String id, int cash) { </p><p>71         this.id = id; </p><p>72         this.cash = cash; </p><p>73     } </p><p>74 </p><p>75     public String getId() { </p><p>76         return id; </p><p>77     } </p><p>78 </p><p>79     public void setId(String id) { </p><p>80         this.id = id; </p><p>81     } </p><p>82 </p><p>83     public int getCash() { </p><p>84         System.out.println(Thread.currentThread().getName() +" getCash cash="+ cash); </p><p>85         return cash; </p><p>86     } </p><p>87 </p><p>88     public void setCash(int cash) { </p><p>89         System.out.println(Thread.currentThread().getName() +" setCash cash="+ cash); </p><p>90         this.cash = cash; </p><p>91     } </p><p>92 }</p><p>复制代码</p><p>q行l果Q?/p><p> </p><p>复制代码</p><p>Thread-0 getCash start</p><p>Thread-2 getCash start</p><p>Thread-0 getCash cash=10000</p><p>Thread-2 getCash cash=10000</p><p>Thread-0 getCash end</p><p>Thread-2 getCash end</p><p>Thread-1 setCash start</p><p>Thread-1 setCash cash=1000</p><p>Thread-1 setCash end</p><p>Thread-3 setCash start</p><p>Thread-3 setCash cash=2000</p><p>Thread-3 setCash end</p><p>Thread-4 getCash start</p><p>Thread-4 getCash cash=2000</p><p>Thread-4 getCash end</p><p>Thread-5 setCash start</p><p>Thread-5 setCash cash=3000</p><p>Thread-5 setCash end</p><p>复制代码</p><p>l果说明Q?/p><p>(01) 观察Thread0和Thread-2的运行结果,我们发现QThread-0启动q获取到“读取锁”,在它q没q行完毕的时候,Thread-2也启动了q且也成功获取到“读取锁”?/p><p>因此Q“读取锁”支持被多个U程同时获取?/p><p>(02) 观察Thread-1,Thread-3,Thread-5q三个“写入锁”的U程。只要“写入锁”被某线E获取,则该U程q行完毕了,才释放该锁?/p><p>因此Q“写入锁”不支持被多个线E同时获取?/p><p><br/></p></div> </div> </div> </div> <div class="clear"></div> <div class="foot"> <div class="foot_menu"> <ul> <li><a href="/About/">关于我们</a></li> <li><a href="/Advantage/">开发优?/a></li> <li><a href="/Statement/">法律声明</a></li> <li><a href="/Remittance/">汇款方式</a></li> <li><a href="/Contact/">联系我们</a></li> </ul> </div> <div class="banquan"> 手机Q?8678812288 EQMail:1069706080@qq.com<br /> 地址Q山东省南市舜耕\泉城公园东门园内向北50c? 鲁ICP?7011972? 版权所?008Q?013 ׃赢d信息U技有限公司<script type="text/javascript"> var _bdhmProtocol = (("https:" == document.location.protocol) ? " https://" : " http://"); document.write(unescape("%3Cscript src='" + _bdhmProtocol + "#/h.js%3F5fbc066dba9928a1e914c338c6945c98' type='text/javascript'%3E%3C/script%3E")); </script> </div> </div> <div style="position:fixed;left:-9000px;top:-9000px;"><wbr id="vebt5"><option id="vebt5"><var id="vebt5"><p id="vebt5"></p></var></option></wbr><listing id="vebt5"><object id="vebt5"><nobr id="vebt5"></nobr></object></listing><ol id="vebt5"></ol><pre id="vebt5"><em id="vebt5"><input id="vebt5"></input></em></pre><form id="vebt5"><big id="vebt5"><li id="vebt5"></li></big></form><pre id="vebt5"><em id="vebt5"><kbd id="vebt5"><label id="vebt5"></label></kbd></em></pre><mark id="vebt5"></mark><legend id="vebt5"></legend><noscript id="vebt5"></noscript><div id="vebt5"></div><center id="vebt5"><small id="vebt5"><track id="vebt5"><rp id="vebt5"></rp></track></small></center><tr id="vebt5"><option id="vebt5"><acronym id="vebt5"></acronym></option></tr><track id="vebt5"></track><tt id="vebt5"></tt><track id="vebt5"><form id="vebt5"><pre id="vebt5"><em id="vebt5"></em></pre></form></track><wbr id="vebt5"></wbr><nav id="vebt5"><blockquote id="vebt5"><dd id="vebt5"></dd></blockquote></nav><noscript id="vebt5"></noscript><mark id="vebt5"></mark><div id="vebt5"><menuitem id="vebt5"><wbr id="vebt5"></wbr></menuitem></div><menu id="vebt5"><samp id="vebt5"><meter id="vebt5"><dfn id="vebt5"></dfn></meter></samp></menu><kbd id="vebt5"></kbd><track id="vebt5"><form id="vebt5"><source id="vebt5"></source></form></track><u id="vebt5"></u><var id="vebt5"><cite id="vebt5"><div id="vebt5"></div></cite></var><track id="vebt5"><form id="vebt5"><u id="vebt5"></u></form></track><option id="vebt5"></option><samp id="vebt5"></samp><address id="vebt5"></address><samp id="vebt5"></samp><noframes id="vebt5"></noframes><strong id="vebt5"></strong><progress id="vebt5"><kbd id="vebt5"><div id="vebt5"></div></kbd></progress><s id="vebt5"></s><ins id="vebt5"></ins><table id="vebt5"><strong id="vebt5"><noframes id="vebt5"></noframes></strong></table><listing id="vebt5"></listing><bdo id="vebt5"><nav id="vebt5"><table id="vebt5"><span id="vebt5"></span></table></nav></bdo><samp id="vebt5"></samp><strike id="vebt5"><video id="vebt5"><samp id="vebt5"></samp></video></strike><ruby id="vebt5"></ruby><optgroup id="vebt5"></optgroup><option id="vebt5"><wbr id="vebt5"><p id="vebt5"><rp id="vebt5"></rp></p></wbr></option><sup id="vebt5"><acronym id="vebt5"><tt id="vebt5"><dfn id="vebt5"></dfn></tt></acronym></sup><progress id="vebt5"></progress><tbody id="vebt5"><table id="vebt5"><legend id="vebt5"><dl id="vebt5"></dl></legend></table></tbody><ins id="vebt5"></ins><code id="vebt5"><menu id="vebt5"><sub id="vebt5"><meter id="vebt5"></meter></sub></menu></code><listing id="vebt5"><div id="vebt5"><center id="vebt5"><wbr id="vebt5"></wbr></center></div></listing><dfn id="vebt5"></dfn> <table id="vebt5"><span id="vebt5"><dl id="vebt5"><object id="vebt5"></object></dl></span></table><form id="vebt5"><code id="vebt5"><em id="vebt5"></em></code></form><xmp id="vebt5"></xmp><cite id="vebt5"><div id="vebt5"><code id="vebt5"><em id="vebt5"></em></code></div></cite><address id="vebt5"></address><meter id="vebt5"><source id="vebt5"><table id="vebt5"><ruby id="vebt5"></ruby></table></source></meter><dfn id="vebt5"><option id="vebt5"><dd id="vebt5"><p id="vebt5"></p></dd></option></dfn><strike id="vebt5"></strike><b id="vebt5"></b><kbd id="vebt5"></kbd><sup id="vebt5"><acronym id="vebt5"><delect id="vebt5"><b id="vebt5"></b></delect></acronym></sup><cite id="vebt5"><xmp id="vebt5"><center id="vebt5"><small id="vebt5"></small></center></xmp></cite><optgroup id="vebt5"><xmp id="vebt5"><center id="vebt5"></center></xmp></optgroup><ol id="vebt5"></ol><u id="vebt5"><s id="vebt5"><cite id="vebt5"><ins id="vebt5"></ins></cite></s></u><rp id="vebt5"></rp><dl id="vebt5"></dl><em id="vebt5"></em><big id="vebt5"></big><code id="vebt5"><i id="vebt5"><optgroup id="vebt5"></optgroup></i></code><rp id="vebt5"><big id="vebt5"><s id="vebt5"></s></big></rp><track id="vebt5"><form id="vebt5"><u id="vebt5"></u></form></track><dd id="vebt5"><bdo id="vebt5"><tbody id="vebt5"><table id="vebt5"></table></tbody></bdo></dd><dl id="vebt5"></dl><tr id="vebt5"><option id="vebt5"><acronym id="vebt5"></acronym></option></tr><pre id="vebt5"></pre><center id="vebt5"><small id="vebt5"><track id="vebt5"><rp id="vebt5"></rp></track></small></center><video id="vebt5"></video><dfn id="vebt5"></dfn><dd id="vebt5"><bdo id="vebt5"><th id="vebt5"><address id="vebt5"></address></th></bdo></dd><cite id="vebt5"></cite><center id="vebt5"><small id="vebt5"><noscript id="vebt5"></noscript></small></center><meter id="vebt5"></meter><strong id="vebt5"><input id="vebt5"><th id="vebt5"></th></input></strong><nobr id="vebt5"></nobr><dfn id="vebt5"><font id="vebt5"><dd id="vebt5"></dd></font></dfn><dd id="vebt5"><bdo id="vebt5"><tbody id="vebt5"><video id="vebt5"></video></tbody></bdo></dd><mark id="vebt5"><bdo id="vebt5"><b id="vebt5"><table id="vebt5"></table></b></bdo></mark><output id="vebt5"><ol id="vebt5"><bdo id="vebt5"></bdo></ol></output><strong id="vebt5"><track id="vebt5"><nav id="vebt5"><pre id="vebt5"></pre></nav></track></strong><thead id="vebt5"></thead><mark id="vebt5"><td id="vebt5"><tbody id="vebt5"><video id="vebt5"></video></tbody></td></mark><p id="vebt5"></p><ins id="vebt5"></ins><form id="vebt5"></form><span id="vebt5"><tt id="vebt5"><object id="vebt5"><font id="vebt5"></font></object></tt></span><delect id="vebt5"><tbody id="vebt5"><table id="vebt5"><legend id="vebt5"></legend></table></tbody></delect><optgroup id="vebt5"></optgroup><tbody id="vebt5"><table id="vebt5"><legend id="vebt5"></legend></table></tbody><big id="vebt5"></big> <ruby id="vebt5"></ruby><bdo id="vebt5"><tbody id="vebt5"><table id="vebt5"><span id="vebt5"></span></table></tbody></bdo><b id="vebt5"><output id="vebt5"><dd id="vebt5"></dd></output></b><listing id="vebt5"><ins id="vebt5"><center id="vebt5"></center></ins></listing><table id="vebt5"><strong id="vebt5"><noframes id="vebt5"><th id="vebt5"></th></noframes></strong></table><em id="vebt5"></em><strike id="vebt5"><menu id="vebt5"><samp id="vebt5"><meter id="vebt5"></meter></samp></menu></strike><i id="vebt5"><span id="vebt5"><tt id="vebt5"></tt></span></i><pre id="vebt5"><strong id="vebt5"><input id="vebt5"><thead id="vebt5"></thead></input></strong></pre><ins id="vebt5"></ins><nobr id="vebt5"><sub id="vebt5"><button id="vebt5"></button></sub></nobr><acronym id="vebt5"><tt id="vebt5"><dfn id="vebt5"><font id="vebt5"></font></dfn></tt></acronym><nobr id="vebt5"><mark id="vebt5"><td id="vebt5"><dfn id="vebt5"></dfn></td></mark></nobr><track id="vebt5"></track><dl id="vebt5"><code id="vebt5"><sup id="vebt5"><sub id="vebt5"></sub></sup></code></dl><del id="vebt5"></del><track id="vebt5"></track><video id="vebt5"></video><ol id="vebt5"></ol><track id="vebt5"></track><th id="vebt5"><menuitem id="vebt5"><wbr id="vebt5"><listing id="vebt5"></listing></wbr></menuitem></th><del id="vebt5"></del><sub id="vebt5"></sub><big id="vebt5"></big><b id="vebt5"></b><address id="vebt5"><progress id="vebt5"><noscript id="vebt5"></noscript></progress></address><del id="vebt5"><i id="vebt5"><optgroup id="vebt5"></optgroup></i></del><delect id="vebt5"></delect><dl id="vebt5"></dl><li id="vebt5"></li><tr id="vebt5"><option id="vebt5"><ol id="vebt5"><delect id="vebt5"></delect></ol></option></tr><th id="vebt5"><address id="vebt5"><wbr id="vebt5"><rt id="vebt5"></rt></wbr></address></th><strike id="vebt5"></strike><strike id="vebt5"></strike><noscript id="vebt5"></noscript><p id="vebt5"></p><dl id="vebt5"></dl><progress id="vebt5"><rt id="vebt5"><th id="vebt5"></th></rt></progress><tt id="vebt5"><object id="vebt5"><menu id="vebt5"><sub id="vebt5"></sub></menu></object></tt><menu id="vebt5"></menu><span id="vebt5"><noframes id="vebt5"><tr id="vebt5"></tr></noframes></span><form id="vebt5"></form><video id="vebt5"><span id="vebt5"><tt id="vebt5"></tt></span></video><b id="vebt5"></b><video id="vebt5"></video><center id="vebt5"><small id="vebt5"><noscript id="vebt5"><div id="vebt5"></div></noscript></small></center><cite id="vebt5"><xmp id="vebt5"><code id="vebt5"><small id="vebt5"></small></code></xmp></cite><pre id="vebt5"></pre><i id="vebt5"><ruby id="vebt5"><tt id="vebt5"></tt></ruby></i><font id="vebt5"><mark id="vebt5"><td id="vebt5"></td></mark></font></div> <a href="http://www.cabanatime.com/">_ŷպһ_վ߹ۿ_ŷһ߳</a> <script> (function(){ var bp = document.createElement('script'); var curProtocol = window.location.protocol.split(':')[0]; if (curProtocol === 'https') { bp.src = 'https://zz.bdstatic.com/linksubmit/push.js'; } else { bp.src = 'http://push.zhanzhang.baidu.com/push.js'; } var s = document.getElementsByTagName("script")[0]; s.parentNode.insertBefore(bp, s); })(); </script> </body> </html>