2009-09-16 42 views
31

我不確定這是否是同步我的ArrayList的正確方法。在java中同步ArrayList的正確方法

我有一個ArrayListin_queue這是從registerInQueue功能傳入。

ArrayList<Record> in_queue = null; 

public void registerInQueue(ArrayList in_queue) 
{ 
    this.in_queue = in_queue; 
} 

現在我試圖同步它。這是否正確同步了我的in_queue對象?

List<Record> in_queue_list = Collections.synchronizedList(in_queue); 

synchronized (in_queue_list) { 
    while (in_queue_list.size() > 0) { 
     in_queue_list.remove(0); 
    } 
} 
+5

由於您正在傳遞引用,因此您無法真正升級列表以進行同步,因此您並不真正擁有它。無論給你什麼參考,仍然可以修改它同時通過你的原始列表。無論您添加什麼同步,除非明確知道該列表將被內部鎖定保護。 – 2009-09-16 08:46:58

+0

我將在隊列上的任何操作周圍放置一個同步塊。謝謝! – bob 2009-09-16 09:09:56

回答

41

你同步兩次,這是毫無意義的,可能會減慢代碼:變化,同時遍歷列表需要在整個操作的synchronnization ,你在做什麼synchronized (in_queue_list)在這種情況下使用Collections.synchronizedList()是多餘的(它會創建一個包裝器來同步各個操作)。

但是,由於您完全清空了列表,第一個元素的迭代去除是最糟糕的方法,每個元素都必須複製所有後續元素,使得它成爲O(n^2 )操作 - 對於較大的列表來說非常慢。

相反,只需撥打clear() - 無需迭代。

編輯: 如果以後需要對Collections.synchronizedList()單方法同步,那麼這是正確的做法:

List<Record> in_queue_list = Collections.synchronizedList(in_queue); 
in_queue_list.clear(); // synchronized implicitly, 

但在許多情況下,單一方法的同步是不夠的(如對於所有的迭代,或者當你得到一個值時,根據它進行計算,並用結果替換它)。在這種情況下,無論如何你都必須使用手動同步,所以Collections.synchronizedList()只是無用的額外開銷。

+7

在這裏同步兩次並不是毫無意義的:它確保在循環運行時沒有其他人可以修改列表。不過,不使用clear()會有點過頭。 :) – Bombe 2009-09-16 08:43:42

+0

所以我應該這樣做:synchronized((List)in_queue)? – bob 2009-09-16 08:45:37

+0

好的!我實際上刪除了一些代碼以簡化它。我將不會遇到clear()/ remove()問題。謝謝=] – bob 2009-09-16 08:49:05

5

是的,這是正確的方法,但如果您希望所有刪除一起保證安全,則需要同步的塊 - 除非隊列爲空,否則不允許刪除。我的猜測是,你只是想要安全的隊列和出隊操作,所以你可以刪除同步塊。

然而,在Java中遠遠先進的併發隊列如ConcurrentLinkedQueue

8

看看你的例子,我認爲ArrayBlockingQueue(或它的兄弟姐妹)可能是有用的。他們會爲您提供同步服務,因此線程可以寫入隊列或進行窺視/獲取,而無需您進行額外的同步工作。

+0

感謝您的建議!這就是我想要做的,不確定是否限制了我的數組的大小。我會牢記這一點。 ;) – bob 2009-09-16 09:06:25

+0

請注意,還有一個LinkedBlockingQueue。而且你不一定需要施加限制。 – 2009-09-16 09:13:06

+0

謝謝,我會記住這= =] – bob 2009-09-16 09:19:38

1

我們來看一個正常的列表(由ArrayList類實現)並使其同步。這顯示在SynchronizedListExample類中。 我們通過Collections.synchronizedList方法傳遞一個新的字符串ArrayList。該方法返回一個同步的字符串列表。 //這裏是SynchronizedArrayList類

package com.mnas.technology.automation.utility; 
import java.util.ArrayList; 
import java.util.Collections; 
import java.util.Iterator; 
import java.util.List; 
import org.apache.log4j.Logger; 
/** 
* 
* @author manoj.kumar 
* @email [email protected] 
* 
*/ 
public class SynchronizedArrayList { 
    static Logger log = Logger.getLogger(SynchronizedArrayList.class.getName()); 
    public static void main(String[] args) {  
     List<String> synchronizedList = Collections.synchronizedList(new ArrayList<String>()); 
     synchronizedList.add("Aditya"); 
     synchronizedList.add("Siddharth"); 
     synchronizedList.add("Manoj"); 
     // when iterating over a synchronized list, we need to synchronize access to the synchronized list 
     synchronized (synchronizedList) { 
      Iterator<String> iterator = synchronizedList.iterator(); 
      while (iterator.hasNext()) { 
       log.info("Synchronized Array List Items: " + iterator.next()); 
      } 
     }  
    } 
} 

注意,遍歷列表時,該訪問依然採用了synchronized塊的synchronizedList對象鎖定完成。 通常,迭代同步的集合應在同步塊中完成