我为ArrayList
获得了一个Index Out of Bounds异常。在异常点,print()和索引在打印时似乎很好。以下是相关代码。我有一个自定义表模型,单击一个按钮时会刷新。
public class CallingClass
{
public void buttonClicked()
{
new Thread(new Runnable()
{
public void run()
{
dataTableModel.refresh();
}
}).start();
}
}
public class DataTableModel extends AbstractTableModel
{
protected ArrayList<Object> data;
public DataTableModel()
{
data = new ArrayList<Object>();
}
public Object getValueAt(int modelRow, int modelColumn)
{
// Throws Index Out of Bounds Exception though a println here shows modelRow value within 0 to data.size()-1
// DataObject is just an interface to support getValue method
return ((DataObject) data.get(modelRow)).getValue();
}
public void refresh()
{
reloadData();
fireTableDataChanged();
}
protected void reloadData()
{
ArrayList<TextMessage> messageList = jmsConnection.getMessageList();
data.clear();
try
{
for(int i=0; i<messageList.size(); ++i)
{
data.add(new MyDataObject(messageList.get(i).getJMSMessageID()));
}
}
catch(Exception e)
{
}
}
}
正如您所看到的,DataTableModel.refresh()
在新线程中运行。对fireTableDataChanged
的调用可能导致eventQueue
线程重绘表,而表又调用getValueAt
方法。尽管modelRow
值小于data.size()
,但抛出异常。不确定如何存在竞争条件,因为Runnable线程在调用fireTableDataChanged
(重新填充数据对象)之后调用reloadData
。因此,当eventQueue线程调用data
时,getValueAt
对象应该是稳定的。另请注意,刷新按钮被禁用,直到可运行的线程出来,以避免重叠调用刷新。
以下是异常消息
Exception in thread "AWT-EventQueue-0" java.lang.IndexOutOfBoundsException: Index: 3, Size: 10
at java.util.ArrayList.rangeCheck(Unknown Source)
at java.util.ArrayList.get(Unknown Source)
at datatablemodels.DataTableModel.getValueAt(DataTableModel.java:70)
如果稍微更改reloadData代码,则异常消失(至少不可重现)。我的猜测是它只是减少异常的几率。
protected void reloadData()
{
ArrayList<TextMessage> messageList = jmsConnection.getMessageList();
ArrayList<Object> tempdata = new ArrayList<Object>();
try
{
for(int i=0; i<messageList.size(); ++i)
{
tempdata.add(new MyDataObject(messageList.get(i).getJMSMessageID()));
}
}
catch(Exception e)
{
}
data = tempdata ;
}
我更感兴趣的是了解这里发生了什么。我确实有其他解决方案,例如synchronized
,CopyOnWriteArrayList
等。
答案 0 :(得分:0)
由于没有同步,因此无法保证在refresh()方法中进行数据更改(在自己的线程中运行)在运行getValueAt()方法的其他线程中是否可见,如果有的话。例如,getValueAt()方法或其中的一部分可以在&#34;之间运行。 data.clear()调用reloadData()方法并重新填充数据表。
当你调用println()时,它们可能会在data.clear()调用之前或重新填充数据之后运行,即使data.get()调用没有。
最重要的是,只要数据被多个线程触及,就像在这里一样,您必须以某种方式同步对数据的访问。