在java中同步ArrayList的正确方法

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1431681/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-12 11:59:22  来源:igfitidea点击:

Correct way to synchronize ArrayList in java

javaarraylistconcurrencysynchronization

提问by bob

I'm not sure if this is the correct way to synchronize my ArrayList.

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

I have an ArrayListin_queuewhich is passed in from the registerInQueuefunction.

我有一个ArrayListin_queueregisterInQueue函数传入的。

ArrayList<Record> in_queue = null;

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

Now I'm trying to synchronize it. Is this sychronizing my in_queueobject correctly?

现在我正在尝试同步它。这是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);
    }
}

采纳答案by Michael Borgwardt

You're synchronizing twice, which is pointless and possibly slows down the code: changes while iterating over the list need a synchronnization over the entire operation, which you are doing with synchronized (in_queue_list)Using Collections.synchronizedList()is superfluous in that case (it creates a wrapper that synchronizes individual operations).

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

However, since you are emptying the list completely, the iterated removal of the first element is the worst possible way to do it, sice for each element all following elements have to be copied, making this an O(n^2) operation - horribly slow for larger lists.

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

Instead, simply call clear()- no iteration needed.

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

Edit:If you need the single-method synchronization of Collections.synchronizedList()later on, then this is the correct way:

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

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

But in many cases, the single-method synchronization is insufficient (e.g. for all iteration, or when you get a value, do computations based on it, and replace it with the result). In that case, you have to use manual synchronization anyway, so Collections.synchronizedList()is just useless additional overhead.

但是在很多情况下,单方法同步是不够的(例如对于所有迭代,或者当你得到一个值时,根据它做计算,并用结果替换它)。在这种情况下,您无论如何都必须使用手动同步,因此Collections.synchronizedList()只是无用的额外开销。

回答by Andrew Duffy

That's correct, and documented:

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

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

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

However, to clear the list, just call List.clear().

但是,要清除列表,只需调用List.clear()

回答by David Rabinowitz

Yes it is the correct way, but the synchronised block is required if you want all the removals together to be safe - unless the queue is empty no removals allowed. My guess is that you just want safe queue and dequeue operations, so you can remove the synchronised block.

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

However, there are far advanced concurrent queues in Java such as ConcurrentLinkedQueue

但是,Java 中有非常先进的并发队列,例如ConcurrentLinkedQueue

回答by Brian Agnew

Looking at your example, I think ArrayBlockingQueue(or its siblings) may be of use. They look after the synchronisation for you, so threads can write to the queue or peek/take without additional synchronisation work on your part.

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

回答by Brian Agnew

Let's take a normal list (implemented by the ArrayList class) and make it synchronized. This is shown in the SynchronizedListExample class. We pass the Collections.synchronizedList method a new ArrayList of Strings. The method returns a synchronized List of Strings. //Here is SynchronizedArrayList class

让我们采用一个普通列表(由 ArrayList 类实现)并使其同步。这显示在 SynchronizedListExample 类中。我们向 Collections.synchronizedList 方法传递一个新的字符串数组列表。该方法返回一个同步的字符串列表。//这里是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());
            }
        }    
    }
}

Notice that when iterating over the list, this access is still done using a synchronized block that locks on the synchronizedList object. In general, iterating over a synchronized collection should be done in a synchronized block

请注意,在对列表进行迭代时,此访问仍使用锁定 synchronizedList 对象的同步块完成。通常,迭代同步集合应该在同步块中完成