生活随笔
收集整理的這篇文章主要介紹了
并发集合(二)使用非阻塞线程安全的列表
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
使用非阻塞線程安全的列表
列表(list)是最基本的集合。一個列表有不確定的元素數量,并且你可以添加、讀取和刪除任意位置上的元素。并發列表允許不同的線程在同一時刻對列表的元素進行添加或刪除,而不會產生任何數據不一致(問題)。
在這個指南中,你將學習如何在你的并發應用程序中使用非阻塞列表。非阻塞列表提供這些操作:如果操作不能立即完成(比如,你想要獲取列表的元素而列表卻是空的),它將根據這個操作拋出異常或返回null值。Java 7引進實現了非阻塞并發列表的ConcurrentLinkedDeque類。
我們將使用以下兩種不同任務來實現一個例子:
準備工作…
這個指南的例子使用Eclipse IDE實現。如果你使用Eclipse或其他IDE,如NetBeans,打開它并創建一個新的Java項目。
如何做…
按以下步驟來實現的這個例子:
1.創建一個實現Runnable接口的AddTask類:
| 1 | public class AddTask implements Runnable { |
2.聲明一個私有的、ConcurrentLinkedDeque類型的、參數化為String類的屬性list。
| 1 | private ConcurrentLinkedDeque<String> list; |
3.實現這個類的構造器,并初始化它的屬性。
| 1 | public AddTask(ConcurrentLinkedDeque<String> list) { |
4.實現這個類的run()方法。它將在列表中存儲10000個正在執行任務的線程的名稱和一個數字的字符串。
| 3 | String name=Thread.currentThread().getName(); |
| 4 | for (int i=0; i<10000; i++){ |
| 5 | list.add(name+": Element "+i); |
5.創建一個實現Runnable接口的PollTask類。
| 1 | public class PollTask implements Runnable { |
6.聲明一個私有的、ConcurrentLinkedDeque類型的、參數化為String類的屬性list。
| 1 | private ConcurrentLinkedDeque<String> list; |
7.實現這個類的構造器,并初始化它的屬性。
| 1 | public PollTask(ConcurrentLinkedDeque<String> list) { |
8.實現這個類的run()方法。它從列表中取出10000個元素(在一個循環5000次的循環中,每次取出2個元素)。
| 3 | for (int i=0; i<5000; i++) { |
9.實現這個例子的主類,通過實現Main類,并實現main()方法。
| 2 | public static void main(String[] args) { |
10.創建一個參數化為String、名為list的ConcurrentLinkedDeque對象。
| 1 | ConcurrentLinkedDeque<String> list=new ConcurrentLinkedDeque<>(); |
11.創建一個存儲100個Thread對象的數組threads。
| 1 | Thread threads[]=new Thread[100]; |
12.創建100個AddTask對象,對于它們中的每一個用一個線程來運行。用之前創建的數組來存儲每個線程,并啟動這些線程。
| 1 | for (int i=0; i<threads.length ; i++){ |
| 2 | AddTask task=new AddTask(list); |
| 3 | threads[i]=new Thread(task); |
| 6 | System.out.printf("Main: %d AddTask threads have been |
| 7 | launched\n",threads.length); |
13.使用join()方法,等待這些線程的完成。
| 1 | for (int i=0; i<threads.length; i++) { |
| 4 | } catch (InterruptedException e) { |
14.將列表的大小寫入控制臺。
| 1 | System.out.printf("Main: Size of the List: %d\n",list.size()); |
15.創建100個PollTask對象,對于它們中的每一個用一個線程來運行。用之前創建的數組來存儲每個線程,并啟動這些線程。
| 1 | for (int i=0; i< threads.length; i++){ |
| 2 | PollTask task=new PollTask(list); |
| 3 | threads[i]=new Thread(task); |
| 6 | System.out.printf("Main: %d PollTask threads have been |
| 7 | launched\n",threads.length); |
16.使用join()方法,等待這些線程的完成。
| 1 | for (int i=0; i<threads.length; i++) { |
| 4 | } catch (InterruptedException e) { |
17.將列表的大小寫入控制臺。
| 1 | System.out.printf("Main: Size of the List: %d\n",list.size()); |
它是如何工作的…
在這個指南中,我們已使用參數化為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異常。
總結
以上是生活随笔為你收集整理的并发集合(二)使用非阻塞线程安全的列表的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。