Java:大型集合和并发线程

Posted

技术标签:

【中文标题】Java:大型集合和并发线程【英文标题】:Java: Large collection and concurrent threads 【发布时间】:2009-12-18 06:58:05 【问题描述】:

我正面临这个问题: 我有很多线程(1024)访问一个大型集合 - 向量。 问题: 有没有可能做一些事情来让我在它上面做并发操作而不必同步所有东西(因为这需要时间)?我的意思是,类似于 mysql 数据库的工作,您不必担心同步和线程安全问题。 Java中有类似的集合吗?谢谢

【问题讨论】:

为什么会有1024个线程?这太疯狂了。 我有 8 个核心 CPU 和 8 GB RAM,并且有 3000 个用户访问我的应用程序,所以我认为这没关系,不是吗? @Mark:不一定,只是并发度很高。但是,8 核 1024 线程可能过多。 我建议给自己一份 Java Concurrency in Practice 等等...这些线程是否将您的 Vector 视为队列? 【参考方案1】:

Vector 是一个非常古老的 Java 类 - 早于 Collections API。它在每个操作上同步,所以你不会有任何运气试图加快它。 您应该考虑重新编写代码以使用 ConcurrentHashMap 或 LinkedBlockingQueue 之类的东西,它们针对并发访问进行了高度优化。

如果不这样做,您提到您希望性能和访问语义类似于数据库 - 为什么不使用专用数据库或消息队列?他们可能会比您更好地实现它,而且您编写的代码更少!

[编辑] 鉴于您的评论:

all what thread does is adding elements to vector 
(only if num of elements in vector = 0) & 
removing elements from vector. (if vector size > 0)

听起来很像您应该使用更像队列而不是列表的东西!大小为 1 的有界队列将为您提供这些语义 - 尽管我会质疑为什么如果那里已经有元素就不能添加元素。当您有数千个线程时,这似乎是一个非常低效的设计。

【讨论】:

【参考方案2】:

首先,这个设计听起来不太对劲。听起来您需要考虑使用适当的数据库而不是简单的数据结构,即使这意味着只使用诸如 HypersonicDB 的内存实例之类的东西。

但是,如果你坚持这样做,那么java.util.concurrent 包有许多高并发、非锁定的数据结构。其中一个可能适合您的目的(例如ConcurrentHashMap,如果您可以使用Map 而不是List

【讨论】:

-1:考虑到他对 Vector 使用的评论,我认为 Steven Schlansker 关于考虑队列的回答更合适。 如果您认为某个答案不好,您就投反对票,而不是因为您认为另一个答案更好。【参考方案3】:

看起来你正在实现生产者消费者模式,你应该谷歌“生产者消费者java”或看看the BlockingQueue interface

【讨论】:

【参考方案4】:

我同意 skaffman 关于查看 java.util.concurrent 的观点。

ConcurrentHashMap 具有很强的可扩展性。但是,对其的 size() 调用仅返回一个近似值。所以例如即使 !(vector 中的元素数量 = 0),您的应用也会偶尔向其中添加元素。

如果你想严格执行你给出的条件,除了同步之外别无他法。

我想您可以让您的用户线程在队列上发布一个可调用对象,并且只有一个线程处理突变,而不是大量的上下文切换。这将消除对集合进行同步的需要。用户线程可以等待 Future.get()。

只是一个想法。

【讨论】:

【参考方案5】:

如果您不想更改数据结构并且只有不频繁的写入,您还可以使用一个或多个ReentrantReadWriteLock 来同步访问。那么多个线程可以同时读取,但是当一个线程要写入时,所有读取都被阻塞,直到写入完成。

但是您应该检查所使用的数据结构是否适合该任务,或者多个 java.util 或 java.util.concurrent 类中的另一个是否更合适。顺便说一下,java.util.Vector 同步的。

【讨论】:

以上是关于Java:大型集合和并发线程的主要内容,如果未能解决你的问题,请参考以下文章

Java并发编程 - 多线程/并发面试题集合(持续更新)

Java并发编程 - 多线程/并发面试题集合(持续更新)

Java容器

Java线程与并发编程实践----额外的并发工具类

Java中的线程--并发库中的集合

Java并发编程:多线程环境中安全使用集合API(含代码)