Java 如何创建同步数组列表

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/3814325/
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-14 05:24:34  来源:igfitidea点击:

how to create Synchronized arraylist

javamultithreadingsynchronization

提问by Lalchand

i have created synchronized arrayList like this

我已经创建了这样的同步 arrayList

import java.text.SimpleDateFormat;
import java.util.*;


class HelloThread  
{

 int i=1;
 List arrayList;
  public  void go()
  {
 arrayList=Collections.synchronizedList(new ArrayList());
 Thread thread1=new Thread(new Runnable() {

  public void run() {
  while(i<=10)
  {
   arrayList.add(i);
   i++;
  }
  }
 });
 thread1.start();
 Thread thred2=new Thread(new Runnable() {
  public void run() {
     while(true)
     {
   Iterator it=arrayList.iterator();
      while(it.hasNext())
      {
       System.out.println(it.next());
      }
     }
  }
 });
 thred2.start();
  }
 }

public class test
{
  public static void main(String[] args)
  {
   HelloThread hello=new HelloThread();
   hello.go();
  }
}

but getting exception like this

但得到这样的异常

Exception in thread "Thread-1" java.util.ConcurrentModificationException

线程“Thread-1”中的异常 java.util.ConcurrentModificationException

anything wrong in my approach ?

我的方法有什么问题吗?

采纳答案by axtavt

