實作你自己的原子(atomic)對象
java版本5中引入原子變量,并提供對單個變量的原子操作。當一個線程在原子變量上執行操作時,這個類的實作包含一種機制用來檢查這個操作在一個步驟内完成。基本上,這個操作是先擷取變量的值,然後在本地變量中改變這個值,最後嘗試将舊值變成這個新值。如果舊值仍然是相同的,它将改變成新值,否則,這個方法重新開始這個操作。(校對注:這段話描述了cas的實作原理 )
在這個指南中,你将學習如何繼承一個原子對象和如何實作遵從原子對象機制的兩個操作,來保證所有的操作在一個步驟内完成。
準備工作…
這個指南的例子使用eclipse ide實作。如果你使用eclipse或其他ide,如netbeans,打開它并建立一個新的java項目。
如何做…
按以下步驟來實作的這個例子:
1.建立parkingcounter類,并指定它繼承atomicinteger類。
<code>1</code>
<code>public</code> <code>class</code> <code>parkingcounter</code><code>extends</code> <code>atomicinteger {</code>
2.聲明一個私有的、int類型的屬性maxnumber,用來存儲停車場允許停放汽車的最大數量。
<code>private</code> <code>int</code> <code>maxnumber;</code>
3.實作這個類的構造器,并初始化它的屬性。
<code>public</code> <code>parkingcounter(</code><code>int</code> <code>maxnumber){</code>
<code>2</code>
<code>set(</code><code>0</code><code>);</code>
<code>3</code>
<code>this</code><code>.maxnumber=maxnumber;</code>
<code>4</code>
<code>}</code>
4.實作carin()方法。這個方法增加車的計數器,如果它小于設定的最大數。建構一個無限循環,并使用get()方法擷取内部計數器的值。
<code>public</code> <code>boolean</code> <code>carin() {</code>
<code>for</code> <code>(;;) {</code>
<code>int</code> <code>value=get();</code>
5.如果計數器的值等于最maxnumber屬性值,這個計數器不能再增加(停車場已滿,其他車不能再進入)。這個方法傳回false值。
<code>if</code> <code>(value==maxnumber) {</code>
<code>system.out.printf("parkingcounter: the parking lot is</code>
<code>full.\n");</code>
<code>return</code> <code>false</code><code>;</code>
6.否則,增加這個值,并compareandset()方法将舊值變成新值。如果這個方法傳回false值,說明計數器沒有增加,是以你必須重新開始這個循環。如果這個方法傳回true值,它意味着改變操作成功,然後你傳回了true值。
<code>01</code>
<code>}</code><code>else</code> <code>{</code>
<code>02</code>
<code>int</code> <code>newvalue=value+</code><code>1</code><code>;</code>
<code>03</code>
<code>boolean</code> <code>changed=compareandset(value,newvalue);</code>
<code>04</code>
<code>if</code> <code>(changed) {</code>
<code>05</code>
<code>system.out.printf("parkingcounter: a car has</code>
<code>06</code>
<code>entered.\n");</code>
<code>07</code>
<code>return</code> <code>true</code><code>;</code>
<code>08</code>
<code>09</code>
<code>10</code>
<code>11</code>
7.實作carout()方法。這個方法減少車的計數器值,如果它大于0。建構一個無限循環,并使用get()方法擷取内部的計數器的值。
<code>public</code> <code>boolean</code> <code>carout() {</code>
<code>if</code> <code>(value==</code><code>0</code><code>) {</code>
<code>empty.\n");</code>
<code>int</code> <code>newvalue=value-</code><code>1</code><code>;</code>
<code>12</code>
<code>system.out.printf("parkingcounter: a car has gone</code>
<code>13</code>
<code>out.\n");</code>
<code>14</code>
<code>15</code>
<code>16</code>
<code>17</code>
<code>18</code>
8.建立一個實作runnable接口的sensor1類。
<code>public</code> <code>class</code> <code>sensor1</code><code>implements</code> <code>runnable {</code>
9.聲明一個私有的、parkingcounter類型的屬性counter。
<code>private</code> <code>parkingcounter counter;</code>
10.實作這個類的構造器,并初始化它的屬性。
<code>public</code> <code>sensor1(parkingcounter counter) {</code>
<code>this</code><code>.counter=counter;</code>
11.實作run()方法。調用幾次carin()和carout()操作。
<code>@override</code>
<code>public</code> <code>void</code> <code>run() {</code>
<code>counter.carin();</code>
<code>counter.carout();</code>
12.建立一個實作了runnable接口的sensor2類。
<code>public</code> <code>class</code> <code>sensor2</code><code>implements</code> <code>runnable {</code>
13.聲明一個私有的、parkingcounter類型的屬性counter。
14.實作這個類的構造器,并初始化它的屬性。
<code>public</code> <code>sensor2(parkingcounter counter) {</code>
15.實作run()方法。調用幾次carin()和carout()操作。
16.實作這個例子的主類,通過實作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><code>throws</code> <code>exception {</code>
17.建立一個parkingcounter對象,名為counter。
<code>parkingcounter counter=</code><code>new</code> <code>parkingcounter(</code><code>5</code><code>);</code>
18.建立和啟動一個sensor1任務和一個sensor2任務。
<code>sensor1 sensor1=</code><code>new</code> <code>sensor1(counter);</code>
<code>sensor2 sensor2=</code><code>new</code> <code>sensor2(counter);</code>
<code>thread thread1=</code><code>new</code> <code>thread(sensor1);</code>
<code>thread thread2=</code><code>new</code> <code>thread(sensor2);</code>
<code>5</code>
<code>thread1.start();</code>
<code>6</code>
<code>thread2.start();</code>
19.等待這兩個任務的結束。
<code>thread1.join();</code>
<code>thread2.join();</code>
20.将計數器的實際值寫入到控制台。
<code>system.out.printf(</code><code>"main: number of cars: %d\n"</code><code>,counter.get());</code>
21.寫入一條資訊到控制台表明程式的結束。
<code>system.out.printf(</code><code>"main: end of the program.\n"</code><code>);</code>
它是如何工作的…
繼承atomicinteger類的parkingcounter類有兩個原子操作,carin()和carount()。這個例子模拟一個系統來控制停車場内的汽車數。這個停車場可容納的汽車數用maxnumber屬性表示。
carin()操作将實際汽車數與停車場(可容納的汽車數)的最大值進行比較。如果它們相等,這輛汽車不能進行停車場并傳回false值。否則,它使用以下的原子操作結構:
用一個本地變量擷取原子對象的值。
用一個不同的變量來存儲新值。
使用compareandset()方法嘗試将舊值替換成新值。如果這個方法傳回true,作為參數傳入的舊值是這個變量的值,是以,它使值變化。随着carin()方法傳回true值,這個操作将以原子方式完成。如果compareandset()方法傳回false值,作為參數傳入的舊值不是這個變量的值(其他線程已修改它),是以這個操作不能以原子方式完成。這個操作将重新開始,直到它可以以原子方式完成。
carout()方法與carin()方法類似。你已實作兩個runnable對象,使用carin()和carout()來模拟停車的活動。當你執行這個程式,你可以看出停車場沒有克服汽車在停車場的最大值。