天天看點

測試并發應用 (一)監控Lock接口

校對:方騰飛

lock 接口是java 并發 api提供的最基本的機制來同步代碼塊。它允許定義臨界區。臨界區是代碼塊可以共享資源,但是不能被多個線程同時執行。此機制是通過lock 接口和 reentrantlock 類實作的。

在這個指南,你将學習從lock對象可以擷取的資訊和如何擷取這些資訊。

準備

指南中的例子是使用eclipse ide 來實作的。如果你使用eclipse 或者其他的ide,例如netbeans, 打開并建立一個新的java項目。

怎麼做呢…

按照這些步驟來實作下面的例子:

<code>001</code>

<code>package</code> <code>tool;</code>

<code>002</code>

<code>003</code>

<code>import</code> <code>java.util.collection;</code>

<code>004</code>

<code>import</code> <code>java.util.concurrent.timeunit;</code>

<code>005</code>

<code>import</code> <code>java.util.concurrent.locks.lock;</code>

<code>006</code>

<code>import</code> <code>java.util.concurrent.locks.reentrantlock;</code>

<code>007</code>

<code>008</code>

<code>//1.   建立一個類,名為 mylock ,擴充 reentrantlock 類。</code>

<code>009</code>

<code>public</code> <code>class</code> <code>mylock</code><code>extends</code> <code>reentrantlock {</code>

<code>010</code>

<code>011</code>

<code>    </code><code>// 2. 實作 getownername() 方法。此方法使用lock類的保護方法 getowner(), 傳回控制鎖的線程(如果存在)的名字。</code>

<code>012</code>

<code>    </code><code>public</code> <code>string getownername() {</code>

<code>013</code>

<code>        </code><code>if</code> <code>(</code><code>this</code><code>.getowner() ==</code><code>null</code><code>) {</code>

<code>014</code>

<code>            </code><code>return</code> <code>"none"</code><code>;</code>

<code>015</code>

<code>        </code><code>}</code>

<code>016</code>

<code>        </code><code>return</code> <code>this</code><code>.getowner().getname();</code>

<code>017</code>

<code>    </code><code>}</code>

<code>018</code>

<code>019</code>

<code>    </code><code>// 3. 實作 getthreads() 方法。此方法使用lock類的保護方法 getqueuedthreads(),傳回在鎖裡的線程的 queued</code>

<code>020</code>

<code>    </code><code>// list。</code>

<code>021</code>

<code>    </code><code>public</code> <code>collection&lt;thread&gt; getthreads() {</code>

<code>022</code>

<code>        </code><code>return</code> <code>this</code><code>.getqueuedthreads();</code>

<code>023</code>

<code>024</code>

<code>025</code>

<code>    </code><code>// 4. 建立一個類,名為 task,實作 runnable 接口.</code>

<code>026</code>

<code>    </code><code>public</code> <code>class</code> <code>task</code><code>implements</code> <code>runnable {</code>

<code>027</code>

<code>028</code>

<code>        </code><code>// 5. 聲明一個私有 lock 屬性,名為 lock。</code>

<code>029</code>

<code>        </code><code>private</code> <code>lock lock;</code>

<code>030</code>

<code>031</code>

<code>        </code><code>// 6. 實作類的構造函數,初始化它的屬性值。</code>

<code>032</code>

<code>        </code><code>public</code> <code>task(lock lock) {</code>

<code>033</code>

<code>            </code><code>this</code><code>.lock = lock;</code>

<code>034</code>

<code>035</code>

<code>036</code>

<code>        </code><code>// 7. 實作 run() 方法。建立疊代5次的for循環。</code>

<code>037</code>

<code>        </code><code>@override</code>

<code>038</code>

<code>        </code><code>public</code> <code>void</code> <code>run() {</code>

<code>039</code>

<code>            </code><code>for</code> <code>(</code><code>int</code> <code>i =</code><code>0</code><code>; i &lt;</code><code>5</code><code>; i++) {</code>

<code>040</code>

<code>041</code>

<code>                </code><code>// 8. 使用lock()方法擷取鎖,并列印一條資訊。</code>

<code>042</code>

<code>                </code><code>lock.lock();</code>

<code>043</code>

<code>                </code><code>system.out.printf(</code><code>"%s: get the lock.\n"</code><code>, thread.currentthread()</code>

<code>044</code>

<code>                        </code><code>.getname());</code>

<code>045</code>

<code>046</code>

<code>                </code><code>// 9. 讓線程休眠 500 毫秒。使用 unlock() 釋放鎖并列印一條資訊。</code>

<code>047</code>

<code>                </code><code>try</code> <code>{</code>

<code>048</code>

<code>                    </code><code>timeunit.milliseconds.sleep(</code><code>500</code><code>);</code>

<code>049</code>

<code>                    </code><code>system.out.printf(</code><code>"%s: free the lock.\n"</code><code>, thread</code>

<code>050</code>

<code>                            </code><code>.currentthread().getname());</code>

<code>051</code>

<code>                </code><code>}</code><code>catch</code> <code>(interruptedexception e) {</code>

<code>052</code>

<code>                    </code><code>e.printstacktrace();</code>

<code>053</code>

<code>                </code><code>}</code><code>finally</code> <code>{</code>

<code>054</code>

<code>                    </code><code>lock.unlock();</code>

<code>055</code>

<code>                </code><code>}</code>

<code>056</code>

<code>            </code><code>}</code>

<code>057</code>

<code>058</code>

<code>059</code>

<code>060</code>

<code>    </code><code>// 10. 建立例子的主類通過建立一個類,名為 main 并添加 main()方法。</code>

<code>061</code>

<code>    </code><code>public</code> <code>static</code> <code>void</code> <code>main(string[] args)</code><code>throws</code> <code>exception {</code>

<code>062</code>

<code>063</code>

<code>        </code><code>// 11. 建立 mylock 對象,名為 lock。</code>

<code>064</code>

<code>        </code><code>mylock lock =</code><code>new</code> <code>mylock();</code>

<code>065</code>

<code>066</code>

<code>        </code><code>// 12. 建立有5個thread對象的 array。</code>

<code>067</code>

<code>        </code><code>thread threads[] =</code><code>new</code> <code>thread[</code><code>5</code><code>];</code>

<code>068</code>

<code>069</code>

<code>        </code><code>// 13. 建立并開始5個線程來執行5個task對象。</code>

<code>070</code>

<code>        </code><code>for</code> <code>(</code><code>int</code> <code>i =</code><code>0</code><code>; i &lt;</code><code>5</code><code>; i++) {</code>

<code>071</code>

<code>            </code><code>task task = lock.</code><code>new</code> <code>task(lock);</code>

<code>072</code>

<code>            </code><code>threads[i] =</code><code>new</code> <code>thread(task);</code>

<code>073</code>

<code>            </code><code>threads[i].start();</code>

<code>074</code>

<code>075</code>

<code>076</code>

<code>        </code><code>// 14. 建立疊代15次的for循環。</code>

<code>077</code>

<code>        </code><code>for</code> <code>(</code><code>int</code> <code>i =</code><code>0</code><code>; i &lt;</code><code>15</code><code>; i++) {</code>

<code>078</code>

<code>079</code>

<code>            </code><code>// 15. 把鎖的擁有者的名字寫入操控台。</code>

<code>080</code>

<code>            </code><code>system.out.printf(</code><code>"main: logging the lock\n"</code><code>);</code>

<code>081</code>

<code>            </code><code>system.out.printf(</code><code>"************************\n"</code><code>);</code>

<code>082</code>

<code>            </code><code>system.out.printf(</code><code>"lock: owner : %s\n"</code><code>, lock.getownername());</code>

<code>083</code>

<code>084</code>

<code>            </code><code>// 16. 顯示鎖queued的線程的号碼和名字。</code>

<code>085</code>

<code>            </code><code>system.out.printf(</code><code>"lock: queued threads: %s\n"</code><code>,</code>

<code>086</code>

<code>                    </code><code>lock.hasqueuedthreads());</code><code>// 譯者注:加上 system</code>

<code>087</code>

<code>            </code><code>if</code> <code>(lock.hasqueuedthreads()) {</code>

<code>088</code>

<code>                </code><code>system.out.printf(</code><code>"lock: queue length: %d\n"</code><code>,</code>

<code>089</code>

<code>                        </code><code>lock.getqueuelength());</code>

<code>090</code>

<code>                </code><code>system.out.printf(</code><code>"lock: queued threads: "</code><code>);</code>

<code>091</code>

<code>                </code><code>collection&lt;thread&gt; lockedthreads = lock.getthreads();</code>

<code>092</code>

<code>                </code><code>for</code> <code>(thread lockedthread : lockedthreads) {</code>

<code>093</code>

<code>                    </code><code>system.out.printf(</code><code>"%s "</code><code>, lockedthread.getname());</code>

<code>094</code>

<code>095</code>

<code>                </code><code>system.out.printf(</code><code>"\n"</code><code>);</code>

<code>096</code>

<code>097</code>

<code>098</code>

<code>            </code><code>// 17. 顯示關于lock對象的公平性和狀态的資訊。</code>

<code>099</code>

<code>            </code><code>system.out.printf(</code><code>"lock: fairness: %s\n"</code><code>, lock.isfair());</code>

<code>100</code>

<code>            </code><code>system.out.printf(</code><code>"lock: locked: %s\n"</code><code>, lock.islocked());</code>

<code>101</code>

<code>102</code>

<code>103</code>

<code>            </code><code>// 18. 讓線程休眠1秒,并合上類的循環。</code>

<code>104</code>

<code>            </code><code>timeunit.seconds.sleep(</code><code>1</code><code>);</code>

<code>105</code>

<code>106</code>

<code>107</code>

<code>}</code>

它是如何工作的…

在這個指南裡,你實作的mylock類擴充了reentrantlock類來傳回資訊,除此之外獲得不到這些資訊 ,因為reentrantlock 類裡的資料都是保護類型的。 通過mylock類實作的方法:

getownername():隻有唯一一個線程可以執行被lock對象保護的臨界區。鎖存儲了正在執行臨界區的線程。此線程會被reentrantlock類的保護方法 getowner()傳回。 此方法使用 getowner() 方法來傳回線程的名字。

getthreads():當線程正在執行臨界區時,其他線程嘗試進入臨界區就會被放到休眠狀态一直到他們可以繼續執行為止。reentrantlock類保護方法getqueuedthreads() 傳回 正在等待執行臨界區的線程list。此方法傳回 getqueuedthreads() 方法傳回的結果。

我們還使用了 reentrantlock 類裡實作的其他方法:

hasqueuedthreads():此方法傳回 boolean 值表明是否有線程在等待擷取此鎖

getqueuelength(): 此方法傳回等待擷取此鎖的線程數量

islocked(): 此方法傳回 boolean 值表明此鎖是否為某個線程所擁有

isfair(): 此方法傳回 boolean 值表明鎖的 fair 模式是否被激活

更多…

reentrantlock 類還有其他方法也是用來擷取lock對象的資訊的:

getholdcount(): 傳回目前線程擷取鎖的次數

isheldbycurrentthread(): 傳回 boolean 值,表明鎖是否為目前線程所擁有

繼續閱讀