597
阿裏雲
技術社區[雲棲]
並發集合(九)使用原子 arrays
聲明:本文是《 Java 7 Concurrency Cookbook 》的第六章, 作者: Javier Fernández González譯者:鄭玉婷 校對:黃庭
當你實現一個多個線程共享一個或者多個對象的並發應用時,你就要使用像鎖或者同步關鍵詞(例如synchronized)來對他們的屬性的訪問進行保護,來避免並發造成的數據不一致的錯誤。
但是這些機製會有以下一些缺點:
死鎖(dead lock):例如:當一個線程等待一個鎖的時候,會被阻塞,而這個鎖被其他線程占用並且永不釋放。這種情況就是死鎖,程序在這種情況下永遠都不會往下執行。
即使隻有一個線程在訪問共享對象,它也要執行必要的獲取鎖和釋放鎖的代碼。
CAS(compare-and-swap)操作為並發操作對象的提供更好的性能,CAS操作通過以下3個步驟來實現對變量值得修改:
- 獲取當前內存中的變量的值
- 用一個新的臨時變量(temporal variable)保存改變後的新值
- 如果當前內存中的值等於變量的舊值,則將新值賦值到當前變量;否則不進行任何操作
對於這個機製,你不需要使用任何同步機製,這樣你就避免了 deadlocks,也獲得了更好的性能。這種機製能保證多個並發線程對一個共享變量操作做到最終一致。
Java 在原子類中實現了CAS機製。這些類提供了compareAndSet() 方法;這個方法是CAS操作的實現和其他方法的基礎。
Java 中還引入了原子Array,用來實現Integer類型和Long類型數組的操作。在這個指南裏,你將要學習如何使用AtomicIntegerArray 類來操作原子 arrays。
指南中的例子是在Eclipse IDE下麵實現的,你也可以使用其他IDE例如NetBeans來實現:
那要怎麼做呢….
按照這些步驟來實現下麵的例子:
01 |
//1.創建一個類,名為 Incrementer,並實現 Runnable 接口。 |
02 |
public class Incrementer implements Runnable {
|
04 |
//2.聲明一個私有 AtomicIntegerArray 屬性,名為 vector,用來儲存一個整數 array。 |
05 |
private AtomicIntegerArray vector;
|
07 |
//3.實現類的構造函數,初始化它的屬性值。 |
08 |
public Incrementer(AtomicIntegerArray vector) {
|
12 |
//4.實現 run() 方法。使用 getAndIncrement() 方操作array裏的所有元素。 |
15 |
for ( int i= 0 ; i<vector.length(); i++){
|
16 |
vector.getAndIncrement(i);
|
20 |
//5.創建一個類,名為 Decrementer,並實現 Runnable 接口。 |
21 |
public class Decrementer implements Runnable {
|
23 |
//6.聲明一個私有 AtomicIntegerArray 屬性,名為 vector,用來儲存一個整數 array。 |
24 |
private AtomicIntegerArray vector;
|
26 |
//7.實現類的構造函數,初始化它的屬性值。 |
27 |
public Decrementer(AtomicIntegerArray vector) {
|
31 |
//8.實現 run() 方法。使用 getAndDecrement() 方法操作array裏的所有元素。 |
34 |
for ( int i= 0 ; i<vector.length(); i++) {
|
35 |
vector.getAndDecrement(i);
|
39 |
//9.我們創建一個示例來進行示範,創建一個類,名為 Main 並添加 main()方法。 |
41 |
public static void main(String[] args) {
|
43 |
//10.聲明一個常量,名為 THREADS,分配它的值為 100。創建一個有1,000個元素的 AtomicIntegerArray 對象。 |
44 |
final int THREADS= 100 ;
|
45 |
AtomicIntegerArray vector= new AtomicIntegerArray( 1000 );
|
47 |
//11. 創建一個 Incrementer 任務來操作之前創建的原子 array。 |
48 |
Incrementer incrementer= new Incrementer(vector);
|
50 |
//12.創建一個 Decrementer 任務來操作之前創建的原子 array。 |
51 |
Decrementer decrementer= new Decrementer(vector);
|
53 |
//13.創建2個array 分別存儲 100 個Thread 對象。 |
54 |
Thread threadIncrementer[]= new Thread[THREADS];
|
55 |
Thread threadDecrementer[]= new Thread[THREADS];
|
57 |
//14.創建並運行 100 個線程來執行 Incrementer 任務和另外 100 個線程來執行 Decrementer 任務。把線程儲存入之前創建的arrays內。 |
58 |
for ( int i= 0 ; i<THREADS; i++) {
|
59 |
threadIncrementer[i]= new Thread(incrementer);
|
60 |
threadDecrementer[i]= new Thread(decrementer);
|
62 |
threadIncrementer[i].start();
|
63 |
threadDecrementer[i].start();
|
65 |
//15.使用 join() 方法來等待線程的完結。 |
66 |
for ( int i= 0 ; i< 100 ; i++) {
|
68 |
threadIncrementer[i].join();
|
69 |
threadDecrementer[i].join();
|
70 |
} catch (InterruptedException e) {
|
74 |
//16.把原子array裏非0的元素寫入操控台。使用 get() 方法來獲取原子 array 元素。 |
75 |
for ( int i= 0 ; i<vector.length(); i++) {
|
76 |
if (vector.get(i)!= 0 ) {
|
77 |
System.out.println( "Vector[" +i+ "] : " +vector.get(i));
|
82 |
System.out.println( "Main: End of the example" );
|
它是怎麼工作的…
在這個例子裏,你實現了2個不同的任務來操作 AtomicIntegerArray 對象:
Incrementer task: 這個類使用getAndIncrement()方法array裏的全部元素 +1
Decrementer task: 這個類使用getAndDecrement()方法array裏的全部元素 -1
在 Main 類,你創建了有1000個元素的 AtomicIntegerArray,然後你執行了100次 Incrementer 和100次 Decrementer 任務。在任務結束後,如果沒有出現任何數據不一致錯誤,那麼array的全部元素的值都為0。如果你運行這個任務,由於全部元素都是0,你隻會看到程序在操控台隻寫了結束信息。
更多…
如今,Java僅提供了另一個原子 array類。它是 AtomicLongArray 類,與 IntegerAtomicArray 類提供了相同的方法。
這些類的一些其他有趣的方法有:
get(int i): 返回array中第i個位置上的值
set(int I, int newValue): 設置array中第i個位置上的值為newValue
參見
第六章,並發集:使用原子變量
文章轉自 並發編程網-ifeve.com
最後更新:2017-05-23 17:32:17