天天看點

并發集合(二)使用非阻塞線程安全的清單

使用非阻塞線程安全的清單

清單(list)是最基本的集合。一個清單有不确定的元素數量,并且你可以添加、讀取和删除任意位置上的元素。并發清單允許不同的線程在同一時刻對清單的元素進行添加或删除,而不會産生任何資料不一緻(問題)。

在這個指南中,你将學習如何在你的并發應用程式中使用非阻塞清單。非阻塞清單提供這些操作:如果操作不能立即完成(比如,你想要擷取清單的元素而清單卻是空的),它将根據這個操作抛出異常或傳回null值。java 7引進實作了非阻塞并發清單的concurrentlinkeddeque類。

我們将使用以下兩種不同任務來實作一個例子:

大量添加資料到清單

在同個清單中,大量删除資料

準備工作…

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

如何做…

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

1.建立一個實作runnable接口的addtask類:

2.聲明一個私有的、concurrentlinkeddeque類型的、參數化為string類的屬性list。

3.實作這個類的構造器,并初始化它的屬性。

4.實作這個類的run()方法。它将在清單中存儲10000個正在執行任務的線程的名稱和一個數字的字元串。

5.建立一個實作runnable接口的polltask類。

6.聲明一個私有的、concurrentlinkeddeque類型的、參數化為string類的屬性list。

7.實作這個類的構造器,并初始化它的屬性。

8.實作這個類的run()方法。它從清單中取出10000個元素(在一個循環5000次的循環中,每次取出2個元素)。

9.實作這個例子的主類,通過實作main類,并實作main()方法。

10.建立一個參數化為string、名為list的concurrentlinkeddeque對象。

11.建立一個存儲100個thread對象的數組threads。

12.建立100個addtask對象,對于它們中的每一個用一個線程來運作。用之前建立的數組來存儲每個線程,并啟動這些線程。

13.使用join()方法,等待這些線程的完成。

14.将清單的大小寫入控制台。

15.建立100個polltask對象,對于它們中的每一個用一個線程來運作。用之前建立的數組來存儲每個線程,并啟動這些線程。

16.使用join()方法,等待這些線程的完成。

17.将清單的大小寫入控制台。

它是如何工作的…

在這個指南中,我們已使用參數化為string類的concurrentlinkeddeque對象來處理非阻塞并發清單的資料。以下截圖顯示這個例子執行的輸出:

并發集合(二)使用非阻塞線程安全的清單

首先,你已執行100個addtask任務來給清單添加元素。每個任務使用add()方法添加10000個元素到清單。這個方法将新元素插入到清單的尾部。當這些任務全部完成,你已在控制台列印這個清單元素的數量。此時,清單有1000000個元素。

然後,你執行100個polltask任務從清單中删除元素。每個任務使用pollfirst()和polllast()方法删除清單的10000個元素。pollfirst()方法傳回并删除清單的第一個元素,polllast()方法傳回并删除清單的最後一個元素。如果清單為空,這些方法将傳回一個null值。當這些任務全部完成,你已在控制台列印這個清單元素的數量。此時,清單有0個元素。

你使用size()方法,列印清單元素的數量。你必須考慮到這個方法會傳回一個并不真實的值,尤其是如果你使用這個方法,而有線程正在添加或删除清單的資料。這個方法必須周遊整個清單來計算元素而對于這個操作清單的内容可以改變。隻有在沒有任何線程修改清單的情況下,你使用這個方法時,你将保證這個傳回值是正确的。

不止這些…

concurrentlinkeddeque類提供更多方法來擷取清單的元素:

getfirst()和getlast():這些方法将分别傳回清單的第一個和最後一個元素。它們不會從清單删除傳回的元素。如果清單為空,這些方法将抛出nosuchelementexcpetion異常。

peek()、peekfirst()和peeklast():這些方法将分别傳回清單的第一個和最後一個元素。它們不會從清單删除傳回的元素。如果清單為空,這些方法将傳回null值。

remove()、removefirst()、 removelast():這些方法将分别傳回清單的第一個和最後一個元素。它們将從清單删除傳回的元素。如果清單為空,這些方法将抛出nosuchelementexcpetion異常。

繼續閱讀