vla*_*lka 3 java multithreading arraylist
我有一个ArrayList,用于缓冲数据,以便其他线程可以读取它们
这个数组不断添加数据,因为它从udp源读取,而其他线程不断从该数组读取.然后从数组中删除数据.
这不是实际的代码,而是一个简化的例子:
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);
}
}
Run Code Online (Sandbox Code Playgroud)
remove()方法从数组中删除数据包,然后将右侧的所有数据包移到左侧以覆盖空白.
我担心的是:由于缓冲区经常被多个线程添加和读取,因此remove()方法会产生问题,因为它必须将数据包移到左边?
我的意思是如果.add()或.get()方法在该arraylist上被调用,同时正在进行转换会是一个问题吗?
我有时会得到索引超出范围的异常,它的类似于:index:100 size 300,这是奇怪的cuz索引在大小范围内,所以我想知道这是否可能导致问题或我应该寻找其他问题 .
谢谢
这听起来像你真正想要的是一个BlockingQueue.ArrayBlockingQueue可能是个不错的选择.如果您需要一个无界的队列而不关心额外的内存利用率(相对于ArrayBlockingQueue),LinkedBlockingQueue也可以.
它允许您以线程安全且高效的方式将项目推入并弹出.那些推送和弹出的行为可能有所不同(当你试图推送到一个完整的队列时会发生什么,或者从一个空队列弹出?),并且BlockingQueue接口的JavaDocs 有一个表格可以很好地显示所有这些行为.
线程安全List(无论它来自synchronizedList或来自CopyOnWriteArrayList)实际上是不够的,因为您的用例使用经典的check-then-act模式,而且本质上是活泼的.请考虑以下代码段:
if(!list.isEmpty()) {
Packet p = list.remove(0); // remove the first item
process(p);
}
Run Code Online (Sandbox Code Playgroud)
即使list是线程安全的,这种用法也不是!如果list在"if"检查期间有一个元素,但是在你到达之前另一个线程将其删除,该remove(0)怎么办?
你可以通过同步两个动作来解决这个问题:
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!
}
Run Code Online (Sandbox Code Playgroud)
但这样效率较低,需要的代码多于a BlockingQueue,因此没有理由这样做.