﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>BlogJava-上善若水-随笔分类-MultiThreading</title><link>http://www.blogjava.net/DLevin/category/54887.html</link><description>In general the OO style is to use a lot of little objects with a lot of little methods that give us a lot of plug points for overriding and variation.
To do is to be -Nietzsche, To bei is to do -Kant, Do be do be do -Sinatra</description><language>zh-cn</language><lastBuildDate>Fri, 04 Sep 2015 22:19:15 GMT</lastBuildDate><pubDate>Fri, 04 Sep 2015 22:19:15 GMT</pubDate><ttl>60</ttl><item><title>实现自己的Lock对象</title><link>http://www.blogjava.net/DLevin/archive/2015/08/11/426723.html</link><dc:creator>DLevin</dc:creator><author>DLevin</author><pubDate>Mon, 10 Aug 2015 22:08:00 GMT</pubDate><guid>http://www.blogjava.net/DLevin/archive/2015/08/11/426723.html</guid><wfw:comment>http://www.blogjava.net/DLevin/comments/426723.html</wfw:comment><comments>http://www.blogjava.net/DLevin/archive/2015/08/11/426723.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/DLevin/comments/commentRss/426723.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/DLevin/services/trackbacks/426723.html</trackback:ping><description><![CDATA[<p>一直想好好学习concurrent包中的各个类的实现，然而经常看了一点就因为其他事情干扰而放下了。发现这样太不利于自己的成长了，因而最近打算潜心一件一件的完成自己想学习的东西。<br /><br />对concurrent包的学习打算先从Lock的实现开始，因而自然而然的就端起了AbstractQueuedSynchronizer，然而要读懂这个类的源码并不是那么容易，因而我就开始问自己一个问题：如果自己要去实现这个一个Lock对象，应该如何实现呢？<br /><br />要实现Lock对象，首先理解什么是锁？我自己从编程角度简单的理解，所谓锁对象（互斥锁）就是它能保证一次只有一个线程能进入它保护的临界区，如果有一个线程已经拿到锁对象，那么其他对象必须让权等待，而在该线程退出这个临界区时需要唤醒等待列表中的其他线程。更学术一些，<a href="http://pan.baidu.com/s/1gd3zfrX">《计算机操作系统》</a>中对同步机制准则的归纳（P50）： </p><ol> <li>空闲让进。当无进程处于临界区时，表明临界资源处于空闲状态，应允许一个请求进入临界区的进程立即进入自己的临界区，以有效的利用临界资源。</li> <li>忙则等待。当已有进程进入临界区时，表明临界资源正在被访问，因而其他试图进入临界区的进程必须等待，以保证对临界区资源的互斥访问。</li> <li>有限等待。对要求访问临界资源的进程，应保证在有限时间内能进入自己的临界区，以免陷入&#8220;死等&#8221;状态。</li> <li>让权等待。当进程不能进入自己的临界区时，应该释放处理机，以免进程陷入&#8220;忙等&#8221;状态。</li> </ol> <p>说了那么多，其实对互斥锁很简单，只需要一个标记位，如果该标记位为0，表示没有被占用，因而直接获得锁，然后把该标记位置为1，此时其他线程发现该标记位已经是1，因而需要等待。这里对这个标记位的比较并设值必须是原子操作，而在JDK5以后提供的atomic包里的工具类可以很方便的提供这个原子操作。然而上面的四个准则应该漏了一点，即释放锁的线程（进程）和得到锁的线程（进程）应该是同一个，就像一把钥匙对应一把锁（理想的），所以一个非常简单的Lock类可以这么实现：<br /></p><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #0000FF; ">public</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">class</span><span style="color: #000000; ">&nbsp;SpinLockV1&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">private</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">final</span><span style="color: #000000; ">&nbsp;AtomicInteger&nbsp;state&nbsp;</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">new</span><span style="color: #000000; ">&nbsp;AtomicInteger(</span><span style="color: #000000; ">0</span><span style="color: #000000; ">);<br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">private</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">volatile</span><span style="color: #000000; ">&nbsp;Thread&nbsp;owner;&nbsp;</span><span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;这里owner字段可能存在中间值，不可靠，因而其他线程不可以依赖这个字段的值</span><span style="color: #008000; "><br /></span><span style="color: #000000; ">&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">public</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">void</span><span style="color: #000000; ">&nbsp;lock()&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">while</span><span style="color: #000000; ">&nbsp;(</span><span style="color: #000000; ">!</span><span style="color: #000000; ">state.compareAndSet(</span><span style="color: #000000; ">0</span><span style="color: #000000; ">,&nbsp;</span><span style="color: #000000; ">1</span><span style="color: #000000; ">))&nbsp;{&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;owner&nbsp;</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&nbsp;Thread.currentThread();<br />&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">public</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">void</span><span style="color: #000000; ">&nbsp;unlock()&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Thread&nbsp;currentThread&nbsp;</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&nbsp;Thread.currentThread();<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">if</span><span style="color: #000000; ">&nbsp;(owner&nbsp;</span><span style="color: #000000; ">!=</span><span style="color: #000000; ">&nbsp;currentThread&nbsp;</span><span style="color: #000000; ">||</span><span style="color: #000000; ">&nbsp;</span><span style="color: #000000; ">!</span><span style="color: #000000; ">state.compareAndSet(</span><span style="color: #000000; ">1</span><span style="color: #000000; ">,&nbsp;</span><span style="color: #000000; ">0</span><span style="color: #000000; ">))&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">throw</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">new</span><span style="color: #000000; ">&nbsp;IllegalStateException(</span><span style="color: #000000; ">"</span><span style="color: #000000; ">The&nbsp;lock&nbsp;is&nbsp;not&nbsp;owned&nbsp;by&nbsp;thread:&nbsp;</span><span style="color: #000000; ">"</span><span style="color: #000000; ">&nbsp;</span><span style="color: #000000; ">+</span><span style="color: #000000; ">&nbsp;currentThread);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;owner&nbsp;</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">null</span><span style="color: #000000; ">;<br />&nbsp;&nbsp;&nbsp;&nbsp;}<br />}</span></div><p>一个简单的测试方法：<br /></p><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #000000; ">&nbsp;&nbsp;&nbsp;&nbsp;@Test<br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">public</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">void</span><span style="color: #000000; ">&nbsp;testLockCorrectly()&nbsp;</span><span style="color: #0000FF; ">throws</span><span style="color: #000000; ">&nbsp;InterruptedException&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">final</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">int</span><span style="color: #000000; ">&nbsp;COUNT&nbsp;</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&nbsp;</span><span style="color: #000000; ">100</span><span style="color: #000000; ">;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Thread[]&nbsp;threads&nbsp;</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">new</span><span style="color: #000000; ">&nbsp;Thread[COUNT];<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SpinLockV1&nbsp;lock&nbsp;</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">new</span><span style="color: #000000; ">&nbsp;SpinLockV1();<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;AddRunner&nbsp;runner&nbsp;</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">new</span><span style="color: #000000; ">&nbsp;AddRunner(lock);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">for</span><span style="color: #000000; ">&nbsp;(</span><span style="color: #0000FF; ">int</span><span style="color: #000000; ">&nbsp;i&nbsp;</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&nbsp;</span><span style="color: #000000; ">0</span><span style="color: #000000; ">;&nbsp;i&nbsp;</span><span style="color: #000000; ">&lt;</span><span style="color: #000000; ">&nbsp;COUNT;&nbsp;i</span><span style="color: #000000; ">++</span><span style="color: #000000; ">)&nbsp;{&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;threads[i]&nbsp;</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">new</span><span style="color: #000000; ">&nbsp;Thread(runner,&nbsp;</span><span style="color: #000000; ">"</span><span style="color: #000000; ">thread-</span><span style="color: #000000; ">"</span><span style="color: #000000; ">&nbsp;</span><span style="color: #000000; ">+</span><span style="color: #000000; ">&nbsp;i);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;threads[i].start();<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">for</span><span style="color: #000000; ">&nbsp;(</span><span style="color: #0000FF; ">int</span><span style="color: #000000; ">&nbsp;i&nbsp;</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&nbsp;</span><span style="color: #000000; ">0</span><span style="color: #000000; ">;&nbsp;i&nbsp;</span><span style="color: #000000; ">&lt;</span><span style="color: #000000; ">&nbsp;COUNT;&nbsp;i</span><span style="color: #000000; ">++</span><span style="color: #000000; ">)&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;threads[i].join();<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; assertEquals(COUNT,&nbsp;runner.getState());<br />&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">private</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">static</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">class</span><span style="color: #000000; ">&nbsp;AddRunner&nbsp;</span><span style="color: #0000FF; ">implements</span><span style="color: #000000; ">&nbsp;Runnable&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">private</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">final</span><span style="color: #000000; ">&nbsp;SpinLockV1&nbsp;lock;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">private</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">int</span><span style="color: #000000; ">&nbsp;state&nbsp;</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&nbsp;</span><span style="color: #000000; ">0</span><span style="color: #000000; ">;<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">public</span><span style="color: #000000; ">&nbsp;AddRunner(SpinLockV1&nbsp;lock)&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">this</span><span style="color: #000000; ">.lock&nbsp;</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&nbsp;lock;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">public</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">void</span><span style="color: #000000; ">&nbsp;run()&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;lock.lock();<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">try</span><span style="color: #000000; ">&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;quietSleep(</span><span style="color: #000000; ">10</span><span style="color: #000000; ">);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;state</span><span style="color: #000000; ">++</span><span style="color: #000000; ">;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(Thread.currentThread().getName()&nbsp;</span><span style="color: #000000; ">+</span><span style="color: #000000; ">&nbsp;</span><span style="color: #000000; ">"</span><span style="color: #000000; ">:&nbsp;</span><span style="color: #000000; ">"</span><span style="color: #000000; ">&nbsp;</span><span style="color: #000000; ">+</span><span style="color: #000000; ">&nbsp;state);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;</span><span style="color: #0000FF; ">finally</span><span style="color: #000000; ">&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;lock.unlock();<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">public</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">int</span><span style="color: #000000; ">&nbsp;getState()&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">return</span><span style="color: #000000; ">&nbsp;state;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;}</span></div><p>然而这个SpinLock其实并不需要state这个字段，因为owner的赋值与否也是一种状态，因而可以用它作为一种互斥状态：<br /></p><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #0000FF; ">public</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">class</span><span style="color: #000000; ">&nbsp;SpinLockV2&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">private</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">final</span><span style="color: #000000; ">&nbsp;AtomicReference</span><span style="color: #000000; ">&lt;</span><span style="color: #000000; ">Thread</span><span style="color: #000000; ">&gt;</span><span style="color: #000000; ">&nbsp;owner&nbsp;</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">new</span><span style="color: #000000; ">&nbsp;AtomicReference</span><span style="color: #000000; ">&lt;</span><span style="color: #000000; ">Thread</span><span style="color: #000000; ">&gt;</span><span style="color: #000000; ">(</span><span style="color: #0000FF; ">null</span><span style="color: #000000; ">);<br />&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">public</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">void</span><span style="color: #000000; ">&nbsp;lock()&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">final</span><span style="color: #000000; ">&nbsp;Thread&nbsp;currentThread&nbsp;</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&nbsp;Thread.currentThread();<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">while</span><span style="color: #000000; ">&nbsp;(</span><span style="color: #000000; ">!</span><span style="color: #000000; ">owner.compareAndSet(</span><span style="color: #0000FF; ">null</span><span style="color: #000000; ">,&nbsp;currentThread))&nbsp;{&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">public</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">void</span><span style="color: #000000; ">&nbsp;unlock()&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Thread&nbsp;currentThread&nbsp;</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&nbsp;Thread.currentThread();<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">if</span><span style="color: #000000; ">&nbsp;(</span><span style="color: #000000; ">!</span><span style="color: #000000; ">owner.compareAndSet(currentThread,&nbsp;</span><span style="color: #0000FF; ">null</span><span style="color: #000000; ">))&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">throw</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">new</span><span style="color: #000000; ">&nbsp;IllegalStateException(</span><span style="color: #000000; ">"</span><span style="color: #000000; ">The&nbsp;lock&nbsp;is&nbsp;not&nbsp;owned&nbsp;by&nbsp;thread:&nbsp;</span><span style="color: #000000; ">"</span><span style="color: #000000; ">&nbsp;</span><span style="color: #000000; ">+</span><span style="color: #000000; ">&nbsp;currentThread);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;}<br />}</span></div><p>这在操作系统中被定义为整形信号量，然而整形信号量如果没拿到锁会一直处于&#8220;忙等&#8221;状态（没有遵循有限等待和让权等待的准则），因而这种锁也叫Spin Lock，在短暂的等待中它可以提升性能，因为可以减少线程的切换，concurrent包中的Atomic大部分都采用这种机制实现，然而如果需要长时间的等待，&#8220;忙等&#8221;会占用不必要的CPU时间，从而性能会变的很差，这个时候就需要将没有拿到锁的线程放到等待列表中，这种方式在操作系统中也叫记录型信号量，它遵循了让权等待准则（当前没有实现有限等待准则）。在JDK6以后提供了LockSupport.park()/LockSupport.unpark()操作，可以将当前线程放入一个等待列表或将一个线程从这个等待列表中唤醒。然而这个park/unpark的等待列表是一个全局的等待列表，在unpartk的时候还是需要提供需要唤醒的Thread对象，因而我们需要维护自己的等待列表，但是如果我们可以用JDK提供的工具类ConcurrentLinkedQueue，就非常容易实现，如LockSupport文档中给出来的<a href="http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/locks/LockSupport.html">代码事例</a>：<br /></p><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #0000FF; ">class</span><span style="color: #000000; ">&nbsp;FIFOMutex&nbsp;{<br />&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">private</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">final</span><span style="color: #000000; ">&nbsp;AtomicBoolean&nbsp;locked&nbsp;</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">new</span><span style="color: #000000; ">&nbsp;AtomicBoolean(</span><span style="color: #0000FF; ">false</span><span style="color: #000000; ">);<br />&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">private</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">final</span><span style="color: #000000; ">&nbsp;Queue</span><span style="color: #000000; ">&lt;</span><span style="color: #000000; ">Thread</span><span style="color: #000000; ">&gt;</span><span style="color: #000000; ">&nbsp;waiters</span><span style="color: #000000; "> =</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">new</span><span style="color: #000000; ">&nbsp;ConcurrentLinkedQueue</span><span style="color: #000000; ">&lt;</span><span style="color: #000000; ">Thread</span><span style="color: #000000; ">&gt;</span><span style="color: #000000; ">();<br /><br />&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">public</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">void</span><span style="color: #000000; ">&nbsp;lock()&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">boolean</span><span style="color: #000000; ">&nbsp;wasInterrupted&nbsp;</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">false</span><span style="color: #000000; ">;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Thread&nbsp;current&nbsp;</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&nbsp;Thread.currentThread();<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;waiters.add(current);<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;Block&nbsp;while&nbsp;not&nbsp;first&nbsp;in&nbsp;queue&nbsp;or&nbsp;cannot&nbsp;acquire&nbsp;lock</span><span style="color: #008000; "><br /></span><span style="color: #000000; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">while</span><span style="color: #000000; ">&nbsp;(waiters.peek()&nbsp;</span><span style="color: #000000; ">!=</span><span style="color: #000000; ">&nbsp;current&nbsp;</span><span style="color: #000000; ">||</span><span style="color: #000000; "> </span><span style="color: #000000; ">!</span><span style="color: #000000; ">locked.compareAndSet(</span><span style="color: #0000FF; ">false</span><span style="color: #000000; ">,&nbsp;</span><span style="color: #0000FF; ">true</span><span style="color: #000000; ">))&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;LockSupport.park(</span><span style="color: #0000FF; ">this</span><span style="color: #000000; ">);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">if</span><span style="color: #000000; ">&nbsp;(Thread.interrupted())&nbsp;</span><span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;ignore&nbsp;interrupts&nbsp;while&nbsp;waiting</span><span style="color: #008000; "><br /></span><span style="color: #000000; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wasInterrupted&nbsp;</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">true</span><span style="color: #000000; ">;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;waiters.remove();<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">if</span><span style="color: #000000; ">&nbsp;(wasInterrupted)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;reassert&nbsp;interrupt&nbsp;status&nbsp;on&nbsp;exit</span><span style="color: #008000; "><br /></span><span style="color: #000000; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;current.interrupt();<br />&nbsp;&nbsp;&nbsp;}<br /><br />&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">public</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">void</span><span style="color: #000000; ">&nbsp;unlock()&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;locked.set(</span><span style="color: #0000FF; ">false</span><span style="color: #000000; ">);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;LockSupport.unpark(waiters.peek());<br />&nbsp;&nbsp;&nbsp;}<br />&nbsp;}</span></div><p>在该代码事例中，有一个线程等待队列和锁标记字段，每次调用lock时先将当前线程放入这个等待队列中，然后拿出队列头线程对象，如果该线程对象正好是当前线程，并且成功
使用CAS方式设置locked字段（这里需要两个同时满足，因为可能出现一个线程已经从队列中移除了但还没有unlock，此时另一个线程调用lock方法，此时队列头的线程就是第二个线程，然而由于第一个线程还没有unlock或者正在unlock，因而需要使用CAS原子操作来判断是否要park），表示该线程竞争成功，获得锁，否则将当前线程park，这里之所以要放在
while循环中，因为park操作可能无理由返回(<strong>spuriously</strong>)，如文档中给出的描述：<br /></p><fieldset><legend>LockSupport.park()</legend><pre>public static&nbsp;void&nbsp;park(<a href="http://docs.oracle.com/javase/7/docs/api/java/lang/Object.html" title="class in java.lang">Object</a>&nbsp;blocker)</pre>
<div class="block">Disables the current thread for thread scheduling purposes unless the
 permit is available.

 <p>If the permit is available then it is consumed and the call returns
 immediately; otherwise
 the current thread becomes disabled for thread scheduling
 purposes and lies dormant until one of three things happens:

 </p><ul><li>Some other thread invokes <a href="http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/locks/LockSupport.html#unpark%28java.lang.Thread%29"><code>unpark</code></a> with the
 current thread as the target; or

 </li><li>Some other thread <a href="http://docs.oracle.com/javase/7/docs/api/java/lang/Thread.html#interrupt%28%29">interrupts</a>
 the current thread; or

 </li><li><strong>The call spuriously (that is, for no reason) returns.
 </strong></li></ul>

 <p>This method does <em>not</em> report which of these caused the
 method to return. Callers should re-check the conditions which caused
 the thread to park in the first place. Callers may also determine,
 for example, the interrupt status of the thread upon return.</p></div>
