在java中同步ArrayList的正确方法

问题描述:

我不确定这是否是同步我的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

你同步两次,这是毫无意义的,可能会减慢代码:变化,同时遍历列表需要在整个操作的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

这是正确的,并记录在案:

http://java.sun.com/javase/6/docs/api/java/util/Collections.html#synchronizedList(java.util.List)

然而,清除列表,只需调用List.clear()

是的,这是正确的方法,但如果您希望所有删除一起保证安全,则需要同步的块 - 除非队列为空,否则不允许删除。我的猜测是,你只是想要安全的队列和出队操作,所以你可以删除同步块。

然而,在Java中远远先进的并发队列如ConcurrentLinkedQueue

看看你的例子,我认为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

我们来看一个正常的列表(由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对象锁定完成。 通常,迭代同步的集合应在同步块中完成