天天看點

基本線程同步(六)使用讀/寫鎖同步資料通路

使用讀/寫鎖同步資料通路

鎖所提供的最重要的改進之一就是readwritelock接口和唯一 一個實作它的reentrantreadwritelock類。這個類提供兩把鎖,一把用于讀操作和一把用于寫操作。同時可以有多個線程執行讀操作,但隻有一個線程可以執行寫操作。當一個線程正在執行一個寫操作,不可能有任何線程執行讀操作。

在這個指南中,你将會學習如何使用readwritelock接口實作一個程式,使用它來控制通路一個存儲兩個産品價格的對象。

準備工作…

你應該事先閱讀使用lock同步代碼塊的指南,才能更好的了解這個食譜。

如何做…

按以下步驟來實作的這個例子:

1.建立pricesinfo類,用它來存儲兩個産品價格的資訊。

<code>1</code>

<code>public</code> <code>class</code> <code>pricesinfo {</code>

2.聲明兩個double類型的屬性,分别命名為price1和price2。

<code>private</code> <code>double</code> <code>price1;</code>

<code>2</code>

<code>private</code> <code>double</code> <code>price2;</code>

3.聲明一個名為lock的readwritelock對象。

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

4.實作類的構造器,初始化這三個屬性。其中,對于lock屬性,我們建立一個新的reentrantreadwritelock對象。

<code>public</code> <code>pricesinfo(){</code>

<code>price1=</code><code>1.0</code><code>;</code>

<code>3</code>

<code>price2=</code><code>2.0</code><code>;</code>

<code>4</code>

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

<code>5</code>

<code>}</code>

5.實作getprice1()方法,用它來傳回price1屬性的值。它使用讀鎖來控制這個屬性值的通路。

<code>public</code> <code>double</code> <code>getprice1() {</code>

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

<code>double</code> <code>value=price1;</code>

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

<code>return</code> <code>value;</code>

<code>6</code>

6.實作getprice2()方法,用它來傳回price2屬性的值。它使用讀鎖來控制這個屬性值的通路。

<code>public</code> <code>double</code> <code>getprice2() {</code>

<code>double</code> <code>value=price2;</code>

7.實作setprices()方法,用來建立這兩個屬性的值。它使用寫鎖來控制對它們的通路。

<code>public</code> <code>void</code> <code>setprices(</code><code>double</code> <code>price1,</code><code>double</code> <code>price2) {</code>

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

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

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

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

8.建立reader類,并指定它實作runnable接口。這個類實作了pricesinfo類屬性值的讀者。

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

9.聲明一個pricesinfo對象,并且實作reader類的構造器來初始化這個對象。

<code>private</code> <code>pricesinfo pricesinfo;</code>

<code>public</code> <code>reader (pricesinfo pricesinfo){</code>

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

10.實作reader類的run()方法,它讀取10次兩個價格的值。

<code>@override</code>

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

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

<code>system.out.printf(</code><code>"%s: price 1: %f\n"</code><code>, thread.</code>

<code>currentthread().getname(),pricesinfo.getprice1());</code>

<code>system.out.printf(</code><code>"%s: price 2: %f\n"</code><code>, thread.</code>

<code>7</code>

<code>currentthread().getname(),pricesinfo.getprice2());</code>

<code>8</code>

<code>9</code>

11.建立writer類,并指定它實作runnable接口。這個類實作了pricesinfo類屬性值的修改者。

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

12.聲明一個pricesinfo對象,并且實作writer類的構造器來初始化這個對象。

<code>public</code> <code>writer(pricesinfo pricesinfo){</code>

13.實作run()方法,它修改了三次兩個價格的值,并且在每次修改之後睡眠2秒。

<code>01</code>

<code>02</code>

<code>03</code>

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

<code>04</code>

<code>system.out.printf("writer: attempt to modify the</code>

<code>05</code>

<code>prices.\n");</code>

<code>06</code>

<code>pricesinfo.setprices(math.random()*</code><code>10</code><code>, math.random()*</code><code>8</code><code>);</code>

<code>07</code>

<code>system.out.printf(</code><code>"writer: prices have been modified.\n"</code><code>);</code>

<code>08</code>

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

<code>09</code>

<code>thread.sleep(</code><code>2</code><code>);</code>

<code>10</code>

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

<code>11</code>

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

<code>12</code>

<code>13</code>

<code>14</code>

14.通過建立類名為main,且包括main()方法來實作這個示例的主類。

<code>public</code> <code>class</code> <code>main {</code>

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

15.建立一個pricesinfo對象。

<code>pricesinfo pricesinfo=</code><code>new</code> <code>pricesinfo();</code>

16.建立5個reader對象,并且用5個線程來執行它們。

<code>reader readers[]=</code><code>new</code> <code>reader[</code><code>5</code><code>];</code>

<code>thread threadsreader[]=</code><code>new</code> <code>thread[</code><code>5</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>readers[i]=</code><code>new</code> <code>reader(pricesinfo);</code>

<code>threadsreader[i]=</code><code>new</code> <code>thread(readers[i]);</code>

17.建立一個writer對象,并且用線程來執行它。

<code>writer writer=</code><code>new</code> <code>writer(pricesinfo);</code>

<code>thread threadwriter=</code><code>new</code> <code>thread(writer);</code>

18.啟動這些線程。

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

<code>threadwriter.start();</code>

它是如何工作的…

在以下截圖中,你可以看到執行這個例子的一個部分輸出:

基本線程同步(六)使用讀/寫鎖同步資料通路

正如我們前面提及到的,reentrantreadwritelock類有兩把鎖,一把用于讀操作,一把用于寫操作。用于讀操作的鎖,是通過在 readwritelock接口中聲明的readlock()方法擷取的。這個鎖是實作lock接口的一個對象,是以我們可以使用lock(), unlock() 和trylock()方法。用于寫操作的鎖,是通過在readwritelock接口中聲明的writelock()方法擷取的。這個鎖是實作lock接 口的一個對象,是以我們可以使用lock(), unlock() 和trylock()方法。確定正确的使用這些鎖,使用它們與被設計的目的是一樣的,這是程式猿的職責。當你獲得lock接口的讀鎖時,不能修改這個變量的值。否則,你可能會有資料不一緻的錯誤。

參見

在第2章,基本線程同步中使用lock同步代碼塊的指南。

在第8章,測試并發應該程式中監控lock接口的指南。

繼續閱讀