<dl><dt><span class="strong">Parameters:</span></dt><dd><code>blocker</code> - the synchronization object responsible for this
        thread parking</dd><dt><span class="strong">Since:</span></dt><dd>1.6</dd></dl></fieldset>我在实现自己的类时就被这个&#8220;无理由返回&#8221;坑了好久。对于已经获得锁的线程，将该线程从等待队列中移除，这里由于ConcurrentLinkedQueue是线程安全的，因而能保证每次都是队列头的线程得到锁，因而在得到锁匙将队列头移除。unlock逻辑比较简单，只需要将locked字段打开（设置为false），唤醒（unpark）队列头的线程即可，然后该线程会继续在lock方法的while循环中继续竞争unlocked字段，并将它自己从线程队列中移除表示获得锁成功。当然安全起见，最好在unlock中加入一些验证逻辑，如解锁的线程和加锁的线程需要相同。<br /><br />然而本文的目的是自己实现一个Lock对象，即只使用一些基本的操作，而不使用JDK提供的Atomic类和ConcurrentLinkedQueue。类似的首先我们也需要一个队列存放等待线程队列（公平起见，使用先进先出队列），因而先定义一个Node对象用以构成这个队列：<br /><p>&nbsp;</p><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #000000; ">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">protected</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">static</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">class</span><span style="color: #000000; ">&nbsp;Node&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">volatile</span><span style="color: #000000; ">&nbsp;Thread&nbsp;owner;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">volatile</span><span style="color: #000000; ">&nbsp;Node&nbsp;prev;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">volatile</span><span style="color: #000000; ">&nbsp;Node&nbsp;next;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">public</span><span style="color: #000000; ">&nbsp;Node(Thread&nbsp;owner)&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">this</span><span style="color: #000000; ">.owner&nbsp;</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&nbsp;owner;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">this</span><span style="color: #000000; ">.state&nbsp;</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&nbsp;INIT;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">public</span><span style="color: #000000; ">&nbsp;Node()&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">this</span><span style="color: #000000; ">(Thread.currentThread());<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;}</span></div><p>简单起见，队列头是一个起点的placeholder，每个调用lock的线程都先将自己竞争放入这个队列尾，每个队列头后一个线程（Node）即是获得锁的线程，所以我们需要有head Node字段用以快速获取队列头的后一个Node，而tail Node字段用来快速插入新的Node，所以关键在于如何线程安全的构建这个队列，方法还是一样的，使用CAS操作，即CAS方法将自己设置成tail值，然后重新构建这个列表：<br /></p><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #000000; ">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">protected</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">boolean</span><span style="color: #000000; ">&nbsp;enqueue(Node&nbsp;node)&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">while</span><span style="color: #000000; ">&nbsp;(</span><span style="color: #0000FF; ">true</span><span style="color: #000000; ">)&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">final</span><span style="color: #000000; ">&nbsp;Node&nbsp;preTail&nbsp;</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&nbsp;tail;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;node.prev&nbsp;</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&nbsp;preTail;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">if</span><span style="color: #000000; ">&nbsp;(compareAndSetTail(preTail,&nbsp;node))&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;preTail.next&nbsp;</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&nbsp;node;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">return</span><span style="color: #000000; ">&nbsp;node.prev&nbsp;</span><span style="color: #000000; ">==</span><span style="color: #000000; ">&nbsp;head;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;}</span></div><p>在当前线程Node以线程安全的方式放入这个队列后，lock实现相对就比较简单了，如果当前Node是的前驱是head，该线程获得锁，否则park当前线程，处理park无理由返回的问题，因而将park放入while循环中（该实现是一个不可重入的实现）：<br /></p><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #000000; ">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">public</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">void</span><span style="color: #000000; ">&nbsp;lock()&nbsp;{</span><span style="color: #000000; "><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;Put&nbsp;the&nbsp;latest&nbsp;node&nbsp;to&nbsp;a&nbsp;queue&nbsp;first,&nbsp;then&nbsp;check&nbsp;if&nbsp;the&nbsp;it&nbsp;is&nbsp;the&nbsp;first&nbsp;node<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;this&nbsp;way,&nbsp;the&nbsp;list&nbsp;is&nbsp;the&nbsp;only&nbsp;shared&nbsp;resource&nbsp;to&nbsp;deal&nbsp;with</span><span style="color: #008000; "><br /></span><span style="color: #000000; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Node&nbsp;node&nbsp;</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">new</span><span style="color: #000000; ">&nbsp;Node();<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">if</span><span style="color: #000000; ">&nbsp;(enqueue(node))&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;current&nbsp;</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&nbsp;node.owner;</span><span style="color: #000000; "><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;</span><span style="color: #0000FF; ">else</span><span style="color: #000000; ">&nbsp;{</span><span style="color: #000000; "><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">while</span><span style="color: #000000; ">&nbsp;(node.prev&nbsp;</span><span style="color: #000000; ">!=</span><span style="color: #000000; ">&nbsp;head)&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;LockSupport.park(</span><span style="color: #0000FF; ">this</span><span style="color: #000000; ">);&nbsp;</span><span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;This&nbsp;may&nbsp;return&nbsp;"spuriously"!!,&nbsp;so&nbsp;put&nbsp;it&nbsp;to&nbsp;while</span><span style="color: #008000; "></span><span style="color: #000000; "><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</span><span style="color: #000000; "><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;current&nbsp;</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&nbsp;node.owner;</span><span style="color: #000000; "><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;}</span></div><p>unlock的实现需要考虑多种情况，如果当前Node(head.next)有后驱，那么直接unpark该后驱即可；如果没有，表示当前已经没有其他线程在等待队列中，然而在这个判断过程中可能会有其他线程进入，因而需要用CAS的方式设置tail，如果设置失败，表示此时有其他线程进入，因而需要将该新进入的线程unpark从而该新进入的线程在调用park后可以立即返回（这里的CAS和enqueue的CAS都是对tail操作，因而能保证状态一致）：<br /></p><div style="background-color: #eeeeee; font-size: 13px; border: 1px solid #cccccc; padding: 4px 5px 4px 4px; width: 98%; word-break: break-all;"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #000000; ">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">public</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">void</span><span style="color: #000000; ">&nbsp;unlock()&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Node&nbsp;curNode&nbsp;</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&nbsp;unlockValidate();</span><span style="color: #000000; "><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Node&nbsp;next&nbsp;</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&nbsp;curNode.next;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">if</span><span style="color: #000000; ">&nbsp;(next&nbsp;</span><span style="color: #000000; ">!=</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">null</span><span style="color: #000000; ">)&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="color: #0000FF; "></span><span style="color: #000000; "></span><span style="color: #000000; "></span><span style="color: #000000; ">head.next = next;</span><span style="color: #000000; "><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;next.prev&nbsp;</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&nbsp;head;</span><span style="color: #000000; "><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;LockSupport.unpark(next.owner);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;</span><span style="color: #0000FF; ">else</span><span style="color: #000000; ">&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">if</span><span style="color: #000000; ">&nbsp;(</span><span style="color: #000000; ">!</span><span style="color: #000000; ">compareAndSetTail(curNode,&nbsp;head))&nbsp;{</span><span style="color: #000000; "><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="color: #000000; "><span style="color: #000000; "></span><span style="color: #0000FF; ">while</span><span style="color: #000000; "></span> (curNode.next == null) { } </span><span style="color: #000000; "><span style="color: #000000; "></span><span style="color: #008000; ">//</span><span style="color: #008000; "> Wait until the next available</span></span><br /><span style="color: #000000; "><span style="color: #000000; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;Another&nbsp;node&nbsp;queued&nbsp;during&nbsp;the&nbsp;time,&nbsp;so&nbsp;we&nbsp;have&nbsp;to&nbsp;unlock&nbsp;that,&nbsp;or&nbsp;else,&nbsp;this&nbsp;node&nbsp;can&nbsp;never&nbsp;unparked</span><span style="color: #008000; "></span><span style="color: #000000; "><br /></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; unlock();<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;</span><span style="color: #0000FF; ">else</span><span style="color: #000000; ">&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="color: #0000FF; "></span><span style="color: #000000; ">compareAndSetNext(head,&nbsp;curNode,&nbsp;</span><span style="color: #0000FF; ">null</span><span style="color: #000000; ">);</span><span style="color: #000000; "><span style="color: #008000; "> //</span><span style="color: #008000;"> Still use CAS here as the head.next may already been changed</span><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;}</span></div><p>具体的代码和测试类可以参考查看<a href="https://github.com/dinglevin/levin-learn/tree/master/levin-learn-corejava/src/main/java/levin/learn/corejava/concurrent/locks">这里</a>。<br /></p><p><br />其实直到自己写完这个类后才直到者其实这是一个MCS锁的变种，因而这个实现每个线程park在自身对应的node上，而由前一个线程unpark它；而AbstractQueuedSynchronizer是CLH锁，因为它的park由前驱状态决定，虽然它也是由前一个线程unpark它。具体可以参考<a href="http://coderbee.net/index.php/concurrent/20131115/577">这里</a>。</p><img src ="http://www.blogjava.net/DLevin/aggbug/426723.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/DLevin/" target="_blank">DLevin</a> 2015-08-11 06:08 <a href="http://www.blogjava.net/DLevin/archive/2015/08/11/426723.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[转]自旋锁、排队自旋锁、MCS锁、CLH锁</title><link>http://www.blogjava.net/DLevin/archive/2015/08/07/416102.html</link><dc:creator>DLevin</dc:creator><author>DLevin</author><pubDate>Thu, 06 Aug 2015 16:18:00 GMT</pubDate><guid>http://www.blogjava.net/DLevin/archive/2015/08/07/416102.html</guid><wfw:comment>http://www.blogjava.net/DLevin/comments/416102.html</wfw:comment><comments>http://www.blogjava.net/DLevin/archive/2015/08/07/416102.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/DLevin/comments/commentRss/416102.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/DLevin/services/trackbacks/416102.html</trackback:ping><description><![CDATA[转自：http://coderbee.net/index.php/concurrent/20131115/577<br /><br /><h3>自旋锁（Spin lock）</h3><p style="margin: 0px 0px 1.714285714rem; padding: 0px; border: 0px; vertical-align: baseline; line-height: 24px; color: #444444; font-family: 'Open Sans', Helvetica, Arial, sans-serif; background-color: #ffffff;">自旋锁是指当一个线程尝试获取某个锁时，如果该锁已被其他线程占用，就一直循环检测锁是否被释放，而不是进入线程挂起或睡眠状态。</p><p style="margin: 0px 0px 1.714285714rem; padding: 0px; border: 0px; vertical-align: baseline; line-height: 24px; color: #444444; font-family: 'Open Sans', Helvetica, Arial, sans-serif; background-color: #ffffff;">自旋锁适用于锁保护的临界区很小的情况，临界区很小的话，锁占用的时间就很短。</p><h4>简单的实现</h4><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #0000FF; ">import</span><span style="color: #000000; ">&nbsp;java.util.concurrent.atomic.AtomicReference;<br /><br /></span><span style="color: #0000FF; ">public</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">class</span><span style="color: #000000; ">&nbsp;SpinLock&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">private</span><span style="color: #000000; ">&nbsp;AtomicReference</span><span style="color: #000000; ">&lt;</span><span style="color: #000000; ">Thread</span><span style="color: #000000; ">&gt;</span><span style="color: #000000; ">&nbsp;owner&nbsp;</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">new</span><span style="color: #000000; ">&nbsp;AtomicReference</span><span style="color: #000000; ">&lt;</span><span style="color: #000000; ">Thread</span><span style="color: #000000; ">&gt;</span><span style="color: #000000; ">();<br />&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">public</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">void</span><span style="color: #000000; ">&nbsp;lock()&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Thread&nbsp;currentThread&nbsp;</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&nbsp;Thread.currentThread();</span><span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;如果锁未被占用，则设置当前线程为锁的拥有者</span><span style="color: #008000; "><br /></span><span style="color: #000000; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">while</span><span style="color: #000000; ">&nbsp;(owner.compareAndSet(</span><span style="color: #0000FF; ">null</span><span style="color: #000000; ">,&nbsp;currentThread))&nbsp;{&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">public</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">void</span><span style="color: #000000; ">&nbsp;unlock()&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Thread&nbsp;currentThread&nbsp;</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&nbsp;Thread.currentThread();</span><span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;只有锁的拥有者才能释放锁</span><span style="color: #008000; "><br /></span><span style="color: #000000; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;owner.compareAndSet(currentThread,&nbsp;</span><span style="color: #0000FF; ">null</span><span style="color: #000000; ">);<br />&nbsp;&nbsp;&nbsp;&nbsp;}<br />}</span></div><p style="margin: 0px 0px 1.714285714rem; padding: 0px; border: 0px; vertical-align: baseline; line-height: 24px; color: #444444; font-family: 'Open Sans', Helvetica, Arial, sans-serif; background-color: #ffffff;"><br />SimpleSpinLock里有一个owner属性持有锁当前拥有者的线程的引用，如果该引用为null，则表示锁未被占用，不为null则被占用。</p><p style="margin: 0px 0px 1.714285714rem; padding: 0px; border: 0px; vertical-align: baseline; line-height: 24px; color: #444444; font-family: 'Open Sans', Helvetica, Arial, sans-serif; background-color: #ffffff;">这里用AtomicReference是为了使用它的原子性的compareAndSet方法（CAS操作），解决了多线程并发操作导致数据不一致的问题，确保其他线程可以看到锁的真实状态<br /></p><h4>缺点</h4><ol style="margin: 0px 0px 1.714285714rem; padding: 0px; border: 0px; vertical-align: baseline; list-style-position: outside; list-style-image: initial; line-height: 24px; color: #444444; font-family: 'Open Sans', Helvetica, Arial, sans-serif; background-color: #ffffff;"><li style="margin: 0px 0px 0px 2.571428571rem; padding: 0px; border: 0px; vertical-align: baseline;">CAS操作需要硬件的配合；</li><li style="margin: 0px 0px 0px 2.571428571rem; padding: 0px; border: 0px; vertical-align: baseline;">保证各个CPU的缓存（L1、L2、L3、跨CPU Socket、主存）的数据一致性，通讯开销很大，在多处理器系统上更严重；</li><li style="margin: 0px 0px 0px 2.571428571rem; padding: 0px; border: 0px; vertical-align: baseline;">没法保证公平性，不保证等待进程/线程按照FIFO顺序获得锁。</li></ol><h3>Ticket Lock</h3><p style="margin: 0px 0px 1.714285714rem; padding: 0px; border: 0px; vertical-align: baseline; line-height: 24px; color: #444444; font-family: 'Open Sans', Helvetica, Arial, sans-serif; background-color: #ffffff;">Ticket Lock 是为了解决上面的公平性问题，类似于现实中银行柜台的排队叫号：锁拥有一个服务号，表示正在服务的线程，还有一个排队号；每个线程尝试获取锁之前先拿一个排队号，然后不断轮询锁的当前服务号是否是自己的排队号，如果是，则表示自己拥有了锁，不是则继续轮询。</p><p style="margin: 0px 0px 1.714285714rem; padding: 0px; border: 0px; vertical-align: baseline; line-height: 24px; color: #444444; font-family: 'Open Sans', Helvetica, Arial, sans-serif; background-color: #ffffff;">当线程释放锁时，将服务号加1，这样下一个线程看到这个变化，就退出自旋。</p><h4>简单的实现</h4><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #0000FF; ">import</span><span style="color: #000000; ">&nbsp;java.util.concurrent.atomic.AtomicInteger;&nbsp;&nbsp;<br /><br /></span><span style="color: #0000FF; ">public</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">class</span><span style="color: #000000; ">&nbsp;TicketLock&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">private</span><span style="color: #000000; ">&nbsp;AtomicInteger&nbsp;serviceNum&nbsp;</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">new</span><span style="color: #000000; ">&nbsp;AtomicInteger();&nbsp;</span><span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;服务号</span><span style="color: #008000; "><br /></span><span style="color: #000000; ">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">private</span><span style="color: #000000; ">&nbsp;AtomicInteger&nbsp;ticketNum&nbsp;</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">new</span><span style="color: #000000; ">&nbsp;AtomicInteger();&nbsp;</span><span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;排队号</span><span style="color: #008000; "><br /></span><span style="color: #000000; ">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">public</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">int</span><span style="color: #000000; ">&nbsp;lock()&nbsp;{&nbsp;</span><span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;首先原子性地获得一个排队号</span><span style="color: #008000; "><br /></span><span style="color: #000000; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">int</span><span style="color: #000000; ">&nbsp;myTicketNum&nbsp;</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&nbsp;ticketNum.getAndIncrement();&nbsp;</span><span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;只要当前服务号不是自己的就不断轮询</span><span style="color: #008000; "><br /></span><span style="color: #000000; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">while</span><span style="color: #000000; ">&nbsp;(serviceNum.get()&nbsp;</span><span style="color: #000000; ">!=</span><span style="color: #000000; ">&nbsp;myTicketNum)&nbsp;{&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">return</span><span style="color: #000000; ">&nbsp;myTicketNum;<br />&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">public</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">void</span><span style="color: #000000; ">&nbsp;unlock(</span><span style="color: #0000FF; ">int</span><span style="color: #000000; ">&nbsp;myTicket)&nbsp;{&nbsp;</span><span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;只有当前线程拥有者才能释放锁</span><span style="color: #008000; "><br /></span><span style="color: #000000; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">int</span><span style="color: #000000; ">&nbsp;next&nbsp;</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&nbsp;myTicket&nbsp;</span><span style="color: #000000; ">+</span><span style="color: #000000; ">&nbsp;</span><span style="color: #000000; ">1</span><span style="color: #000000; ">;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;serviceNum.compareAndSet(myTicket,&nbsp;next);<br />&nbsp;&nbsp;&nbsp;&nbsp;}<br />}</span></div><h4>缺点</h4><p style="margin: 0px 0px 1.714285714rem; padding: 0px; border: 0px; vertical-align: baseline; line-height: 24px; color: #444444; font-family: 'Open Sans', Helvetica, Arial, sans-serif; background-color: #ffffff;">Ticket Lock 虽然解决了公平性的问题，但是多处理器系统上，每个进程/线程占用的处理器都在读写同一个变量serviceNum ，每次读写操作都必须在多个处理器缓存之间进行缓存同步，这会导致繁重的系统总线和内存的流量，大大降低系统整体的性能。</p><p style="margin: 0px 0px 1.714285714rem; padding: 0px; border: 0px; vertical-align: baseline; line-height: 24px; color: #444444; font-family: 'Open Sans', Helvetica, Arial, sans-serif; background-color: #ffffff;">下面介绍的CLH锁和MCS锁都是为了解决这个问题的。</p><p style="margin: 0px 0px 1.714285714rem; padding: 0px; border: 0px; vertical-align: baseline; line-height: 24px; color: #444444; font-family: 'Open Sans', Helvetica, Arial, sans-serif; background-color: #ffffff;">MCS 来自于其发明人名字的首字母： John Mellor-Crummey和Michael Scott。</p><p style="margin: 0px 0px 1.714285714rem; padding: 0px; border: 0px; vertical-align: baseline; line-height: 24px; color: #444444; font-family: 'Open Sans', Helvetica, Arial, sans-serif; background-color: #ffffff;">CLH的发明人是：Craig，Landin and Hagersten。</p><h3>MCS锁</h3><p style="margin: 0px 0px 1.714285714rem; padding: 0px; border: 0px; vertical-align: baseline; line-height: 24px; color: #444444; font-family: 'Open Sans', Helvetica, Arial, sans-serif; background-color: #ffffff;">MCS Spinlock 是一种基于链表的可扩展、高性能、公平的自旋锁，申请线程只在本地变量上自旋，直接前驱负责通知其结束自旋，从而极大地减少了不必要的处理器缓存同步的次数，降低了总线和内存的开销。</p><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #0000FF; ">import</span><span style="color: #000000; ">&nbsp;java.util.concurrent.atomic.AtomicReferenceFieldUpdater;<br /><br /></span><span style="color: #0000FF; ">public</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">class</span><span style="color: #000000; ">&nbsp;MCSLock&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">public</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">static</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">class</span><span style="color: #000000; ">&nbsp;MCSNode&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">volatile</span><span style="color: #000000; ">&nbsp;MCSNode&nbsp;next;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">volatile</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">boolean</span><span style="color: #000000; ">&nbsp;isBlock&nbsp;</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">true</span><span style="color: #000000; ">;&nbsp;</span><span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;默认是在等待锁</span><span style="color: #008000; "><br /></span><span style="color: #000000; ">&nbsp;&nbsp;&nbsp;&nbsp;}<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">volatile</span><span style="color: #000000; ">&nbsp;MCSNode&nbsp;queue;</span><span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;指向最后一个申请锁的MCSNode</span><span style="color: #008000; "><br /></span><span style="color: #000000; ">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">private</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">static</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">final</span><span style="color: #000000; ">&nbsp;AtomicReferenceFieldUpdater&nbsp;UPDATER&nbsp;</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&nbsp;AtomicReferenceFieldUpdater<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.newUpdater(MCSLock.</span><span style="color: #0000FF; ">class</span><span style="color: #000000; ">,&nbsp;MCSNode.</span><span style="color: #0000FF; ">class</span><span style="color: #000000; ">,&nbsp;</span><span style="color: #000000; ">"</span><span style="color: #000000; ">queue</span><span style="color: #000000; ">"</span><span style="color: #000000; ">);<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">public</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">void</span><span style="color: #000000; ">&nbsp;lock(MCSNode&nbsp;currentThread)&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;MCSNode&nbsp;predecessor&nbsp;</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&nbsp;UPDATER.getAndSet(</span><span style="color: #0000FF; ">this</span><span style="color: #000000; ">,&nbsp;currentThread);</span><span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;step&nbsp;1</span><span style="color: #008000; "><br /></span><span style="color: #000000; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">if</span><span style="color: #000000; ">&nbsp;(predecessor&nbsp;</span><span style="color: #000000; ">!=</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">null</span><span style="color: #000000; ">)&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;predecessor.next&nbsp;</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&nbsp;currentThread;</span><span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;step&nbsp;2</span><span style="color: #008000; "><br /></span><span style="color: #000000; "><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">while</span><span style="color: #000000; ">&nbsp;(currentThread.isBlock)&nbsp;{</span><span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;step&nbsp;3</span><span style="color: #008000; "><br /></span><span style="color: #000000; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;}<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">public</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">void</span><span style="color: #000000; ">&nbsp;unlock(MCSNode&nbsp;currentThread)&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">if</span><span style="color: #000000; ">&nbsp;(currentThread.isBlock)&nbsp;{</span><span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;锁拥有者进行释放锁才有意义</span><span style="color: #008000; "><br /></span><span style="color: #000000; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">return</span><span style="color: #000000; ">;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">if</span><span style="color: #000000; ">&nbsp;(currentThread.next&nbsp;</span><span style="color: #000000; ">==</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">null</span><span style="color: #000000; ">)&nbsp;{</span><span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;检查是否有人排在自己后面</span><span style="color: #008000; "><br /></span><span style="color: #000000; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">if</span><span style="color: #000000; ">&nbsp;(UPDATER.compareAndSet(</span><span style="color: #0000FF; ">this</span><span style="color: #000000; ">,&nbsp;currentThread,&nbsp;</span><span style="color: #0000FF; ">null</span><span style="color: #000000; ">))&nbsp;{</span><span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;step&nbsp;4<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;compareAndSet返回true表示确实没有人排在自己后面</span><span style="color: #008000; "><br /></span><span style="color: #000000; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">return</span><span style="color: #000000; ">;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;</span><span style="color: #0000FF; ">else</span><span style="color: #000000; ">&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;突然有人排在自己后面了，可能还不知道是谁，下面是等待后续者<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;这里之所以要忙等是因为：step&nbsp;1执行完后，step&nbsp;2可能还没执行完</span><span style="color: #008000; "><br /></span><span style="color: #000000; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">while</span><span style="color: #000000; ">&nbsp;(currentThread.next&nbsp;</span><span style="color: #000000; ">==</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">null</span><span style="color: #000000; ">)&nbsp;{&nbsp;</span><span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;step&nbsp;5</span><span style="color: #008000; "><br /></span><span style="color: #000000; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;currentThread.next.isBlock&nbsp;</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">false</span><span style="color: #000000; ">;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;currentThread.next&nbsp;</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">null</span><span style="color: #000000; ">;</span><span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;for&nbsp;GC</span><span style="color: #008000; "><br /></span><span style="color: #000000; ">&nbsp;&nbsp;&nbsp;&nbsp;}<br />}</span></div><h3>CLH锁</h3><p style="margin: 0px 0px 1.714285714rem; padding: 0px; border: 0px; vertical-align: baseline; line-height: 24px; color: #444444; font-family: 'Open Sans', Helvetica, Arial, sans-serif; background-color: #ffffff;">CLH锁也是一种基于链表的可扩展、高性能、公平的自旋锁，申请线程只在本地变量上自旋，它不断轮询前驱的状态，如果发现前驱释放了锁就结束自旋。<br /></p><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #0000FF; ">import</span><span style="color: #000000; ">&nbsp;java.util.concurrent.atomic.AtomicReferenceFieldUpdater;<br /><br /></span><span style="color: #0000FF; ">public</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">class</span><span style="color: #000000; ">&nbsp;CLHLock&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">public</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">static</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">class</span><span style="color: #000000; ">&nbsp;CLHNode&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">private</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">boolean</span><span style="color: #000000; ">&nbsp;isLocked&nbsp;</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">true</span><span style="color: #000000; ">;&nbsp;</span><span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;默认是在等待锁</span><span style="color: #008000; "><br /></span><span style="color: #000000; ">&nbsp;&nbsp;&nbsp;&nbsp;}<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;@SuppressWarnings(</span><span style="color: #000000; ">"</span><span style="color: #000000; ">unused</span><span style="color: #000000; ">"</span><span style="color: #000000; ">&nbsp;)<br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">private</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">volatile</span><span style="color: #000000; ">&nbsp;CLHNode&nbsp;tail&nbsp;;<br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">private</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">static</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">final</span><span style="color: #000000; ">&nbsp;AtomicReferenceFieldUpdater</span><span style="color: #000000; ">&lt;</span><span style="color: #000000; ">CLHLock,&nbsp;CLHNode</span><span style="color: #000000; ">&gt;</span><span style="color: #000000; ">&nbsp;UPDATER&nbsp;</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&nbsp;AtomicReferenceFieldUpdater<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.&nbsp;newUpdater(CLHLock.</span><span style="color: #0000FF; ">class</span><span style="color: #000000; ">,&nbsp;CLHNode&nbsp;.</span><span style="color: #0000FF; ">class</span><span style="color: #000000; ">&nbsp;,&nbsp;</span><span style="color: #000000; ">"</span><span style="color: #000000; ">tail</span><span style="color: #000000; ">"</span><span style="color: #000000; ">&nbsp;);<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">public</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">void</span><span style="color: #000000; ">&nbsp;lock(CLHNode&nbsp;currentThread)&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;CLHNode&nbsp;preNode&nbsp;</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&nbsp;UPDATER.getAndSet(&nbsp;</span><span style="color: #0000FF; ">this</span><span style="color: #000000; ">,&nbsp;currentThread);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">if</span><span style="color: #000000; ">(preNode&nbsp;</span><span style="color: #000000; ">!=</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">null</span><span style="color: #000000; ">)&nbsp;{</span><span style="color: #008000; ">//</span><span style="color: #008000; ">已有线程占用了锁，进入自旋</span><span style="color: #008000; "><br /></span><span style="color: #000000; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">while</span><span style="color: #000000; ">(preNode.isLocked&nbsp;)&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;}<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">public</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">void</span><span style="color: #000000; ">&nbsp;unlock(CLHNode&nbsp;currentThread)&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;如果队列里只有当前线程，则释放对当前线程的引用（for&nbsp;GC）。</span><span style="color: #008000; "><br /></span><span style="color: #000000; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">if</span><span style="color: #000000; ">&nbsp;(</span><span style="color: #000000; ">!</span><span style="color: #000000; ">UPDATER&nbsp;.compareAndSet(</span><span style="color: #0000FF; ">this</span><span style="color: #000000; ">,&nbsp;currentThread,&nbsp;</span><span style="color: #0000FF; ">null</span><span style="color: #000000; ">))&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;还有后续线程</span><span style="color: #008000; "><br /></span><span style="color: #000000; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;currentThread.&nbsp;isLocked&nbsp;</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">false</span><span style="color: #000000; ">&nbsp;;</span><span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;改变状态，让后续线程结束自旋</span><span style="color: #008000; "><br /></span><span style="color: #000000; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;}<br />}</span></div><p style="margin: 0px 0px 1.714285714rem; padding: 0px; border: 0px; vertical-align: baseline; line-height: 24px; color: #444444; font-family: 'Open Sans', Helvetica, Arial, sans-serif; background-color: #ffffff;"><br /></p><h3>CLH锁 与 MCS锁 的比较</h3><p style="margin: 0px 0px 1.714285714rem; padding: 0px; border: 0px; vertical-align: baseline; line-height: 24px; color: #444444; font-family: 'Open Sans', Helvetica, Arial, sans-serif; background-color: #ffffff;">下图是CLH锁和MCS锁队列图示：<br /><img src="http://coderbee.net/wp-content/uploads/2013/11/CLH-MCS-SpinLock.png" alt="CLH-MCS-SpinLock" style="margin: 0px; padding: 0px; border: 0px; vertical-align: baseline; max-width: 100%; border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; box-shadow: rgba(0, 0, 0, 0.2) 0px 1px 4px;" /></p><p style="margin: 0px 0px 1.714285714rem; padding: 0px; border: 0px; vertical-align: baseline; line-height: 24px; color: #444444; font-family: 'Open Sans', Helvetica, Arial, sans-serif; background-color: #ffffff;">差异：</p><ol style="margin: 0px 0px 1.714285714rem; padding: 0px; border: 0px; vertical-align: baseline; list-style-position: outside; list-style-image: initial; line-height: 24px; color: #444444; font-family: 'Open Sans', Helvetica, Arial, sans-serif; background-color: #ffffff;"><li style="margin: 0px 0px 0px 2.571428571rem; padding: 0px; border: 0px; vertical-align: baseline;">从代码实现来看，CLH比MCS要简单得多。</li><li style="margin: 0px 0px 0px 2.571428571rem; padding: 0px; border: 0px; vertical-align: baseline;">从自旋的条件来看，CLH是在本地变量上自旋，MCS是自旋在其他对象的属性。</li><li style="margin: 0px 0px 0px 2.571428571rem; padding: 0px; border: 0px; vertical-align: baseline;">从链表队列来看，CLH的队列是隐式的，CLHNode并不实际持有下一个节点；MCS的队列是物理存在的。</li><li style="margin: 0px 0px 0px 2.571428571rem; padding: 0px; border: 0px; vertical-align: baseline;">CLH锁释放时只需要改变自己的属性，MCS锁释放则需要改变后继节点的属性。</li></ol><p style="margin: 0px 0px 1.714285714rem; padding: 0px; border: 0px; vertical-align: baseline; line-height: 24px; color: #444444; font-family: 'Open Sans', Helvetica, Arial, sans-serif; background-color: #ffffff;"><strong style="margin: 0px; padding: 0px; border: 0px; vertical-align: baseline;">注意：这里实现的锁都是独占的，且不能重入的。</strong></p><img src ="http://www.blogjava.net/DLevin/aggbug/416102.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/DLevin/" target="_blank">DLevin</a> 2015-08-07 00:18 <a href="http://www.blogjava.net/DLevin/archive/2015/08/07/416102.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[转]并发(Concurrent)与并行(Parallel)的区别</title><link>http://www.blogjava.net/DLevin/archive/2015/07/28/426471.html</link><dc:creator>DLevin</dc:creator><author>DLevin</author><pubDate>Tue, 28 Jul 2015 15:43:00 GMT</pubDate><guid>http://www.blogjava.net/DLevin/archive/2015/07/28/426471.html</guid><wfw:comment>http://www.blogjava.net/DLevin/comments/426471.html</wfw:comment><comments>http://www.blogjava.net/DLevin/archive/2015/07/28/426471.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/DLevin/comments/commentRss/426471.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/DLevin/services/trackbacks/426471.html</trackback:ping><description><![CDATA[<p>看到一篇非常简洁的解释并发（Concurrent）与并行（Parallel）的区别的文章，纪录一下，以供参考。原文出自：<strong><a href="http://joearms.github.io/2013/04/05/concurrent-and-parallel-programming.html">http://joearms.github.io/2013/04/05/concurrent-and-parallel-programming.html</a><br /><br /></strong></p><p style="margin: 0px 0px 10px; text-align: justify; color: #555555; font-family: 'Open Sans', Calibri, Candara, Arial, sans-serif; line-height: 20px; background-color: #ffffff;">What&#8217;s the difference between concurrency and parallelism?</p><p style="margin: 0px 0px 10px; text-align: justify; color: #555555; font-family: 'Open Sans', Calibri, Candara, Arial, sans-serif; line-height: 20px; background-color: #ffffff;">Explain it to a five year old.</p><p><strong><img src="http://www.blogjava.net/images/blogjava_net/dlevin/con_and_par.jpg" width="600" height="451" alt="" /><br /></strong></p><p style="margin: 0px 0px 10px; text-align: justify; color: #555555; font-family: 'Open Sans', Calibri, Candara, Arial, sans-serif; line-height: 20px; background-color: #ffffff;"><strong>Concurrent</strong>&nbsp;= Two queues and one coffee machine.</p><p style="margin: 0px 0px 10px; text-align: justify; color: #555555; font-family: 'Open Sans', Calibri, Candara, Arial, sans-serif; line-height: 20px; background-color: #ffffff;"><strong>Parallel</strong>&nbsp;= Two queues and two coffee machines.</p><p><strong><br /></strong></p><img src ="http://www.blogjava.net/DLevin/aggbug/426471.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/DLevin/" target="_blank">DLevin</a> 2015-07-28 23:43 <a href="http://www.blogjava.net/DLevin/archive/2015/07/28/426471.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[转]深入JVM锁机制2-Lock</title><link>http://www.blogjava.net/DLevin/archive/2014/07/22/416101.html</link><dc:creator>DLevin</dc:creator><author>DLevin</author><pubDate>Tue, 22 Jul 2014 13:46:00 GMT</pubDate><guid>http://www.blogjava.net/DLevin/archive/2014/07/22/416101.html</guid><wfw:comment>http://www.blogjava.net/DLevin/comments/416101.html</wfw:comment><comments>http://www.blogjava.net/DLevin/archive/2014/07/22/416101.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/DLevin/comments/commentRss/416101.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/DLevin/services/trackbacks/416101.html</trackback:ping><description><![CDATA[转自：http://blog.csdn.net/chen77716/article/details/6641477<br /><br /><p style="margin: 0px; padding: 0px; font-family: Arial; line-height: 26px; background-color: #ffffff;">前文（<a href="http://blog.csdn.net/chen77716/article/details/6618779" style="color: #ca0000; text-decoration: none;">深入JVM锁机制-synchronized</a>）分析了JVM中的synchronized实现，本文继续分析JVM中的另一种锁Lock的实现。与synchronized不同的是，Lock完全用Java写成，在java这个层面是无关JVM实现的。</p><p style="margin: 0px; padding: 0px; font-family: Arial; line-height: 26px; background-color: #ffffff;">在java.util.concurrent.locks包中有很多Lock的实现类，常用的有ReentrantLock、ReadWriteLock（实现类ReentrantReadWriteLock），其实现都依赖java.util.concurrent.AbstractQueuedSynchronizer类，实现思路都大同小异，因此我们以ReentrantLock作为讲解切入点。</p><h3><a name="t0" style="color: rgb(202, 0, 0);"></a>1. ReentrantLock的调用过程</h3><p style="margin: 0px; padding: 0px; font-family: Arial; line-height: 26px; background-color: #ffffff;">经过观察ReentrantLock把所有Lock接口的操作都委派到一个Sync类上，该类继承了AbstractQueuedSynchronizer：</p><div bg_java"="" style="width: 936.53125px; line-height: 26px;"><div><div><strong>[java]</strong>&nbsp;<a href="http://blog.csdn.net/chen77716/article/details/6641477#" title="view plain" style="padding: 1px; display: inline-block; width: 16px; height: 16px; text-indent: -2000px; background-image: url(http://static.blog.csdn.net/scripts/SyntaxHighlighter/styles/images/default/ico_plain.gif); background-position: 0% 0%; background-repeat: no-repeat;">view plain</a><a href="http://blog.csdn.net/chen77716/article/details/6641477#" title="copy" style="padding: 1px; display: inline-block; width: 16px; height: 16px; text-indent: -2000px; background-image: url(http://static.blog.csdn.net/scripts/SyntaxHighlighter/styles/images/default/ico_copy.gif); background-position: 0% 0%; background-repeat: no-repeat;">copy</a><div style="position: absolute; left: 485px; top: 657px; width: 18px; height: 18px; z-index: 99;"></div></div></div><ol start="1"><li style="line-height: 18px;">static&nbsp;abstract&nbsp;class&nbsp;Sync&nbsp;extends&nbsp;AbstractQueuedSynchronizer&nbsp;&nbsp;</li></ol></div><p style="margin: 0px; padding: 0px; font-family: Arial; line-height: 26px; background-color: #ffffff;">Sync又有两个子类：</p><div bg_java"="" style="width: 936.53125px; line-height: 26px;"><div><div><strong>[java]</strong>&nbsp;<a href="http://blog.csdn.net/chen77716/article/details/6641477#" title="view plain" style="padding: 1px; display: inline-block; width: 16px; height: 16px; text-indent: -2000px; background-image: url(http://static.blog.csdn.net/scripts/SyntaxHighlighter/styles/images/default/ico_plain.gif); background-position: 0% 0%; background-repeat: no-repeat;">view plain</a><a href="http://blog.csdn.net/chen77716/article/details/6641477#" title="copy" style="padding: 1px; display: inline-block; width: 16px; height: 16px; text-indent: -2000px; background-image: url(http://static.blog.csdn.net/scripts/SyntaxHighlighter/styles/images/default/ico_copy.gif); background-position: 0% 0%; background-repeat: no-repeat;">copy</a><div style="position: absolute; left: 485px; top: 770px; width: 18px; height: 18px; z-index: 99;"></div></div></div><ol start="1"><li style="line-height: 18px;">final&nbsp;static&nbsp;class&nbsp;NonfairSync&nbsp;extends&nbsp;Sync&nbsp;&nbsp;</li></ol></div><div bg_java"="" style="width: 936.53125px; line-height: 26px;"><div><div><strong>[java]</strong>&nbsp;<a href="http://blog.csdn.net/chen77716/article/details/6641477#" title="view plain" style="padding: 1px; display: inline-block; width: 16px; height: 16px; text-indent: -2000px; background-image: url(http://static.blog.csdn.net/scripts/SyntaxHighlighter/styles/images/default/ico_plain.gif); background-position: 0% 0%; background-repeat: no-repeat;">view plain</a><a href="http://blog.csdn.net/chen77716/article/details/6641477#" title="copy" style="padding: 1px; display: inline-block; width: 16px; height: 16px; text-indent: -2000px; background-image: url(http://static.blog.csdn.net/scripts/SyntaxHighlighter/styles/images/default/ico_copy.gif); background-position: 0% 0%; background-repeat: no-repeat;">copy</a><div style="position: absolute; left: 485px; top: 839px; width: 18px; height: 18px; z-index: 99;"></div></div></div><ol start="1"><li style="line-height: 18px;">final&nbsp;static&nbsp;class&nbsp;FairSync&nbsp;extends&nbsp;Sync&nbsp;&nbsp;</li></ol></div><p style="margin: 0px; padding: 0px; font-family: Arial; line-height: 26px; background-color: #ffffff;">显然是为了支持公平锁和非公平锁而定义，默认情况下为非公平锁。</p><p style="margin: 0px; padding: 0px; font-family: Arial; line-height: 26px; background-color: #ffffff;">先理一下Reentrant.lock()方法的调用过程（默认非公平锁）：</p><p style="margin: 0px; padding: 0px; font-family: Arial; line-height: 26px; background-color: #ffffff;"><img alt="" src="http://hi.csdn.net/attachment/201107/29/0_13119022769n5R.gif" style="border: none; max-width: 100%;" /></p><p style="margin: 0px; padding: 0px; font-family: Arial; line-height: 26px; background-color: #ffffff;">这些讨厌的Template模式导致很难直观的看到整个调用过程，其实通过上面调用过程及AbstractQueuedSynchronizer的注释可以发现，AbstractQueuedSynchronizer中抽象了绝大多数Lock的功能，而只把tryAcquire方法延迟到子类中实现。tryAcquire方法的语义在于用具体子类判断请求线程是否可以获得锁，无论成功与否AbstractQueuedSynchronizer都将处理后面的流程。</p><h3><a name="t1" style="color: rgb(202, 0, 0);"></a>2.&nbsp;锁实现（加锁）</h3><p style="margin: 0px; padding: 0px; font-family: Arial; line-height: 26px; background-color: #ffffff;">简单说来，AbstractQueuedSynchronizer会把所有的请求线程构成一个CLH队列，当一个线程执行完毕（lock.unlock()）时会激活自己的后继节点，但正在执行的线程并不在队列中，而那些等待执行的线程全部处于阻塞状态，经过调查线程的显式阻塞是通过调用LockSupport.park()完成，而LockSupport.park()则调用sun.misc.Unsafe.park()本地方法，再进一步，HotSpot在Linux中中通过调用pthread_mutex_lock函数把线程交给系统内核进行阻塞。</p><p style="margin: 0px; padding: 0px; font-family: Arial; line-height: 26px; background-color: #ffffff;">该队列如图：</p><p style="margin: 0px; padding: 0px; font-family: Arial; line-height: 26px; background-color: #ffffff;"><img alt="" src="http://hi.csdn.net/attachment/201107/28/0_1311847049xnXb.gif" style="border: none; max-width: 100%;" /></p><p style="margin: 0px; padding: 0px; font-family: Arial; line-height: 26px; background-color: #ffffff;">与synchronized相同的是，这也是一个虚拟队列，不存在队列实例，仅存在节点之间的前后关系。令人疑惑的是为什么采用CLH队列呢？原生的CLH队列是用于自旋锁，但Doug Lea把其改造为阻塞锁。</p><p style="margin: 0px; padding: 0px; font-family: Arial; line-height: 26px; background-color: #ffffff;">当有线程竞争锁时，该线程会首先尝试获得锁，这对于那些已经在队列中排队的线程来说显得不公平，这也是非公平锁的由来，与synchronized实现类似，这样会极大提高吞吐量。</p><p style="margin: 0px; padding: 0px; font-family: Arial; line-height: 26px; background-color: #ffffff;">如果已经存在Running线程，则新的竞争线程会被追加到队尾，具体是采用基于CAS的Lock-Free算法，因为线程并发对Tail调用CAS可能会导致其他线程CAS失败，解决办法是循环CAS直至成功。AbstractQueuedSynchronizer的实现非常精巧，令人叹为观止，不入细节难以完全领会其精髓，下面详细说明实现过程：</p><h4><a name="t2" style="color: rgb(202, 0, 0);"></a>2.1 Sync.nonfairTryAcquire</h4><p style="margin: 0px; padding: 0px; font-family: Arial; line-height: 26px; background-color: #ffffff;">nonfairTryAcquire方法将是lock方法间接调用的第一个方法，每次请求锁时都会首先调用该方法。</p><div bg_java"="" style="width: 936.53125px; line-height: 26px;"><div><div><strong>[java]</strong>&nbsp;<a href="http://blog.csdn.net/chen77716/article/details/6641477#" title="view plain" style="padding: 1px; display: inline-block; width: 16px; height: 16px; text-indent: -2000px; background-image: url(http://static.blog.csdn.net/scripts/SyntaxHighlighter/styles/images/default/ico_plain.gif); background-position: 0% 0%; background-repeat: no-repeat;">view plain</a><a href="http://blog.csdn.net/chen77716/article/details/6641477#" title="copy" style="padding: 1px; display: inline-block; width: 16px; height: 16px; text-indent: -2000px; background-image: url(http://static.blog.csdn.net/scripts/SyntaxHighlighter/styles/images/default/ico_copy.gif); background-position: 0% 0%; background-repeat: no-repeat;">copy</a><div style="position: absolute; left: 485px; top: 2022px; width: 18px; height: 18px; z-index: 99;"></div></div></div><ol start="1"><li style="line-height: 18px;">final&nbsp;boolean&nbsp;nonfairTryAcquire(int&nbsp;acquires)&nbsp;{&nbsp;&nbsp;</li><li style="line-height: 18px;">&nbsp;&nbsp;&nbsp;&nbsp;final&nbsp;Thread&nbsp;current&nbsp;=&nbsp;Thread.currentThread();&nbsp;&nbsp;</li><li style="line-height: 18px;">&nbsp;&nbsp;&nbsp;&nbsp;int&nbsp;c&nbsp;=&nbsp;getState();&nbsp;&nbsp;</li><li style="line-height: 18px;">&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(c&nbsp;==&nbsp;<span style="color: #c00000;">0</span>)&nbsp;{&nbsp;&nbsp;</li><li style="line-height: 18px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(compareAndSetState(<span style="color: #c00000;">0</span>,&nbsp;acquires))&nbsp;{&nbsp;&nbsp;</li><li style="line-height: 18px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;setExclusiveOwnerThread(current);&nbsp;&nbsp;</li><li style="line-height: 18px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;true;&nbsp;&nbsp;</li><li style="line-height: 18px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</li><li style="line-height: 18px;">&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</li><li style="line-height: 18px;">&nbsp;&nbsp;&nbsp;&nbsp;else&nbsp;if&nbsp;(current&nbsp;==&nbsp;getExclusiveOwnerThread())&nbsp;{&nbsp;&nbsp;</li><li style="line-height: 18px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;int&nbsp;nextc&nbsp;=&nbsp;c&nbsp;+&nbsp;acquires;&nbsp;&nbsp;</li><li style="line-height: 18px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(nextc&nbsp;&lt;&nbsp;<span style="color: #c00000;">0</span>)&nbsp;//&nbsp;overflow&nbsp;&nbsp;</li><li style="line-height: 18px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;throw&nbsp;new&nbsp;Error("Maximum&nbsp;lock&nbsp;count&nbsp;exceeded");&nbsp;&nbsp;</li><li style="line-height: 18px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;setState(nextc);&nbsp;&nbsp;</li><li style="line-height: 18px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;true;&nbsp;&nbsp;</li><li style="line-height: 18px;">&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</li><li style="line-height: 18px;">&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;false;&nbsp;&nbsp;</li><li style="line-height: 18px;">}&nbsp;&nbsp;</li></ol></div><p style="margin: 0px; padding: 0px; font-family: Arial; line-height: 26px; background-color: #ffffff;">该方法会首先判断当前状态，如果c==0说明没有线程正在竞争该锁，如果不c !=0 说明有线程正拥有了该锁。</p><p style="margin: 0px; padding: 0px; font-family: Arial; line-height: 26px; background-color: #ffffff;">如果发现c==0，则通过CAS设置该状态值为acquires,acquires的初始调用值为1，每次线程重入该锁都会+1，每次unlock都会-1，但为0时释放锁。如果CAS设置成功，则可以预计其他任何线程调用CAS都不会再成功，也就认为当前线程得到了该锁，也作为Running线程，很显然这个Running线程并未进入等待队列。</p><p style="margin: 0px; padding: 0px; font-family: Arial; line-height: 26px; background-color: #ffffff;">如果c !=0 但发现自己已经拥有锁，只是简单地++acquires，并修改status值，但因为没有竞争，所以通过setStatus修改，而非CAS，也就是说这段代码实现了偏向锁的功能，并且实现的非常漂亮。<br /></p><h4><a name="t3" style="color: rgb(202, 0, 0);"></a>2.2 AbstractQueuedSynchronizer.addWaiter</h4><p style="margin: 0px; padding: 0px; font-family: Arial; line-height: 26px; background-color: #ffffff;"></p><p style="margin: 0px; padding: 0px; font-family: Arial; line-height: 26px; background-color: #ffffff;"></p><p style="margin: 0px; padding: 0px; font-family: Arial; line-height: 26px; background-color: #ffffff;"></p><p style="margin: 0px; padding: 0px; font-family: Arial; line-height: 26px; background-color: #ffffff;"></p><p style="margin: 0px; padding: 0px; font-family: Arial; line-height: 26px; background-color: #ffffff;">addWaiter方法负责把当前无法获得锁的线程包装为一个Node添加到队尾：</p><div bg_java"="" style="width: 936.53125px; line-height: 26px;"><div><div><strong>[java]</strong>&nbsp;<a href="http://blog.csdn.net/chen77716/article/details/6641477#" title="view plain" style="padding: 1px; display: inline-block; width: 16px; height: 16px; text-indent: -2000px; background-image: url(http://static.blog.csdn.net/scripts/SyntaxHighlighter/styles/images/default/ico_plain.gif); background-position: 0% 0%; background-repeat: no-repeat;">view plain</a><a href="http://blog.csdn.net/chen77716/article/details/6641477#" title="copy" style="padding: 1px; display: inline-block; width: 16px; height: 16px; text-indent: -2000px; background-image: url(http://static.blog.csdn.net/scripts/SyntaxHighlighter/styles/images/default/ico_copy.gif); background-position: 0% 0%; background-repeat: no-repeat;">copy</a><div style="position: absolute; left: 485px; top: 2623px; width: 18px; height: 18px; z-index: 99;"></div></div></div><ol start="1"><li style="line-height: 18px;">private&nbsp;Node&nbsp;addWaiter(Node&nbsp;mode)&nbsp;{&nbsp;&nbsp;</li><li style="line-height: 18px;">&nbsp;&nbsp;&nbsp;&nbsp;Node&nbsp;node&nbsp;=&nbsp;new&nbsp;Node(Thread.currentThread(),&nbsp;mode);&nbsp;&nbsp;</li><li style="line-height: 18px;">&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;Try&nbsp;the&nbsp;fast&nbsp;path&nbsp;of&nbsp;enq;&nbsp;backup&nbsp;to&nbsp;full&nbsp;enq&nbsp;on&nbsp;failure&nbsp;&nbsp;</li><li style="line-height: 18px;">&nbsp;&nbsp;&nbsp;&nbsp;Node&nbsp;pred&nbsp;=&nbsp;tail;&nbsp;&nbsp;</li><li style="line-height: 18px;">&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(pred&nbsp;!=&nbsp;null)&nbsp;{&nbsp;&nbsp;</li><li style="line-height: 18px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;node.prev&nbsp;=&nbsp;pred;&nbsp;&nbsp;</li><li style="line-height: 18px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(compareAndSetTail(pred,&nbsp;node))&nbsp;{&nbsp;&nbsp;</li><li style="line-height: 18px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pred.next&nbsp;=&nbsp;node;&nbsp;&nbsp;</li><li style="line-height: 18px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;node;&nbsp;&nbsp;</li><li style="line-height: 18px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</li><li style="line-height: 18px;">&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</li><li style="line-height: 18px;">&nbsp;&nbsp;&nbsp;&nbsp;enq(node);&nbsp;&nbsp;</li><li style="line-height: 18px;">&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;node;&nbsp;&nbsp;</li><li style="line-height: 18px;">}&nbsp;&nbsp;</li></ol></div><p style="margin: 0px; padding: 0px; font-family: Arial; line-height: 26px; background-color: #ffffff;">其中参数mode是独占锁还是共享锁，默认为null，独占锁。追加到队尾的动作分两步：</p><ol style="font-family: Arial; line-height: 26px; background-color: #ffffff;"><li>如果当前队尾已经存在(tail!=null)，则使用CAS把当前线程更新为Tail</li><li>如果当前Tail为null或则线程调用CAS设置队尾失败，则通过enq方法继续设置Tail</li></ol><p style="margin: 0px; padding: 0px; font-family: Arial; line-height: 26px; background-color: #ffffff;">下面是enq方法：</p><div bg_java"="" style="width: 936.53125px; line-height: 26px;"><div><div><strong>[java]</strong>&nbsp;<a href="http://blog.csdn.net/chen77716/article/details/6641477#" title="view plain" style="padding: 1px; display: inline-block; width: 16px; height: 16px; text-indent: -2000px; background-image: url(http://static.blog.csdn.net/scripts/SyntaxHighlighter/styles/images/default/ico_plain.gif); background-position: 0% 0%; background-repeat: no-repeat;">view plain</a><a href="http://blog.csdn.net/chen77716/article/details/6641477#" title="copy" style="padding: 1px; display: inline-block; width: 16px; height: 16px; text-indent: -2000px; background-image: url(http://static.blog.csdn.net/scripts/SyntaxHighlighter/styles/images/default/ico_copy.gif); background-position: 0% 0%; background-repeat: no-repeat;">copy</a><div style="position: absolute; left: 485px; top: 3076px; width: 18px; height: 18px; z-index: 99;"></div></div></div><ol start="1"><li style="line-height: 18px;">private&nbsp;Node&nbsp;enq(final&nbsp;Node&nbsp;node)&nbsp;{&nbsp;&nbsp;</li><li style="line-height: 18px;">&nbsp;&nbsp;&nbsp;&nbsp;for&nbsp;(;;)&nbsp;{&nbsp;&nbsp;</li><li style="line-height: 18px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Node&nbsp;t&nbsp;=&nbsp;tail;&nbsp;&nbsp;</li><li style="line-height: 18px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(t&nbsp;==&nbsp;null)&nbsp;{&nbsp;//&nbsp;Must&nbsp;initialize&nbsp;&nbsp;</li><li style="line-height: 18px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Node&nbsp;h&nbsp;=&nbsp;new&nbsp;Node();&nbsp;//&nbsp;Dummy&nbsp;header&nbsp;&nbsp;</li><li style="line-height: 18px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;h.next&nbsp;=&nbsp;node;&nbsp;&nbsp;</li><li style="line-height: 18px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;node.prev&nbsp;=&nbsp;h;&nbsp;&nbsp;</li><li style="line-height: 18px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(compareAndSetHead(h))&nbsp;{&nbsp;&nbsp;</li><li style="line-height: 18px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;tail&nbsp;=&nbsp;node;&nbsp;&nbsp;</li><li style="line-height: 18px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;h;&nbsp;&nbsp;</li><li style="line-height: 18px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</li><li style="line-height: 18px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</li><li style="line-height: 18px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else&nbsp;{&nbsp;&nbsp;</li><li style="line-height: 18px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;node.prev&nbsp;=&nbsp;t;&nbsp;&nbsp;</li><li style="line-height: 18px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(compareAndSetTail(t,&nbsp;node))&nbsp;{&nbsp;&nbsp;</li><li style="line-height: 18px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;t.next&nbsp;=&nbsp;node;&nbsp;&nbsp;</li><li style="line-height: 18px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;t;&nbsp;&nbsp;</li><li style="line-height: 18px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</li><li style="line-height: 18px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</li><li style="line-height: 18px;">&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</li><li style="line-height: 18px;">}&nbsp;&nbsp;</li></ol></div><p style="margin: 0px; padding: 0px; font-family: Arial; line-height: 26px; background-color: #ffffff;"><br />该方法就是循环调用CAS，即使有高并发的场景，无限循环将会最终成功把当前线程追加到队尾（或设置队头）。总而言之，addWaiter的目的就是通过CAS把当前现在追加到队尾，并返回包装后的Node实例。</p><p style="margin: 0px; padding: 0px; font-family: Arial; line-height: 26px; background-color: #ffffff;">把线程要包装为Node对象的主要原因，除了用Node构造供虚拟队列外，还用Node包装了各种线程状态，这些状态被精心设计为一些数字值：</p><ul style="font-family: Arial; line-height: 26px; background-color: #ffffff;"><li>SIGNAL(-1)&nbsp;：线程的后继线程正/已被阻塞，当该线程release或cancel时要重新这个后继线程(unpark)</li><li>CANCELLED(1)：因为超时或中断，该线程已经被取消</li><li>CONDITION(-2)：表明该线程被处于条件队列，就是因为调用了Condition.await而被阻塞</li><li>PROPAGATE(-3)：传播共享锁</li><li>0：0代表无状态</li></ul><h4><a name="t4" style="color: rgb(202, 0, 0);"></a>2.3 AbstractQueuedSynchronizer.acquireQueued</h4><p style="margin: 0px; padding: 0px; font-family: Arial; line-height: 26px; background-color: #ffffff;">acquireQueued的主要作用是把已经追加到队列的线程节点（addWaiter方法返回值）进行阻塞，但阻塞前又通过tryAccquire重试是否能获得锁，如果重试成功能则无需阻塞，直接返回</p><div bg_java"="" style="width: 936.53125px; line-height: 26px;"><div><div><strong>[java]</strong>&nbsp;<a href="http://blog.csdn.net/chen77716/article/details/6641477#" title="view plain" style="padding: 1px; display: inline-block; width: 16px; height: 16px; text-indent: -2000px; background-image: url(http://static.blog.csdn.net/scripts/SyntaxHighlighter/styles/images/default/ico_plain.gif); background-position: 0% 0%; background-repeat: no-repeat;">view plain</a><a href="http://blog.csdn.net/chen77716/article/details/6641477#" title="copy" style="padding: 1px; display: inline-block; width: 16px; height: 16px; text-indent: -2000px; background-image: url(http://static.blog.csdn.net/scripts/SyntaxHighlighter/styles/images/default/ico_copy.gif); background-position: 0% 0%; background-repeat: no-repeat;">copy</a><div style="position: absolute; left: 485px; top: 3863px; width: 18px; height: 18px; z-index: 99;"></div></div></div><ol start="1"><li style="line-height: 18px;">final&nbsp;boolean&nbsp;acquireQueued(final&nbsp;Node&nbsp;node,&nbsp;int&nbsp;arg)&nbsp;{&nbsp;&nbsp;</li><li style="line-height: 18px;">&nbsp;&nbsp;&nbsp;&nbsp;try&nbsp;{&nbsp;&nbsp;</li><li style="line-height: 18px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;boolean&nbsp;interrupted&nbsp;=&nbsp;false;&nbsp;&nbsp;</li><li style="line-height: 18px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;for&nbsp;(;;)&nbsp;{&nbsp;&nbsp;</li><li style="line-height: 18px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;final&nbsp;Node&nbsp;p&nbsp;=&nbsp;node.predecessor();&nbsp;&nbsp;</li><li style="line-height: 18px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(p&nbsp;==&nbsp;head&nbsp;&amp;&amp;&nbsp;tryAcquire(arg))&nbsp;{&nbsp;&nbsp;</li><li style="line-height: 18px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;setHead(node);&nbsp;&nbsp;</li><li style="line-height: 18px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;p.next&nbsp;=&nbsp;null;&nbsp;//&nbsp;help&nbsp;GC&nbsp;&nbsp;</li><li style="line-height: 18px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;interrupted;&nbsp;&nbsp;</li><li style="line-height: 18px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</li><li style="line-height: 18px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(shouldParkAfterFailedAcquire(p,&nbsp;node)&nbsp;&amp;&amp;&nbsp;&nbsp;</li><li style="line-height: 18px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;parkAndCheckInterrupt())&nbsp;&nbsp;</li><li style="line-height: 18px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;interrupted&nbsp;=&nbsp;true;&nbsp;&nbsp;</li><li style="line-height: 18px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</li><li style="line-height: 18px;">&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;catch&nbsp;(RuntimeException&nbsp;ex)&nbsp;{&nbsp;&nbsp;</li><li style="line-height: 18px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cancelAcquire(node);&nbsp;&nbsp;</li><li style="line-height: 18px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;throw&nbsp;ex;&nbsp;&nbsp;</li><li style="line-height: 18px;">&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</li><li style="line-height: 18px;">}&nbsp;&nbsp;</li></ol></div><p style="margin: 0px; padding: 0px; font-family: Arial; line-height: 26px; background-color: #ffffff;"><br />仔细看看这个方法是个无限循环，感觉如果p == head &amp;&amp; tryAcquire(arg)条件不满足循环将永远无法结束，当然不会出现死循环，奥秘在于第12行的parkAndCheckInterrupt会把当前线程挂起，从而阻塞住线程的调用栈。</p><div bg_java"="" style="width: 936.53125px; line-height: 26px;"><div><div><strong>[java]</strong>&nbsp;<a href="http://blog.csdn.net/chen77716/article/details/6641477#" title="view plain" style="padding: 1px; display: inline-block; width: 16px; height: 16px; text-indent: -2000px; background-image: url(http://static.blog.csdn.net/scripts/SyntaxHighlighter/styles/images/default/ico_plain.gif); background-position: 0% 0%; background-repeat: no-repeat;">view plain</a><a href="http://blog.csdn.net/chen77716/article/details/6641477#" title="copy" style="padding: 1px; display: inline-block; width: 16px; height: 16px; text-indent: -2000px; background-image: url(http://static.blog.csdn.net/scripts/SyntaxHighlighter/styles/images/default/ico_copy.gif); background-position: 0% 0%; background-repeat: no-repeat;">copy</a><div style="position: absolute; left: 485px; top: 4352px; width: 18px; height: 18px; z-index: 99;"></div></div></div><ol start="1"><li style="line-height: 18px;">private&nbsp;final&nbsp;boolean&nbsp;parkAndCheckInterrupt()&nbsp;{&nbsp;&nbsp;</li><li style="line-height: 18px;">&nbsp;&nbsp;&nbsp;&nbsp;LockSupport.park(this);&nbsp;&nbsp;</li><li style="line-height: 18px;">&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;Thread.interrupted();&nbsp;&nbsp;</li><li style="line-height: 18px;">}&nbsp;&nbsp;</li></ol></div><p style="margin: 0px; padding: 0px; font-family: Arial; line-height: 26px; background-color: #ffffff;">如前面所述，LockSupport.park最终把线程交给系统（Linux）内核进行阻塞。当然也不是马上把请求不到锁的线程进行阻塞，还要检查该线程的状态，比如如果该线程处于Cancel状态则没有必要，具体的检查在shouldParkAfterFailedAcquire中：</p><div bg_java"="" style="width: 936.53125px; line-height: 26px;"><div><div><strong>[java]</strong>&nbsp;<a href="http://blog.csdn.net/chen77716/article/details/6641477#" title="view plain" style="padding: 1px; display: inline-block; width: 16px; height: 16px; text-indent: -2000px; background-image: url(http://static.blog.csdn.net/scripts/SyntaxHighlighter/styles/images/default/ico_plain.gif); background-position: 0% 0%; background-repeat: no-repeat;">view plain</a><a href="http://blog.csdn.net/chen77716/article/details/6641477#" title="copy" style="padding: 1px; display: inline-block; width: 16px; height: 16px; text-indent: -2000px; background-image: url(http://static.blog.csdn.net/scripts/SyntaxHighlighter/styles/images/default/ico_copy.gif); background-position: 0% 0%; background-repeat: no-repeat;">copy</a><div style="position: absolute; left: 485px; top: 4545px; width: 18px; height: 18px; z-index: 99;"></div></div></div><ol start="1"><li style="line-height: 18px;">&nbsp;&nbsp;private&nbsp;static&nbsp;boolean&nbsp;shouldParkAfterFailedAcquire(Node&nbsp;pred,&nbsp;Node&nbsp;node)&nbsp;{&nbsp;&nbsp;</li><li style="line-height: 18px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;int&nbsp;ws&nbsp;=&nbsp;pred.waitStatus;&nbsp;&nbsp;</li><li style="line-height: 18px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(ws&nbsp;==&nbsp;Node.SIGNAL)&nbsp;&nbsp;</li><li style="line-height: 18px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;/*&nbsp;</li><li style="line-height: 18px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;This&nbsp;node&nbsp;has&nbsp;already&nbsp;set&nbsp;status&nbsp;asking&nbsp;a&nbsp;release&nbsp;</li><li style="line-height: 18px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;to&nbsp;signal&nbsp;it,&nbsp;so&nbsp;it&nbsp;can&nbsp;safely&nbsp;park&nbsp;</li><li style="line-height: 18px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*/&nbsp;&nbsp;</li><li style="line-height: 18px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;true;&nbsp;&nbsp;</li><li style="line-height: 18px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(ws&nbsp;&gt;&nbsp;<span style="color: #c00000;">0</span>)&nbsp;{&nbsp;&nbsp;</li><li style="line-height: 18px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;/*&nbsp;</li><li style="line-height: 18px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;Predecessor&nbsp;was&nbsp;cancelled.&nbsp;Skip&nbsp;over&nbsp;predecessors&nbsp;and&nbsp;</li><li style="line-height: 18px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;indicate&nbsp;retry.&nbsp;</li><li style="line-height: 18px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*/&nbsp;&nbsp;</li><li style="line-height: 18px;">&nbsp;&nbsp;&nbsp;do&nbsp;{&nbsp;&nbsp;</li><li style="line-height: 18px;">node.prev&nbsp;=&nbsp;pred&nbsp;=&nbsp;pred.prev;&nbsp;&nbsp;</li><li style="line-height: 18px;">&nbsp;&nbsp;&nbsp;}&nbsp;while&nbsp;(pred.waitStatus&nbsp;&gt;&nbsp;<span style="color: #c00000;">0</span>);&nbsp;&nbsp;</li><li style="line-height: 18px;">&nbsp;&nbsp;&nbsp;pred.next&nbsp;=&nbsp;node;&nbsp;&nbsp;</li><li style="line-height: 18px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;else&nbsp;{&nbsp;&nbsp;</li><li style="line-height: 18px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;/*&nbsp;</li><li style="line-height: 18px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;waitStatus&nbsp;must&nbsp;be&nbsp;0&nbsp;or&nbsp;PROPAGATE.&nbsp;Indicate&nbsp;that&nbsp;we&nbsp;</li><li style="line-height: 18px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;need&nbsp;a&nbsp;signal,&nbsp;but&nbsp;don't&nbsp;park&nbsp;yet.&nbsp;Caller&nbsp;will&nbsp;need&nbsp;to&nbsp;</li><li style="line-height: 18px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;retry&nbsp;to&nbsp;make&nbsp;sure&nbsp;it&nbsp;cannot&nbsp;acquire&nbsp;before&nbsp;parking.&nbsp;&nbsp;</li><li style="line-height: 18px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*/&nbsp;&nbsp;</li><li style="line-height: 18px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;compareAndSetWaitStatus(pred,&nbsp;ws,&nbsp;Node.SIGNAL);&nbsp;&nbsp;</li><li style="line-height: 18px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;&nbsp;</li><li style="line-height: 18px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;false;&nbsp;&nbsp;</li><li style="line-height: 18px;">&nbsp;&nbsp;}&nbsp;&nbsp;</li></ol></div><p style="margin: 0px; padding: 0px; font-family: Arial; line-height: 26px; background-color: #ffffff;">检查原则在于：</p><ul style="font-family: Arial; line-height: 26px; background-color: #ffffff;"><li>规则1：如果前继的节点状态为SIGNAL，表明当前节点需要unpark，则返回成功，此时acquireQueued方法的第12行（parkAndCheckInterrupt）将导致线程阻塞</li><li>规则2：如果前继节点状态为CANCELLED(ws&gt;0)，说明前置节点已经被放弃，则回溯到一个非取消的前继节点，返回false，acquireQueued方法的无限循环将递归调用该方法，直至规则1返回true，导致线程阻塞</li><li>规则3：如果前继节点状态为非SIGNAL、非CANCELLED，则设置前继的状态为SIGNAL，返回false后进入acquireQueued的无限循环，与规则2同</li></ul><p style="margin: 0px; padding: 0px; font-family: Arial; line-height: 26px; background-color: #ffffff;">总体看来，shouldParkAfterFailedAcquire就是靠前继节点判断当前线程是否应该被阻塞，如果前继节点处于CANCELLED状态，则顺便删除这些节点重新构造队列。</p><p style="margin: 0px; padding: 0px; font-family: Arial; line-height: 26px; background-color: #ffffff;">至此，锁住线程的逻辑已经完成，下面讨论解锁的过程。</p><h3><a name="t5" style="color: rgb(202, 0, 0);"></a>3. 解锁</h3><p style="margin: 0px; padding: 0px; font-family: Arial; line-height: 26px; background-color: #ffffff;">请求锁不成功的线程会被挂起在acquireQueued方法的第12行，12行以后的代码必须等线程被解锁锁才能执行，假如被阻塞的线程得到解锁，则执行第13行，即设置interrupted = true，之后又进入无限循环。</p><p style="margin: 0px; padding: 0px; font-family: Arial; line-height: 26px; background-color: #ffffff;">从无限循环的代码可以看出，并不是得到解锁的线程一定能获得锁，必须在第6行中调用tryAccquire重新竞争，因为锁是非公平的，有可能被新加入的线程获得，从而导致刚被唤醒的线程再次被阻塞，这个细节充分体现了&#8220;非公平&#8221;的精髓。通过之后将要介绍的解锁机制会看到，第一个被解锁的线程就是Head，因此p == head的判断基本都会成功。</p><p style="margin: 0px; padding: 0px; font-family: Arial; line-height: 26px; background-color: #ffffff;">至此可以看到，把tryAcquire方法延迟到子类中实现的做法非常精妙并具有极强的可扩展性，令人叹为观止！当然精妙的不是这个Templae设计模式，而是Doug Lea对锁结构的精心布局。</p><p style="margin: 0px; padding: 0px; font-family: Arial; line-height: 26px; background-color: #ffffff;">解锁代码相对简单，主要体现在AbstractQueuedSynchronizer.release和Sync.tryRelease方法中：</p><p style="margin: 0px; padding: 0px; font-family: Arial; line-height: 26px; background-color: #ffffff;">class AbstractQueuedSynchronizer</p><div bg_java"="" style="width: 936.53125px; line-height: 26px;"><div><div><strong>[java]</strong>&nbsp;<a href="http://blog.csdn.net/chen77716/article/details/6641477#" title="view plain" style="padding: 1px; display: inline-block; width: 16px; height: 16px; text-indent: -2000px; background-image: url(http://static.blog.csdn.net/scripts/SyntaxHighlighter/styles/images/default/ico_plain.gif); background-position: 0% 0%; background-repeat: no-repeat;">view plain</a><a href="http://blog.csdn.net/chen77716/article/details/6641477#" title="copy" style="padding: 1px; display: inline-block; width: 16px; height: 16px; text-indent: -2000px; background-image: url(http://static.blog.csdn.net/scripts/SyntaxHighlighter/styles/images/default/ico_copy.gif); background-position: 0% 0%; background-repeat: no-repeat;">copy</a><div style="position: absolute; left: 485px; top: 5622px; width: 18px; height: 18px; z-index: 99;"></div></div></div><ol start="1"><li style="line-height: 18px;">public&nbsp;final&nbsp;boolean&nbsp;release(int&nbsp;arg)&nbsp;{&nbsp;&nbsp;</li><li style="line-height: 18px;">&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(tryRelease(arg))&nbsp;{&nbsp;&nbsp;</li><li style="line-height: 18px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Node&nbsp;h&nbsp;=&nbsp;head;&nbsp;&nbsp;</li><li style="line-height: 18px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(h&nbsp;!=&nbsp;null&nbsp;&amp;&amp;&nbsp;h.waitStatus&nbsp;!=&nbsp;<span style="color: #c00000;">0</span>)&nbsp;&nbsp;</li><li style="line-height: 18px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;unparkSuccessor(h);&nbsp;&nbsp;</li><li style="line-height: 18px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;true;&nbsp;&nbsp;</li><li style="line-height: 18px;">&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</li><li style="line-height: 18px;">&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;false;&nbsp;&nbsp;</li><li style="line-height: 18px;">}&nbsp;&nbsp;</li></ol></div><p style="margin: 0px; padding: 0px; font-family: Arial; line-height: 26px; background-color: #ffffff;">class Sync</p><div bg_java"="" style="width: 936.53125px; line-height: 26px;"><div><div><strong>[java]</strong>&nbsp;<a href="http://blog.csdn.net/chen77716/article/details/6641477#" title="view plain" style="padding: 1px; display: inline-block; width: 16px; height: 16px; text-indent: -2000px; background-image: url(http://static.blog.csdn.net/scripts/SyntaxHighlighter/styles/images/default/ico_plain.gif); background-position: 0% 0%; background-repeat: no-repeat;">view plain</a><a href="http://blog.csdn.net/chen77716/article/details/6641477#" title="copy" style="padding: 1px; display: inline-block; width: 16px; height: 16px; text-indent: -2000px; background-image: url(http://static.blog.csdn.net/scripts/SyntaxHighlighter/styles/images/default/ico_copy.gif); background-position: 0% 0%; background-repeat: no-repeat;">copy</a><div style="position: absolute; left: 485px; top: 5879px; width: 18px; height: 18px; z-index: 99;"></div></div></div><ol start="1"><li style="line-height: 18px;">protected&nbsp;final&nbsp;boolean&nbsp;tryRelease(int&nbsp;releases)&nbsp;{&nbsp;&nbsp;</li><li style="line-height: 18px;">&nbsp;&nbsp;&nbsp;&nbsp;int&nbsp;c&nbsp;=&nbsp;getState()&nbsp;-&nbsp;releases;&nbsp;&nbsp;</li><li style="line-height: 18px;">&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(Thread.currentThread()&nbsp;!=&nbsp;getExclusiveOwnerThread())&nbsp;&nbsp;</li><li style="line-height: 18px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;throw&nbsp;new&nbsp;IllegalMonitorStateException();&nbsp;&nbsp;</li><li style="line-height: 18px;">&nbsp;&nbsp;&nbsp;&nbsp;boolean&nbsp;free&nbsp;=&nbsp;false;&nbsp;&nbsp;</li><li style="line-height: 18px;">&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(c&nbsp;==&nbsp;<span style="color: #c00000;">0</span>)&nbsp;{&nbsp;&nbsp;</li><li style="line-height: 18px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;free&nbsp;=&nbsp;true;&nbsp;&nbsp;</li><li style="line-height: 18px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;setExclusiveOwnerThread(null);&nbsp;&nbsp;</li><li style="line-height: 18px;">&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</li><li style="line-height: 18px;">&nbsp;&nbsp;&nbsp;&nbsp;setState(c);&nbsp;&nbsp;</li><li style="line-height: 18px;">&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;free;&nbsp;&nbsp;</li><li style="line-height: 18px;">}&nbsp;&nbsp;</li></ol></div><p style="margin: 0px; padding: 0px; font-family: Arial; line-height: 26px; background-color: #ffffff;"><br />tryRelease与tryAcquire语义相同，把如何释放的逻辑延迟到子类中。tryRelease语义很明确：如果线程多次锁定，则进行多次释放，直至status==0则真正释放锁，所谓释放锁即设置status为0，因为无竞争所以没有使用CAS。</p><p style="margin: 0px; padding: 0px; font-family: Arial; line-height: 26px; background-color: #ffffff;">release的语义在于：如果可以释放锁，则唤醒队列第一个线程（Head），具体唤醒代码如下：</p><div bg_java"="" style="width: 936.53125px; line-height: 26px;"><div><div><strong>[java]</strong>&nbsp;<a href="http://blog.csdn.net/chen77716/article/details/6641477#" title="view plain" style="padding: 1px; display: inline-block; width: 16px; height: 16px; text-indent: -2000px; background-image: url(http://static.blog.csdn.net/scripts/SyntaxHighlighter/styles/images/default/ico_plain.gif); background-position: 0% 0%; background-repeat: no-repeat;">view plain</a><a href="http://blog.csdn.net/chen77716/article/details/6641477#" title="copy" style="padding: 1px; display: inline-block; width: 16px; height: 16px; text-indent: -2000px; background-image: url(http://static.blog.csdn.net/scripts/SyntaxHighlighter/styles/images/default/ico_copy.gif); background-position: 0% 0%; background-repeat: no-repeat;">copy</a><div style="position: absolute; left: 485px; top: 6268px; width: 18px; height: 18px; z-index: 99;"></div></div></div><ol start="1"><li style="line-height: 18px;">private&nbsp;void&nbsp;unparkSuccessor(Node&nbsp;node)&nbsp;{&nbsp;&nbsp;</li><li style="line-height: 18px;">&nbsp;&nbsp;&nbsp;&nbsp;/*&nbsp;</li><li style="line-height: 18px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;If&nbsp;status&nbsp;is&nbsp;negative&nbsp;(i.e.,&nbsp;possibly&nbsp;needing&nbsp;signal)&nbsp;try&nbsp;</li><li style="line-height: 18px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;to&nbsp;clear&nbsp;in&nbsp;anticipation&nbsp;of&nbsp;signalling.&nbsp;It&nbsp;is&nbsp;OK&nbsp;if&nbsp;this&nbsp;</li><li style="line-height: 18px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;fails&nbsp;or&nbsp;if&nbsp;status&nbsp;is&nbsp;changed&nbsp;by&nbsp;waiting&nbsp;thread.&nbsp;</li><li style="line-height: 18px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*/&nbsp;&nbsp;</li><li style="line-height: 18px;">&nbsp;&nbsp;&nbsp;&nbsp;int&nbsp;ws&nbsp;=&nbsp;node.waitStatus;&nbsp;&nbsp;</li><li style="line-height: 18px;">&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(ws&nbsp;&lt;&nbsp;<span style="color: #c00000;">0</span>)&nbsp;&nbsp;</li><li style="line-height: 18px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;compareAndSetWaitStatus(node,&nbsp;ws,&nbsp;<span style="color: #c00000;">0</span>);&nbsp;&nbsp;&nbsp;</li><li style="line-height: 18px;">&nbsp;&nbsp;</li><li style="line-height: 18px;">&nbsp;&nbsp;&nbsp;&nbsp;/*&nbsp;</li><li style="line-height: 18px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;Thread&nbsp;to&nbsp;unpark&nbsp;is&nbsp;held&nbsp;in&nbsp;successor,&nbsp;which&nbsp;is&nbsp;normally&nbsp;</li><li style="line-height: 18px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;just&nbsp;the&nbsp;next&nbsp;node.&nbsp;&nbsp;But&nbsp;if&nbsp;cancelled&nbsp;or&nbsp;apparently&nbsp;null,&nbsp;</li><li style="line-height: 18px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;traverse&nbsp;backwards&nbsp;from&nbsp;tail&nbsp;to&nbsp;find&nbsp;the&nbsp;actual&nbsp;</li><li style="line-height: 18px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;non-cancelled&nbsp;successor.&nbsp;</li><li style="line-height: 18px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*/&nbsp;&nbsp;</li><li style="line-height: 18px;">&nbsp;&nbsp;&nbsp;&nbsp;Node&nbsp;s&nbsp;=&nbsp;node.next;&nbsp;&nbsp;</li><li style="line-height: 18px;">&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(s&nbsp;==&nbsp;null&nbsp;||&nbsp;s.waitStatus&nbsp;&gt;&nbsp;<span style="color: #c00000;">0</span>)&nbsp;{&nbsp;&nbsp;</li><li style="line-height: 18px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;s&nbsp;=&nbsp;null;&nbsp;&nbsp;</li><li style="line-height: 18px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;for&nbsp;(Node&nbsp;t&nbsp;=&nbsp;tail;&nbsp;t&nbsp;!=&nbsp;null&nbsp;&amp;&amp;&nbsp;t&nbsp;!=&nbsp;node;&nbsp;t&nbsp;=&nbsp;t.prev)&nbsp;&nbsp;</li><li style="line-height: 18px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(t.waitStatus&nbsp;&lt;=&nbsp;<span style="color: #c00000;">0</span>)&nbsp;&nbsp;</li><li style="line-height: 18px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;s&nbsp;=&nbsp;t;&nbsp;&nbsp;</li><li style="line-height: 18px;">&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</li><li style="line-height: 18px;">&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(s&nbsp;!=&nbsp;null)&nbsp;&nbsp;</li><li style="line-height: 18px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;LockSupport.unpark(s.thread);&nbsp;&nbsp;</li><li style="line-height: 18px;">}&nbsp;&nbsp;</li></ol></div><p style="margin: 0px; padding: 0px; font-family: Arial; line-height: 26px; background-color: #ffffff;"><br />这段代码的意思在于找出第一个可以unpark的线程，一般说来head.next == head，Head就是第一个线程，但Head.next可能被取消或被置为null，因此比较稳妥的办法是从后往前找第一个可用线程。貌似回溯会导致性能降低，其实这个发生的几率很小，所以不会有性能影响。之后便是通知系统内核继续该线程，在Linux下是通过pthread_mutex_unlock完成。之后，被解锁的线程进入上面所说的重新竞争状态。</p><h3><a name="t6" style="color: rgb(202, 0, 0);"></a>4. Lock VS Synchronized</h3><p style="margin: 0px; padding: 0px; font-family: Arial; line-height: 26px; background-color: #ffffff;">AbstractQueuedSynchronizer通过构造一个基于阻塞的CLH队列容纳所有的阻塞线程，而对该队列的操作均通过Lock-Free（CAS）操作，但对已经获得锁的线程而言，ReentrantLock实现了偏向锁的功能。</p><p style="margin: 0px; padding: 0px; font-family: Arial; line-height: 26px; background-color: #ffffff;">synchronized的底层也是一个基于CAS操作的等待队列，但JVM实现的更精细，把等待队列分为ContentionList和EntryList，目的是为了降低线程的出列速度；当然也实现了偏向锁，从数据结构来说二者设计没有本质区别。但synchronized还实现了自旋锁，并针对不同的系统和硬件体系进行了优化，而Lock则完全依靠系统阻塞挂起等待线程。</p><p style="margin: 0px; padding: 0px; font-family: Arial; line-height: 26px; background-color: #ffffff;">当然Lock比synchronized更适合在应用层扩展，可以继承AbstractQueuedSynchronizer定义各种实现，比如实现读写锁（ReadWriteLock），公平或不公平锁；同时，Lock对应的Condition也比wait/notify要方便的多、灵活的多。</p><img src ="http://www.blogjava.net/DLevin/aggbug/416101.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/DLevin/" target="_blank">DLevin</a> 2014-07-22 21:46 <a href="http://www.blogjava.net/DLevin/archive/2014/07/22/416101.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[转]深入JVM锁机制1-synchronized</title><link>http://www.blogjava.net/DLevin/archive/2014/07/22/416100.html</link><dc:creator>DLevin</dc:creator><author>DLevin</author><pubDate>Tue, 22 Jul 2014 13:38:00 GMT</pubDate><guid>http://www.blogjava.net/DLevin/archive/2014/07/22/416100.html</guid><wfw:comment>http://www.blogjava.net/DLevin/comments/416100.html</wfw:comment><comments>http://www.blogjava.net/DLevin/archive/2014/07/22/416100.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/DLevin/comments/commentRss/416100.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/DLevin/services/trackbacks/416100.html</trackback:ping><description><![CDATA[转自：http://blog.csdn.net/chen77716/article/details/6618779<br /><br /><p style="margin: 0px; padding: 0px; font-family: Arial; line-height: 26px; background-color: #ffffff;">&nbsp; &nbsp;目前在Java中存在两种锁机制：synchronized和Lock，Lock接口及其实现类是JDK5增加的内容，其作者是大名鼎鼎的并发专家Doug Lea。本文并不比较synchronized与Lock孰优孰劣，只是介绍二者的实现原理。</p><div style="font-family: Arial; line-height: 26px; background-color: #ffffff;"><p style="margin: 4px 0px; padding: 2px 0px;">&nbsp; &nbsp;数据同步需要依赖锁，那锁的同步又依赖谁？synchronized给出的答案是在软件层面依赖JVM，而Lock给出的方案是在硬件层面依赖特殊的CPU指令，大家可能会进一步追问：JVM底层又是如何实现synchronized的？</p><p style="margin: 4px 0px; padding: 2px 0px;">&nbsp; &nbsp;本文所指说的JVM是指Hotspot的6u23版本，下面首先介绍synchronized的实现：</p><span style="padding: 2px 0px; margin: 4px 0px;">&nbsp; &nbsp;synrhronized关键字简洁、清晰、语义明确，因此即使有了Lock接口，使用的还是非常广泛。其应用层的语义是可以把任何一个非null对象作为"锁"，当synchronized作用在方法上时，锁住的便是对象实例（this）；当作用在静态方法时锁住的便是对象对应的Class实例，因为Class数据存在于永久带，因此静态方法锁相当于该类的一个全局锁；当synchronized作用于某一个对象实例时，锁住的便是对应的代码块。在HotSpot JVM实现中，锁有个专门的名字：对象监视器。</span><h3><a name="t0" style="color: rgb(202, 0, 0);"></a>&nbsp; 1. 线程状态及状态转换</h3><p style="margin: 4px 0px; padding: 2px 0px;">&nbsp; &nbsp; 当多个线程同时请求某个对象监视器时，对象监视器会设置几种状态用来区分请求的线程：</p><p style="margin: 4px 0px; padding: 2px 0px;"></p><ul><li>Contention List：所有请求锁的线程将被首先放置到该竞争队列</li><li>Entry List：Contention List中那些有资格成为候选人的线程被移到Entry List</li><li>Wait Set：那些调用wait方法被阻塞的线程被放置到Wait Set</li><li>OnDeck：任何时刻最多只能有一个线程正在竞争锁，该线程称为OnDeck</li><li>Owner：获得锁的线程称为Owner</li><li>!Owner：释放锁的线程</li></ul><div>下图反映了个状态转换关系：</div><div><img alt="" src="http://hi.csdn.net/attachment/201107/28/0_1311821841e55M.gif" style="border: none; max-width: 100%;" /></div><div>新请求锁的线程将首先被加入到ConetentionList中，当某个拥有锁的线程（Owner状态）调用unlock之后，如果发现EntryList为空则从ContentionList中移动线程到EntryList，下面说明下ContentionList和EntryList的实现方式：</div><h4><a name="t1" style="color: rgb(202, 0, 0);"></a>1.1 ContentionList虚拟队列</h4><p style="margin: 0px; padding: 0px;">ContentionList并不是一个真正的Queue，而只是一个虚拟队列，原因在于ContentionList是由Node及其next指针逻辑构成，并不存在一个Queue的数据结构。ContentionList是一个后进先出（LIFO）的队列，每次新加入Node时都会在队头进行，通过CAS改变第一个节点的的指针为新增节点，同时设置新增节点的next指向后续节点，而取得操作则发生在队尾。显然，该结构其实是个Lock-Free的队列。</p><p style="margin: 0px; padding: 0px;">因为只有Owner线程才能从队尾取元素，也即线程出列操作无争用，当然也就避免了CAS的ABA问题。</p><div><img alt="" src="http://hi.csdn.net/attachment/201107/27/0_1311762773jLq3.gif" style="border: none; max-width: 100%;" /></div><h4><a name="t2" style="color: rgb(202, 0, 0);"></a>1.2 EntryList</h4><div>EntryList与ContentionList逻辑上同属等待队列，ContentionList会被线程并发访问，为了降低对ContentionList队尾的争用，而建立EntryList。Owner线程在unlock时会从ContentionList中迁移线程到EntryList，并会指定EntryList中的某个线程（一般为Head）为Ready（OnDeck）线程。Owner线程并不是把锁传递给OnDeck线程，只是把竞争锁的权利交给OnDeck，OnDeck线程需要重新竞争锁。这样做虽然牺牲了一定的公平性，但极大的提高了整体吞吐量，在Hotspot中把OnDeck的选择行为称之为&#8220;竞争切换&#8221;。</div><div>&nbsp;</div><div>OnDeck线程获得锁后即变为owner线程，无法获得锁则会依然留在EntryList中，考虑到公平性，在EntryList中的位置不发生变化（依然在队头）。如果Owner线程被wait方法阻塞，则转移到WaitSet队列；如果在某个时刻被notify/notifyAll唤醒，则再次转移到EntryList。</div><h3><a name="t3" style="color: rgb(202, 0, 0);"></a>2. 自旋锁</h3><div>那些处于ContetionList、EntryList、WaitSet中的线程均处于阻塞状态，阻塞操作由操作系统完成（在Linxu下通过pthread_mutex_lock函数）。线程被阻塞后便进入内核（Linux）调度状态，这个会导致系统在用户态与内核态之间来回切换，严重影响锁的性能</div><div></div><div>缓解上述问题的办法便是自旋，其原理是：当发生争用时，若Owner线程能在很短的时间内释放锁，则那些正在争用线程可以稍微等一等（自旋），在Owner线程释放锁后，争用线程可能会立即得到锁，从而避免了系统阻塞。但Owner运行的时间可能会超出了临界值，争用线程自旋一段时间后还是无法获得锁，这时争用线程则会停止自旋进入阻塞状态（后退）。基本思路就是自旋，不成功再阻塞，尽量降低阻塞的可能性，这对那些执行时间很短的代码块来说有非常重要的性能提高。自旋锁有个更贴切的名字：自旋-指数后退锁，也即复合锁。很显然，自旋在多处理器上才有意义。</div><div></div><div>还有个问题是，线程自旋时做些啥？其实啥都不做，可以执行几次for循环，可以执行几条空的汇编指令，目的是占着CPU不放，等待获取锁的机会。所以说，自旋是把双刃剑，如果旋的时间过长会影响整体性能，时间过短又达不到延迟阻塞的目的。显然，自旋的周期选择显得非常重要，但这与操作系统、硬件体系、系统的负载等诸多场景相关，很难选择，如果选择不当，不但性能得不到提高，可能还会下降，因此大家普遍认为自旋锁不具有扩展性。</div><div>&nbsp;</div><div>对自旋锁周期的选择上，HotSpot认为最佳时间应是一个线程上下文切换的时间，但目前并没有做到。经过调查，目前只是通过汇编暂停了几个CPU周期，除了自旋周期选择，HotSpot还进行许多其他的自旋优化策略，具体如下：</div><div><ul><li>如果平均负载小于CPUs则一直自旋</li><li>如果有超过(CPUs/2)个线程正在自旋，则后来线程直接阻塞</li><li>如果正在自旋的线程发现Owner发生了变化则延迟自旋时间（自旋计数）或进入阻塞</li><li>如果CPU处于节电模式则停止自旋</li><li>自旋时间的最坏情况是CPU的存储延迟（CPU A存储了一个数据，到CPU B得知这个数据直接的时间差）</li><li>自旋时会适当放弃线程优先级之间的差异</li></ul><div>那synchronized实现何时使用了自旋锁？答案是在线程进入ContentionList时，也即第一步操作前。线程在进入等待队列时首先进行自旋尝试获得锁，如果不成功再进入等待队列。这对那些已经在等待队列中的线程来说，稍微显得不公平。还有一个不公平的地方是自旋线程可能会抢占了Ready线程的锁。自旋锁由每个监视对象维护，每个监视对象一个。</div></div><h3><a name="t4" style="color: rgb(202, 0, 0);"></a>3. 偏向锁</h3><div>在JVM1.6中引入了偏向锁，偏向锁主要解决无竞争下的锁性能问题，首先我们看下无竞争下锁存在什么问题：</div><div>现在几乎所有的锁都是可重入的，也即已经获得锁的线程可以多次锁住/解锁监视对象，按照之前的HotSpot设计，每次加锁/解锁都会涉及到一些CAS操作（比如对等待队列的CAS操作），CAS操作会延迟本地调用，因此偏向锁的想法是一旦线程第一次获得了监视对象，之后让监视对象&#8220;偏向&#8221;这个线程，之后的多次调用则可以避免CAS操作，说白了就是置个变量，如果发现为true则无需再走各种加锁/解锁流程。但还有很多概念需要解释、很多引入的问题需要解决：</div><h4><a name="t5" style="color: rgb(202, 0, 0);"></a>3.1 CAS及SMP架构</h4><div>CAS为什么会引入本地延迟？这要从SMP（对称多处理器）架构说起，下图大概表明了SMP的结构：</div><div></div><div><img alt="" src="http://hi.csdn.net/attachment/201107/28/411087_1311836022idIz.jpg" style="border: none; max-width: 100%;" /></div><div>其意思是所有的CPU会共享一条系统总线（BUS），靠此总线连接主存。每个核都有自己的一级缓存，各核相对于BUS对称分布，因此这种结构称为&#8220;对称多处理器&#8221;。</div><div>&nbsp;</div><div>而CAS的全称为Compare-And-Swap，是一条CPU的原子指令，其作用是让CPU比较后原子地更新某个位置的值，经过调查发现，其实现方式是基于硬件平台的汇编指令，就是说CAS是靠硬件实现的，JVM只是封装了汇编调用，那些AtomicInteger类便是使用了这些封装后的接口。</div><div>&nbsp;</div><div>Core1和Core2可能会同时把主存中某个位置的值Load到自己的L1 Cache中，当Core1在自己的L1 Cache中修改这个位置的值时，会通过总线，使Core2中L1 Cache对应的值&#8220;失效&#8221;，而Core2一旦发现自己L1 Cache中的值失效（称为Cache命中缺失）则会通过总线从内存中加载该地址最新的值，大家通过总线的来回通信称为&#8220;Cache一致性流量&#8221;，因为总线被设计为固定的&#8220;通信能力&#8221;，如果Cache一致性流量过大，总线将成为瓶颈。而当Core1和Core2中的值再次一致时，称为&#8220;Cache一致性&#8221;，从这个层面来说，锁设计的终极目标便是减少Cache一致性流量。</div><div>&nbsp;</div><div>而CAS恰好会导致Cache一致性流量，如果有很多线程都共享同一个对象，当某个Core CAS成功时必然会引起总线风暴，这就是所谓的本地延迟，本质上偏向锁就是为了消除CAS，降低Cache一致性流量。</div><div>&nbsp;</div><div><strong><em>Cache一致性：</em></strong></div><div>上面提到Cache一致性，其实是有协议支持的，现在通用的协议是MESI（最早由Intel开始支持），具体参考：<a href="http://en.wikipedia.org/wiki/MESI_protocol" style="color: #ca0000; text-decoration: none;">http://en.wikipedia.org/wiki/MESI_protocol</a>，以后会仔细讲解这部分。</div><div><strong><em>Cache一致性流量的例外情况：</em></strong></div><div>其实也不是所有的CAS都会导致总线风暴，这跟Cache一致性协议有关，具体参考：<a href="http://blogs.oracle.com/dave/entry/biased_locking_in_hotspot" style="color: #ca0000; text-decoration: none;">http://blogs.oracle.com/dave/entry/biased_locking_in_hotspot</a></div><div><strong><em>NUMA(Non Uniform Memory Access Achitecture）架构：</em></strong></div><div>与SMP对应还有非对称多处理器架构，现在主要应用在一些高端处理器上，主要特点是没有总线，没有公用主存，每个Core有自己的内存，针对这种结构此处不做讨论。</div><h4><a name="t6" style="color: rgb(202, 0, 0);"></a>3.2 偏向解除</h4><div>偏向锁引入的一个重要问题是，在多争用的场景下，如果另外一个线程争用偏向对象，拥有者需要释放偏向锁，而释放的过程会带来一些性能开销，但总体说来偏向锁带来的好处还是大于CAS代价的。</div><h3><a name="t7" style="color: rgb(202, 0, 0);"></a>4. 总结</h3><div>关于锁，JVM中还引入了一些其他技术比如锁膨胀等，这些与自旋锁、偏向锁相比影响不是很大，这里就不做介绍。</div><div>通过上面的介绍可以看出，synchronized的底层实现主要依靠Lock-Free的队列，基本思路是自旋后阻塞，竞争切换后继续竞争锁，稍微牺牲了公平性，但获得了高吞吐量。下面会继续介绍JVM锁中的Lock（<a href="http://blog.csdn.net/chen77716/article/details/6641477" style="color: #ca0000; text-decoration: none;">深入JVM锁2-Lock</a>）。</div></div><img src ="http://www.blogjava.net/DLevin/aggbug/416100.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/DLevin/" target="_blank">DLevin</a> 2014-07-22 21:38 <a href="http://www.blogjava.net/DLevin/archive/2014/07/22/416100.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>