我如何创建一个并发的列表实例,在那里我可以通过索引访问元素?JDK是否有我可以使用的类或工厂方法?
当前回答
CopyOnWriteArrayList是ArrayList的线程安全变体 所有可变操作(添加、设置等)都由 创建底层数组的新副本。
CopyOnWriteArrayList是同步列表实现列表接口的并发替代,它是java.util.concurrent包的一部分,它是线程安全的集合。
public class CopyOnWriteArrayList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable
CopyOnWriteArrayList是故障安全的,当底层的CopyOnWriteArrayList在迭代期间使用ArrayList的单独副本被修改时,不会抛出ConcurrentModificationException。
这通常代价太大,因为拷贝数组涉及每个更新操作,将创建一个克隆副本。CopyOnWriteArrayList是频繁读操作的最佳选择。
/**
* Returns a shallow copy of this list. (The elements themselves
* are not copied.)
*
* @return a clone of this list
*/
public Object clone() {
try {
@SuppressWarnings("unchecked")
CopyOnWriteArrayList<E> clone =
(CopyOnWriteArrayList<E>) super.clone();
clone.resetLock();
return clone;
} catch (CloneNotSupportedException e) {
// this shouldn't happen, since we are Cloneable
throw new InternalError();
}
}
http://gee.cs.oswego.edu/dl/classes/EDU/oswego/cs/dl/util/concurrent/CopyOnWriteArrayList.html https://docs.oracle.com/javase/9/docs/api/java/util/concurrent/CopyOnWriteArrayList.html https://www.logicbig.com/tutorials/core-java-tutorial/java-collections/concurrent-collection-cheatsheet.html
其他回答
大多数情况下,如果您需要并发列表,则它位于模型对象内部(因为您不应该使用抽象数据类型(如列表)来表示应用程序模型图中的节点),或者它是特定服务的一部分,您可以自己同步访问。
class MyClass {
List<MyType> myConcurrentList = new ArrayList<>();
void myMethod() {
synchronzied(myConcurrentList) {
doSomethingWithList;
}
}
}
通常这就足够让你继续下去了。如果你需要迭代,迭代列表的一个副本,而不是列表本身,并且只同步你复制列表的部分,而不是在你迭代它的时候。
另外,当并发处理一个列表时,通常要做的事情不仅仅是添加、删除或复制,这意味着该操作变得足够有意义,以保证它自己的方法,并且该列表成为一个特殊类的成员,仅表示这个具有线程安全行为的特定列表。
即使我同意需要一个并发列表实现和Vector / collections . synchronizelist (list)不做的技巧,你肯定需要像compareAndAdd或compareAndRemove或get(…, ifAbsentDo),即使您有ConcurrentList实现,开发人员在使用并发列表(和映射)时也经常会因为没有考虑真正的事务而引入错误。
在这些场景中,事务对于与并发ADT(抽象数据类型)交互的预期目的来说太小,总是导致我将列表隐藏在一个特殊的类中,并在方法级别上使用synchronized同步访问这个类对象方法。这是确保交易正确的唯一方法。
我已经看到了太多的错误,不能用其他方法来做——至少如果代码很重要,处理一些像金钱或安全或保证一些服务质量措施(例如至少发送一次且只发送一次消息)。
CopyOnWriteArrayList是ArrayList的线程安全变体 所有可变操作(添加、设置等)都由 创建底层数组的新副本。
CopyOnWriteArrayList是同步列表实现列表接口的并发替代,它是java.util.concurrent包的一部分,它是线程安全的集合。
public class CopyOnWriteArrayList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable
CopyOnWriteArrayList是故障安全的,当底层的CopyOnWriteArrayList在迭代期间使用ArrayList的单独副本被修改时,不会抛出ConcurrentModificationException。
这通常代价太大,因为拷贝数组涉及每个更新操作,将创建一个克隆副本。CopyOnWriteArrayList是频繁读操作的最佳选择。
/**
* Returns a shallow copy of this list. (The elements themselves
* are not copied.)
*
* @return a clone of this list
*/
public Object clone() {
try {
@SuppressWarnings("unchecked")
CopyOnWriteArrayList<E> clone =
(CopyOnWriteArrayList<E>) super.clone();
clone.resetLock();
return clone;
} catch (CloneNotSupportedException e) {
// this shouldn't happen, since we are Cloneable
throw new InternalError();
}
}
http://gee.cs.oswego.edu/dl/classes/EDU/oswego/cs/dl/util/concurrent/CopyOnWriteArrayList.html https://docs.oracle.com/javase/9/docs/api/java/util/concurrent/CopyOnWriteArrayList.html https://www.logicbig.com/tutorials/core-java-tutorial/java-collections/concurrent-collection-cheatsheet.html
ConcurrentLinkedQueue
如果您不关心是否具有基于索引的访问,而只想要List的插入顺序保持特性,那么可以考虑java.util.concurrent.ConcurrentLinkedQueue。因为它实现了Iterable,一旦你添加完所有的项,你可以使用增强的for语法循环内容:
Queue<String> globalQueue = new ConcurrentLinkedQueue<String>();
//Multiple threads can safely call globalQueue.add()...
for (String href : globalQueue) {
//do something with href
}
免责声明:这个答案发表于2011年,在JDK 5之前,也在更高级和最优的并发api之前。因此,虽然下面的方法可以工作,但它不是最好的选择。
如果你需要的只是简单的调用同步,你可以很好地使用Collections.synchronizedList(List):
List<Object> objList = Collections.synchronizedList(new ArrayList<Object>());
在java.util.concurrent中有一个并发列表实现。特别是CopyOnWriteArrayList。
推荐文章
- 返回大列表中每n项的python方式
- 使用Enum实现单例(Java)
- RabbitMQ与通道和连接之间的关系
- buildSessionFactory()配置方法在Hibernate中已弃用?
- Spring MVC -如何获得所有的请求参数在一个地图在Spring控制器?
- 如何在Java中按两个字段排序?
- 文件之间的差异。路径中的分隔符和斜杠
- Python:查找列表中的元素
- 在方法参数中使用NotNull注释
- Spring MVC中处理可选参数的@RequestParam
- Tomcat:如何查找正在运行的Tomcat版本?
- “java”、“javaw”和“javaws”之间有什么区别?
- 将Date对象转换为日历对象
- 在Java中保存最后N个元素的大小有限的队列
- 如何运行一个类从Jar不是主类在其清单文件