如果我在线程中运行它会出现异常,但如果没有线程它似乎不会出现。如何修复它以使其没有错误。
线程“AWT- EventQueue -0”中的异常 java.lang.IndexOutOfBoundsException:索引:1,大小
:
0 MyListModel.getElementAt(MyListModel.java:31)
在 ta.MyListModel.getElementAt(MyListModel.java:1)
在 javax.swing.plaf.basic.BasicListUI.updateLayoutState(Unknown Source)
在 javax.swing.plaf.basic.BasicListUI。 maybeUpdateLayoutState(未知来源)
在 javax.swing.plaf.basic.BasicListUI.getPreferredSize(未知来源)
在 javax.swing.JComponent.getPreferredSize(未知来源)
在 javax.swing.ScrollPaneLayout.layoutContainer(未知来源)
在 java.awt.Container.layout(未知来源)
在 java.awt.Container.doLayout(未知来源)
在 java.awt.Container.validateTree(未知来源)
在 java.awt.Container.validate(未知来源)
在 javax .swing.RepaintManager$3.run(未知来源)
在 javax.swing.RepaintManager$3.run(未知来源)
在 java.security.AccessController.doPrivileged(本地方法)
在 java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(未知来源)
在 javax.swing.RepaintManager.validateInvalidComponents(未知来源)
在 javax.swing.RepaintManager$ProcessingRunnable.run(未知来源)
在 java.awt.event.InvocationEvent.dispatch(未知来源)
在 java.awt.EventQueue.dispatchEventImpl(未知来源)
在 java.awt.EventQueue.access$500(未知来源)
在 java.awt.EventQueue$3.run(未知来源)在 java.awt.EventQueue
$3.run(未知来源) 在
java.security.AccessController.doPrivileged(本机方法)未知来源) 在 java.awt.EventDispatchThread.pumpOneEventForFilters(未知来源) 在 java.awt.EventDispatchThread.pumpEventsForFilter(未知来源)
在 java.awt.EventDispatchThread.pumpEventsForHierarchy(未知来源)
在 java.awt.EventDispatchThread.pumpEvents(
未知来源)
在 java.awt.EventDispatchThread.pumpEvents(未知来源)
模型类
package ta;
import java.math.BigDecimal;
import java.util.LinkedList;
import javax.swing.AbstractListModel;
public class MyListModel extends AbstractListModel<String>{
private static final long serialVersionUID = 1L;
private LinkedList<BigDecimal> listBets;
public LinkedList<BigDecimal> getListBets() {
return listBets;
}
public void setListBets(LinkedList<BigDecimal> listBets) {
this.listBets = listBets;
}
public MyListModel(LinkedList<BigDecimal> list) {
setList(list);
}
public void add(BigDecimal value){
getList().add(value);
refresh();
}
public String getElementAt(int index) {
return String.format("%.8f", getList().get(index));
}
public int getSize() {
return getList().size();
}
public LinkedList<BigDecimal> getList(){
return listBets;
}
public void setList(LinkedList<BigDecimal> list){
this.listBets = list;
refresh();
}
public void clear() {
getList().clear();
refresh();
}
public void removeSide() {
getList().removeLast();
getList().removeFirst();
refresh();
}
void removeLast(){
getList().removeLast();
refresh();
}
public void refresh() {
fireContentsChanged(this, 0, getSize());
}
}
有主要方法的类
package ta;
import java.awt.EventQueue;
import javax.swing.JFrame;
import javax.swing.JPanel;
import java.awt.BorderLayout;
import java.awt.GridLayout;
import java.util.LinkedList;
import java.util.NoSuchElementException;
import java.util.Random;
import java.util.Scanner;
import javax.swing.JTextArea;
import javax.swing.JScrollPane;
import javax.swing.JList;
import javax.swing.JOptionPane;
import javax.swing.JButton;
import java.awt.event.ActionListener;
import java.math.BigDecimal;
import java.text.ParseException;
import java.awt.event.ActionEvent;
public class TA {
private JFrame frame;
private MyListModel listModelBets;
private JList<String> list;
private JTextArea textArea;
private final String defaultBets = "0.00000001\n0.00000001\n0.00000001\n0.00000001\n0.00000001";
private final boolean win = true;
private final boolean lose = false;
/**
* Launch the application.
*/
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
TA window = new TA();
window.frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
/**
* Create the application.
*/
public TA() {
listModelBets = new MyListModel(new LinkedList<>());
initialize();
}
/**
* Initialize the contents of the frame.
*/
private void initialize() {
frame = new JFrame();
frame.setBounds(100, 100, 450, 300);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().setLayout(new BorderLayout(0, 0));
JPanel panel_2 = new JPanel();
frame.getContentPane().add(panel_2);
panel_2.setLayout(new GridLayout(0, 2, 0, 0));
JPanel panel_1 = new JPanel();
panel_2.add(panel_1);
panel_1.setLayout(new BorderLayout(0, 0));
JScrollPane scrollPane = new JScrollPane();
panel_1.add(scrollPane);
textArea = new JTextArea(defaultBets);
scrollPane.setViewportView(textArea);
JPanel panel = new JPanel();
panel_2.add(panel);
panel.setLayout(new BorderLayout(0, 0));
JScrollPane scrollPane_1 = new JScrollPane();
panel.add(scrollPane_1);
list = new JList<String>(listModelBets);
scrollPane_1.setViewportView(list);
JPanel panel_3 = new JPanel();
frame.getContentPane().add(panel_3, BorderLayout.SOUTH);
JButton btnNewButton_1 = new JButton("Clear");
btnNewButton_1.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
listModelBets.clear();
}
});
panel_3.add(btnNewButton_1);
JButton btnPlay = new JButton("Play");
btnPlay.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
Thread th = new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 1000; i++) {
boolean result = play();
if (result) {
if (listModelBets.getSize() == 1) {
listModelBets.removeLast();
} else if (listModelBets.getSize() > 1) {
listModelBets.removeSide();
}
} else {
listModelBets.add(getBet());
}
}
}
});
th.start();
}
});
panel_3.add(btnPlay);
}
void addBets() {
Scanner sc = new Scanner(textArea.getText());
sc.useDelimiter("\\n");
while (sc.hasNext()) {
String s = sc.next();
if (s != null && !s.equals("")) {
try {
BigDecimal b = new BigDecimal(s);
listModelBets.add(b);
} catch (NumberFormatException ex) {
// JOptionPane.showMessageDialog(frame, "Enter number
// value.\nSample 0.00000001");
}
}
}
sc.close();
}
boolean play() {
Random rnd = new Random();
return rnd.nextBoolean();
}
BigDecimal getBet() {
BigDecimal sum = null;
if (listModelBets.getSize() > 0) {
sum = calcSum();
} else {
addBets();
sum = calcSum();
}
return sum;
}
BigDecimal calcSum() {
BigDecimal sum = null;
try {
BigDecimal first = listModelBets.getList().getFirst();
BigDecimal last = listModelBets.getList().getLast();
sum = first.add(last);
} catch (NoSuchElementException ex) {
// stopGame();
JOptionPane.showMessageDialog(frame, "Enter number value\nin editor bets.\nSample 0.00000001");
}
return sum;
}
}
您的问题是该模型
MyListModel不是线程安全的。但是您同时从不同的线程使用它。在获取列表大小和获取元素时,另一个线程设法删除了这些元素。因此,发生错误。
我看到了这个问题的几种解决方案:
制作一个模型
thread-safe,最简单的方法是LinkedList用包中的替代品替换它,java.util.concurrent或者声明synchronized。另一种解决方案是在一个线程中更改模型。因为 由于元素是从流中接收到的
UI,因此应该从中进行删除。这需要按如下方式完成删除操作: