简体   繁体   English

在java中同步ArrayList的正确方法

[英]Correct way to synchronize ArrayList in java

I'm not sure if this is the correct way to synchronize my ArrayList . 我不确定这是否是同步我的ArrayList的正确方法。

I have an ArrayList in_queue which is passed in from the registerInQueue function. 我有一个ArrayList in_queue ,它是从registerInQueue函数传入的。

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_queue object 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);
    }
}

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) ,你正在使用synchronized (in_queue_list)进行synchronized (in_queue_list)在这种情况下使用Collections.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. 但是,由于您正在完全清空列表,因此迭代删除第一个元素是最糟糕的方法,每个元素的sice必须复制所有后续元素,这使得这是一个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 (eg 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()只是无用的额外开销。

Looking at your example, I think ArrayBlockingQueue (or its siblings) may be of use. 看看你的例子,我认为ArrayBlockingQueue (或它的兄弟姐妹)可能有用。 They look after the synchronisation for you, so threads can write to the queue or peek/take without additional synchronisation work on your part. 他们会为您管理同步,因此线程可以写入队列或查看/获取,而无需您进行额外的同步工作。

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()

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. 我的猜测是你只想要安全的队列和出列操作,所以你可以删除synchronized块。

However, there are far advanced concurrent queues in Java such as ConcurrentLinkedQueue 但是,Java中有很多高级并发队列,例如ConcurrentLinkedQueue

Let's take a normal list (implemented by the ArrayList class) and make it synchronized. 让我们采用一个普通的列表(由ArrayList类实现)并使其同步。 This is shown in the SynchronizedListExample class. 这显示在SynchronizedListExample类中。 We pass the Collections.synchronizedList method a new ArrayList of Strings. 我们传递Collections.synchronizedList方法一个新的字符串ArrayList。 The method returns a synchronized List of Strings. 该方法返回一个同步的字符串列表。 //Here is SynchronizedArrayList class //这是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 kumarmanoj.mtech@gmail.com
* 
*/
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. 请注意,在遍历列表时,仍然使用锁定synchronizedList对象的synchronized块完成此访问。 In general, iterating over a synchronized collection should be done in a synchronized block 通常,迭代同步集合应该在同步块中完成

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM