在java中同步ArrayList的正确方法

bob*_*bob 35 java concurrency synchronization arraylist

我不确定这是否是同步我的正确方法ArrayList.

我有一个ArrayList in_queueregisterInQueue函数传入的.

ArrayList<Record> in_queue = null;

public void registerInQueue(ArrayList in_queue)
{
    this.in_queue = in_queue;
}
Run Code Online (Sandbox Code Playgroud)

现在我正在尝试同步它.这是否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);
    }
}
Run Code Online (Sandbox Code Playgroud)

Mic*_*rdt 46

你正在进行两次同步,这是毫无意义的,可能会减慢代码的速度:在列表上进行迭代时需要对整个操作进行同步,而在这种情况下synchronized (in_queue_list)使用Collections.synchronizedList()则是多余的(它创建了一个同步单个操作的包装器) ).

但是,由于您正在完全清空列表,因此迭代删除第一个元素是最糟糕的方法,每个元素的sice必须复制所有后续元素,这使得这是一个O(n ^ 2)操作 - 非常可怕较大的列表慢.

相反,只需调用clear()- 不需要迭代.

编辑: 如果以后需要单方法同步Collections.synchronizedList(),那么这是正确的方法:

List<Record> in_queue_list = Collections.synchronizedList(in_queue);
in_queue_list.clear(); // synchronized implicitly, 
Run Code Online (Sandbox Code Playgroud)

但在许多情况下,单方法同步是不够的(例如,对于所有迭代,或者当您获得值时,基于它进行计算,并将其替换为结果).在这种情况下,您无论如何都必须使用手动同步,因此Collections.synchronizedList()只是无用的额外开销.

  • 在这里同步两次并不是没有意义的:它确保在循环运行时没有其他人可以修改列表.但是,不使用`clear()`有点过分了.:) (7认同)
  • @Bombe:不,这完全没有意义.正如我所写,使用Collections.synchronizedList()是多余的 (4认同)

Bri*_*new 8

看看你的例子,我认为ArrayBlockingQueue(或它的兄弟姐妹)可能有用.他们会为您管理同步,因此线程可以写入队列或查看/获取,而无需您进行额外的同步工作.


Dav*_*itz 5

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

但是,Java中有很多高级并发队列,例如ConcurrentLinkedQueue