问题描述
限时送ChatGPT账号..我有一个 ArrayList 用于缓冲数据,以便其他线程可以读取它们
i have an ArrayList that's used to buffer data so that other threads can read them
这个数组不断地有数据添加到它,因为它从一个 udp 源读取,其他线程不断地从那个数组中读取.然后从数组中删除数据.
this array constantly has data added to it since it's reading from a udp source, and the other threads constantly reading from that array.Then the data is removed from the array.
这不是实际的代码,而是一个简化的例子:
this is not the actual code but a simplified example :
public class PacketReader implements Runnable{
pubic static ArrayList<Packet> buffer = new ArrayList() ;
@Override
public void run(){
while(bActive){
//read from udp source and add data to the array
}
}
public class Player implements Runnable(){
@Override
public void run(){
//read packet from buffer
//decode packets
// now for the problem :
PacketReader.buffer.remove(the packet that's been read);
}
}
remove() 方法从数组中移除数据包,然后将所有右侧的数据包向左移动以覆盖空白.
The remove() method removes packets from the array and then shifts all the packets on the right to the left to cover the void.
我担心的是:由于缓冲区不断地被多个线程添加和读取,remove() 方法是否会产生问题,因为它必须将数据包向左移动?
My concern is : since the buffer is constantly being added to and read from by multiple threads , would the remove() method make issues since its gonna have to shift packets to the left?
我的意思是,如果在该数组列表上调用 .add() 或 .get() 方法,同时进行转换会不会有问题?
i mean if .add() or .get() methods get called on that arraylist at the same time that shift is being done would it be a problem ?
我有时确实会得到索引越界异常,它类似于:索引:100 大小 300,这很奇怪,因为索引在大小范围内,所以我想知道这是否可能导致问题,或者我应该寻找其他问题.
i do get index out of bounds exception sometimes and its something like : index : 100 size 300 , which is strange cuz index is within size , so i want to know if this is what may possibly be causing the problem or should i look for other problems .
谢谢
推荐答案
听起来您真正想要的是 BlockingQueue
.ArrayBlockingQueue
可能是个不错的选择.如果你需要一个无界队列并且不关心额外的内存使用(相对于ArrayBlockingQueue
),LinkedBlockingQueue
也有效.
It sounds like what you really want is a BlockingQueue
. ArrayBlockingQueue
is probably a good choice. If you need an unbounded queue and don't care about extra memory utilization (relative to ArrayBlockingQueue
), LinkedBlockingQueue
also works.
它允许您以线程安全且高效的方式将项目推入和弹出.这些推送和弹出的行为可能不同(当您尝试推送到一个完整队列或从一个空队列弹出时会发生什么?),并且 BlockingQueue
接口的 JavaDocs 有一个表格显示所有这些行为都很好.
It lets you push items in and pop them out, in a thread-safe and efficient way. The behavior of those pushes and pops can differ (what happens when you try to push to a full queue, or pop from an empty one?), and the JavaDocs for the BlockingQueue
interface have a table that shows all of these behaviors nicely.
线程安全的List
(无论它来自synchronizedList
还是CopyOnWriteArrayList
)实际上还不够,因为您的用例使用经典的检查然后行动模式,这本质上是活泼的.考虑这个片段:
A thread-safe List
(regardless of whether it comes from synchronizedList
or CopyOnWriteArrayList
) isn't actually enough, because your use case uses a classic check-then-act pattern, and that's inherently racy. Consider this snippet:
if(!list.isEmpty()) {
Packet p = list.remove(0); // remove the first item
process(p);
}
即使 list
是线程安全的,这种用法也不是!如果 list
在if"检查期间有一个元素,但在你到达 remove(0)
之前另一个线程将其删除怎么办?
Even if list
is thread-safe, this usage is not! What if list
has one element during the "if" check, but then another thread removes it before you get to remove(0)
?
您可以通过同步两个操作来解决这个问题:
You can get around this by synchronizing around both actions:
Pattern p;
synchronized (list) {
if (list.isEmpty()) {
p = null;
} else {
p = list.remove(0);
}
}
if (p != null) {
process(p); // we don't want to call process(..) while still synchronized!
}
不过,与 BlockingQueue
相比,这效率较低且需要更多代码,因此没有理由这样做.
This is less efficient and takes more code than a BlockingQueue
, though, so there's no reason to do it.
这篇关于多个线程访问一个 ArrayList的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!
更多推荐
[db:关键词]
发布评论