Iteratorof synchronizedListis not (and can't be) synchronized, you need to synchronize on the list manually while iterating (see javadoc):

IteratorofsynchronizedList不是(也不能)同步,您需要在迭代时手动同步列表(请参阅javadoc):

synchronized(arrayList) {
    Iterator it=arrayList.iterator(); 
    while(it.hasNext()) { 
        System.out.println(it.next()); 
   } 
}

Another approach is to use a CopyOnWriteArrayListinstead of Collections.synchronizedList(). It implements a copy-on-write semantic and therefore doesn't require synchronization.

另一种方法是使用 aCopyOnWriteArrayList而不是Collections.synchronizedList()。它实现了写时复制语义,因此不需要同步。

回答by Spike Gronim

You may not modify a Collection that you are iterating. You can work around this by accessing the array entries by index, not through an Iterator. I can provide more advice if you tell me the problem that you are trying to solve with this code.

您不能修改正在迭代的集合。您可以通过按索引访问数组条目来解决此问题,而不是通过迭代器。如果您告诉我您尝试使用此代码解决的问题,我可以提供更多建议。

回答by Bart van Heukelom

As Spike said, you can't modify a collection while iterating it. However, I think the solution is to lock the list while iterating.

正如 Spike 所说,您不能在迭代时修改集合。但是,我认为解决方案是在迭代时锁定列表。

class HelloThread  
{

 int i=1;
 List arrayList;
  public  void go()
  {
 arrayList=Collections.synchronizedList(new ArrayList());
 Thread thread1=new Thread(new Runnable() {

  public void run() {
  while(i<=10)
  {
synchronized(someLock) {
   arrayList.add(i);
}
   i++;
  }
  }
 });
 thread1.start();
 Thread thred2=new Thread(new Runnable() {
  public void run() {
     while(true)
     {
synchronized(someLock) {
   Iterator it=arrayList.iterator();
      while(it.hasNext())
      {
       System.out.println(it.next());
      }
}
     }
  }
 });
 thred2.start();
  }
 }

public class test
{
  public static void main(String[] args)
  {
   HelloThread hello=new HelloThread();
   hello.go();
  }
}

I'm not sure what you're trying to do, so I hope this doesn't break the functionality of your code.

我不确定您要做什么,所以我希望这不会破坏您代码的功能。

回答by stacker

The java.util.ConcurrentModificationException occurs when you manipulate (add,remove) a collection while iterating over the same collection.

java.util.ConcurrentModificationException 当您在迭代同一集合时操作(添加、删除)集合时发生。

You probably want to consume the create entries in your second thread while after they have been created by your first thread. So you could use ArrayLists get( index )and size()for control

您可能希望在第一个线程创建后使用第二个线程中的创建条目。所以你可以使用 ArrayListsget( index )和 size()进行控制

回答by dogbane

Consider using a CopyOnWriteArrayListwhich is thread-safe. Every time you add an item, a fresh copy of the underlying array is created. However, the iterator will not reflect additions to the list since the iterator was created, but is guaranteed not to throw ConcurrentModificationException.

考虑使用线程安全的CopyOnWriteArrayList。每次添加项目时,都会创建底层数组的新副本。但是,迭代器不会反映自创建迭代器以来对列表的添加,但保证不会 throw ConcurrentModificationException

arrayList=new CopyOnWriteArrayList();

回答by Stephen C

Other answers have identified the problem:

其他答案已经确定了问题:

  • The iterators for synchronized collections are not synchronized. In fact, they are simply the iterators returned by the collection objects inside the wrapper classes.

  • Many collection classes (including ArrayList) use a fail-fast mechanism to detect concurrent modifications during iteration. This behavior is clearly documented in the javadocs for the respective classes. This is what you are seeing.

  • 同步集合的迭代器不同步。事实上,它们只是包装类中的集合对象返回的迭代器。

  • 许多集合类(包括ArrayList)使用快速失败机制来检测迭代期间的并发修改。此行为在相应类的 javadoc 中有明确记录。这就是你所看到的。

Not all collection classes do this. For example, many of the java.util.Concurrent...collection classes allow concurrent modification during iteration, but relax the semantics of the iteration sequence so that the results of the modifications may or may notbe apparent in the objects returned by the iterator.

并非所有集合类都这样做。例如,许多java.util.Concurrent...集合类允许在迭代期间进行并发修改,但放宽了迭代序列的语义,以便修改的结果在迭代器返回的对象中可能会也可能不会很明显。

The javadoc for the Collections.synchronizedList()explains how to synchronize the iterator. Basically you do this:

的 javadocCollections.synchronizedList()解释了如何同步迭代器。基本上你这样做:

List list = Collections.synchronizedList(new ArrayList());
  ...
synchronized (list) {
    Iterator i = list.iterator(); // Must be in synchronized block
    while (i.hasNext())
        foo(i.next());
}

(Aside: normally it is not safe to assume that doing something like this would work. In theory, the synchronized list could use a private lock object, and the synchronizedstatement would not lock out concurrent modifications. However the javadocs say that this is what to do in this case ... so it is safe.)

(旁白:通常假设做这样的事情会起作用是不安全的。理论上,同步列表可以使用私有锁对象,并且该synchronized语句不会锁定并发修改。但是 javadocs 说这是什么在这种情况下做......所以它是安全的。)

The problem with doing that is that locking the collection creates a potential concurrency bottleneck. The alternative to is to use a copy-on-write data structure that internally makes a copy of the relevant parts of the collection. This approach means that an iterator sees sees a snapshot of the collection. Modifications may be made to the collection concurrent with an iteration, but the iterator does not see them. The problem with copy-on-write is that modifications are potentially a lot more expensive.

这样做的问题是锁定集合会造成潜在的并发瓶颈。另一种方法是使用写时复制数据结构,该结构在内部制作集合相关部分的副本。这种方法意味着迭代器看到的是集合的快照。可以在迭代的同时对集合进行修改,但迭代器看不到它们。写时复制的问题在于修改可能要贵得多。

Ultimately, you need to balance the characteristics and costs of the different collection types wrt concurrent modification versus your actual requirements. Can you get away with the iterator not seeing all concurrent modifications?

最终,您需要在并发修改与您的实际需求之间平衡不同集合类型的特性和成本。你能摆脱迭代器看不到所有并发修改的问题吗?

回答by Stephen C

Let's take a normal list (implemented by the ArrayList class) and make it synchronized. This is shown in the SynchronizedArrayList class. We pass the Collections.synchronizedList method a new ArrayList of Strings. The method returns a synchronized List of Strings. //Here is SynchronizedArrayList class 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) {

让我们采用一个普通列表(由 ArrayList 类实现)并使其同步。这显示在 SynchronizedArrayList 类中。我们向 Collections.synchronizedList 方法传递一个新的字符串数组列表。该方法返回一个同步的字符串列表。//这里是SynchronizedArrayList类包com.mnas.technology.automation.utility; 导入 java.util.ArrayList; 导入 java.util.Collections; 导入 java.util.Iterator; 导入 java.util.List; 导入 org.apache.log4j.Logger; /** * * @author manoj.kumar * @email [email protected] * */ public class SynchronizedArrayList { static Logger log = Logger.getLogger(SynchronizedArrayList.class.getName()); 公共静态无效主(字符串 [] 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