返回 Java 数组与集合
我正在尝试思考关于 java 应用程序中的内存分配和多线程的一些设计,这就是我想知道的:
我有一个具有同步集合的类,比如说一个每秒更新多次的列表,但是所有更新都发生在类及其自己的线程内,而不是来自其他线程。但是,我还有许多其他线程调用 getCollection() 方法并执行 foreach 以只读方式迭代其内容。这是我不知道的:
如果另一个线程正在迭代同步集合,执行更新的单个线程是否必须等到没有其他线程迭代的时间点?
我的第二个问题是,通过执行 .toArray 返回集合的数组副本而不是集合本身似乎是有意义的,但从内存的角度考虑,是否必须分配一个大小为新的数组每次都会检查集合内容,如果每秒在包含数千个对象的集合上被调用数百次,我不知道是否有意义。
另外,如果我从不返回集合本身,那么不再需要使列表同步?
将不胜感激任何意见。谢谢! - 邓肯
I'm trying to think through some design in regards to memory allocation and multithreading in a java app and this is what I'm wondering:
I have a class that has a synchronized Collection say a list that is getting updated several times a a second but all updates are happening within the class and its own thread not from other threads. However I have many other threads that call the getCollection() method and do a foreach to iterate its contents in a read only fashion. This is what I don't know:
If another thread is iterating the synchronized colletion will the single thread that performs the updates have to wait until a point in time when no other threads are iterating?
My second question is it seems to make sense to return an array copy of the collection not the collection itself by doing .toArray but from thinking about it from a memory point of view won't that have to allocate a new array that is the size of the collection contents everytime and if getting called hundreds of times a second on a collection that has several thousand objects in it is something I don't know makes sense or not.
Also if I never return the collection itself than making the list synchronized is no longer necessary?
Would appreciate any input. Thanks! - Duncan
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
如果您谈论的是同步(非并发)集合,那么是的。
至于第二个问题,
看起来像是 java.util.concurrent.CopyOnWriteArrayList 的真实用例。
If you're talking about synchronized (not concurrent) collections then yes.
As for the second question, it
looks like a real use case for
java.util.concurrent.CopyOnWriteArrayList
.我建议您使用 CopyOnWriteArrayList。这是线程安全的,可以被任意数量的线程高效地读取访问。如果您有少量更新,这应该没问题。
不过还是要回答一下你的问题。如果在修改同步集合时对它进行迭代,您将得到 ConcurrentModificationException(COWAL 没有得到这个)。您的更新不会因此被阻止,只有您的读者会遇到问题。
您不必在每次调用 getCollection 时创建一个副本,而是在每次修改集合时创建一个副本(频率要低得多),这就是 COWAL 为您所做的事情。
如果您按需返回副本,您仍然需要同步集合。
I would suggest you use the CopyOnWriteArrayList. This is thread safe and can be read accessed efficient by any number of threads. Provided you have a small number of updates this should be fine.
However, to answer your questions. If you iterator over a synchronized collection while it is being modifed, you will get a ConcurrentModificationException (COWAL doesn't get this) Your update will not be blocked by this, only your readers will have a problem.
Instead of creating a copy each time getCollection is called, youc an create a copy each time the collection is modifed (far less often) This is what COWAL does for you.
If you return a copy on demand, you will still need to synchronize the collection.
处理这个问题最简单的方法可能是保留两个集合:一个由类本身更新,另一个是调用
getCollection()
时返回的易失性字段中的只读副本。后者需要通过在适当时更新主集合的过程来重新创建。这允许您自动更新集合:一次性更改多个元素,同时隐藏中间状态。
如果您的更新不频繁,并且每次更新都会使集合保持一致状态,那么请使用已经建议的 CopyOnWriteArrayList。
Probably the easiest way to deal with this is to keep two collections: one that is updated by the class itself, and a read-only copy in a volatile field that is returned when
getCollection()
is called.The latter needs to be recreated by the process that updates the main collection when appropiate. This allows you to atomically update your collection: change several elements in one go, while hiding the intermediate states.
If your updates are infrequent and every update leaves the collection in a consistent state, then use the CopyOnWriteArrayList already suggested.
看起来集合正在频繁更新,并且 #getCollection() 被频繁调用。您可以使用 CopyOnWriteArrayList,但每次修改数组时都会创建一个副本。因此,您需要了解这对性能有何影响。
另一种选择是让类中的线程在每次调用 #getCollection 时进行复制。这将涉及 #getCollection 等待内部类线程完成。
如果您只想 #getCollection 返回最近的副本而不是最新的副本,那么您可以让内部线程定期创建在 #getCollection 中返回的集合的副本。该副本需要是易失性的或者是 AtomicReference。
It seems that the collections is being updated frequently and #getCollection() is being called frequently. You could use CopyOnWriteArrayList but you'll creating a copy every time you modify the array. So you'll need to see how this effects performance.
Another option is to task the thread within the class to make a copy everytime #getCollection is called. This will involve #getCollection waiting for the internal class thread to complete.
If you just want #getCollection to return a recent copy and not the most up to date copy then you can have the internal thread periodically create a copy of the collection that gets returned in #getCollection. The copy will need to be volatile or be an AtomicReference.