Java制作列表线程的副本安全吗?

时间:2017-06-23 18:49:09

标签: java multithreading list concurrency

我在Java应用程序中运行多个线程,并且所有线程都需要访问同一个列表。但是,只有一个线程实际上需要插入/删除/更改列表,而其他线程只需要访问它。

在其他线程中,我希望在需要读取它时为我创建一个列表副本,但有没有办法以线程安全的方式执行此操作?如果我有一个方法来按元素复制列表元素并且列表发生了变化,那么它会搞砸它不会吗?

编辑:

列表不会经常删除,如果我只是正常复制并捕获异常,它会起作用吗?如果列表在副本中间增长并且我错过了它,那么它对功能的影响不会很大

6 个答案:

答案 0 :(得分:3)

您可以将CopyOnWriteArrayList用于您的目的。

CopyOnWriteArrayList是Java 5 Concurrency API中引入的并发Collection类及其在Java中的流行表兄ConcurrentHashMap

  

顾名思义,CopyOnWriteArrayList创建底层副本   具有每个突变操作的ArrayList,例如添加或设置。一般   CopyOnWriteArrayList非常昂贵,因为它涉及昂贵   每次写入操作的数组副本,但如果你的话,它非常有效   有一个列表,其中迭代次数超过变异,例如你最需要的   迭代ArrayList并且不要经常修改它。

使用此集合,您不应每次都创建新实例。你应该只有一个这样的对象,它会起作用。

答案 1 :(得分:1)

嗯,所以我认为你想要的是 CopyOnWriteArrayList

  

CopyOnWriteArrayList - ArrayList的线程安全变体,其中所有可变操作(添加,设置等)都是通过创建底层数组的新副本来实现的。

参考:CopyOnWriteArrayList

答案 2 :(得分:0)

您可以使用线程安全的CopyOnWriteArrayList,但它会在每次更新过程中创建新的。{/ p>

或者您可以使用readWriteLock,因此当更新使用时,没有人可以读取多个线程可以同时读取。

答案 3 :(得分:0)

根据您的具体用法,您可能会受益于以下其中一种:

  1. 如果您不需要随机访问,请使用ConcurrentLinkedQueue
  2. 如果您不需要随机访问写入(并且您很可能不会或者您将像疯了一样复制内存块)但只需要它进行读取,请使用ConcurrentLinkedQueue进行写入操作如果对队列进行了更改(在单独的线程中),则不时将其复制到列表中,将此列表提供给读者"。
  3. 由于您的写入来自一个线程,前一个可以使用2个列表(例如,写入线程会将其复制到"读取视图"不时)。但是,请注意,如果您使用ArrayList实现并且需要随机访问写入,那么您正在查看内存区域的常量副本,即使没有过多的同步也不会很好。
  4. 改为使用地图,ConcurrentHashMap如果您不关心订购并想要O(1)性能,或者ConcurrentSkipListMap如果您确实需要订购并且可以使用O(logN)性能

答案 4 :(得分:0)

我决定通过一个处理线程的单独线程来解决这个问题,如果他们想要写入列表,或者从列表中获取,则BlockingQueue用于其他线程提交。如果他们想要写入列表,它将提交一个包含他们想要写的内容的对象,如果他们想要阅读,它将提交一个Future,该列表中的线程将填充

答案 5 :(得分:-1)

console.log('Starting directory: ${process.cwd()}');
try {
  process.chdir('C:\Users\HalvorSD\node-party');
  console.log('New directory: ${process.cwd()}');
} catch (err) {
  console.error('chdir: ${err}');
}

示例:

Use Collections.synchronizedList().