Я новичок, пытаюсь написать программу, которая строит треугольник Серпинского методом хаоса. Все работает примерно до ~700 итерации, затем вываливаются ошибки.
import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.util.ArrayList; import java.util.List; import java.util.concurrent.CopyOnWriteArrayList; import javax.swing.*; import javax.swing.border.LineBorder; class PointDraw extends JFrame { int counter; static List<ColorPoint> points; static Color pointColor; static JSlider pointSize; static JSlider speedThread; static DrawingPane pane; List<Integer> massiveX = new CopyOnWriteArrayList<>(); List<Integer> massiveY = new CopyOnWriteArrayList<>(); JLabel jcounter = new JLabel(); void count() { String str; counter += 1; str = Integer.toString(counter); jcounter.setText(str); } StartGame startGame = new StartGame(); Thread thr = new Thread(startGame); PointDraw() { setTitle("Треугольник Серпинского"); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); points = new ArrayList<>(); pointColor = Color.BLACK; pane = new DrawingPane(); JPanel topPanel = new JPanel(); JButton colorButton = new JButton(); colorButton.setBackground(pointColor); colorButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { pointColor = JColorChooser.showDialog(PointDraw.this, "Выберите цвет:", pointColor); colorButton.setBackground(pointColor); } }); colorButton.setPreferredSize(new Dimension(40, 40)); pointSize = new JSlider(5, 20, 5); speedThread = new JSlider(1, 20, 1); JButton startButton = new JButton("Старт"); startButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { if (massiveX.size() < 4) { JOptionPane.showMessageDialog(null, "Задайте необходимое количество точек!", "Ахтунг!", JOptionPane.WARNING_MESSAGE); } else { thr.start(); } } }); JButton stopButton = new JButton("Стоп"); stopButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { startGame.mystop(); points.clear(); pane.repaint(); massiveX.clear(); massiveY.clear(); } }); JButton pauseButton = new JButton("Пауза"); pauseButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { startGame.mysuspended(); } }); JButton continueButton = new JButton("Продолжить"); continueButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { startGame.myresume(); } }); topPanel.add(new JLabel("Цвет:")); topPanel.add(colorButton); topPanel.add(new JLabel("Размер точки:")); topPanel.add(pointSize); topPanel.add(new JLabel("Скорость:")); topPanel.add(speedThread); topPanel.add(startButton); topPanel.add(stopButton); topPanel.add(pauseButton); topPanel.add(continueButton); topPanel.add(new JLabel("Кол-во точек:")); topPanel.add(jcounter); add(pane); add(topPanel, BorderLayout.NORTH); pack(); } public static void main(String[] args) { new PointDraw().setVisible(true); } class DrawingPane extends JComponent { public DrawingPane() { setPreferredSize(new Dimension(1200, 400)); setBorder(new LineBorder(Color.GRAY)); addMouseListener(new MouseAdapter() { @Override public void mouseClicked(MouseEvent e) { if (points.size() < 4) { ColorPoint point = new ColorPoint(e.getX(), e.getY(), pointSize.getValue(), pointColor); points.add(point); massiveX.add(e.getX()); massiveY.add(e.getY()); } else { JOptionPane.showMessageDialog(null, "Нельзя создавать больше 4-х точек!", "Ахтунг!", JOptionPane.WARNING_MESSAGE); } repaint(); } }); } @Override protected void paintComponent(Graphics g) { super.paintComponent(g); Graphics2D g2 = (Graphics2D) g; g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); for (ColorPoint p : points) { g2.setColor(p.getColor()); int x = p.getX(); int y = p.getY(); int size = p.getSize(); g2.fillOval(x - size / 2, y - size / 2, size, size); } } } static class ColorPoint { private int x; private int y; private int size; private Color color; public ColorPoint(int x, int y, int size, Color color) { this.x = x; this.y = y; this.size = size; this.color = color; } public int getX() { return x; } public int getY() { return y; } public Color getColor() { return color; } public int getSize() { return size; } } static class RandomPoint { int min; int max; static int rnd(int min, int max) { max -= min; return (int) (Math.random() * ++max) + min; } } class StartGame extends JComponent implements Runnable { volatile boolean suspended; volatile boolean stopped; synchronized void mysuspended() { suspended = true; } synchronized void myresume() { suspended = false; notify(); } synchronized void mystop() { stopped = true; } StartGame() { suspended = false; stopped = false; } @Override public void run() { int n_point_x; int n_point_y; try { for (int i = 0; i < 50000; i++) { count(); synchronized (this) { while (suspended) { JOptionPane.showMessageDialog(null, "Поток поставлен на паузу!", "Ахтунг!", JOptionPane.WARNING_MESSAGE); wait(); } if (stopped) break; } int next_point = RandomPoint.rnd(0, 2); n_point_x = (massiveX.get(3) + massiveX.get(next_point)) / 2; n_point_y = (massiveY.get(3) + massiveY.get(next_point)) / 2; massiveX.remove(3); massiveY.remove(3); massiveX.add(n_point_x); massiveY.add(n_point_y); PointDraw.ColorPoint point = new PointDraw.ColorPoint(n_point_x, n_point_y, PointDraw.pointSize.getValue(), PointDraw.pointColor); PointDraw.points.add(point); PointDraw.pane.repaint(); Thread.sleep(PointDraw.speedThread.getValue() * 50); } } catch (InterruptedException ex) { ex.printStackTrace(); } JOptionPane.showMessageDialog(null, "Программа закончила свою работу!", "Ахтунг!", JOptionPane.WARNING_MESSAGE); } } }
Лог:
Exception in thread "AWT-EventQueue-0" java.util.ConcurrentModificationException at java.base/java.util.ArrayList$Itr.checkForComodification(ArrayList.java:1042) at java.base/java.util.ArrayList$Itr.next(ArrayList.java:996) at Homework.PointDraw$DrawingPane.paintComponent(PointDraw.java:149) at java.desktop/javax.swing.JComponent.paint(JComponent.java:1074) at java.desktop/javax.swing.JComponent.paintChildren(JComponent.java:907) at java.desktop/javax.swing.JComponent.paint(JComponent.java:1083) at java.desktop/javax.swing.JComponent.paintToOffscreen(JComponent.java:5255) at java.desktop/javax.swing.RepaintManager$PaintManager.paintDoubleBufferedImpl(RepaintManager.java:1643) at java.desktop/javax.swing.RepaintManager$PaintManager.paintDoubleBuffered(RepaintManager.java:1618) at java.desktop/javax.swing.RepaintManager$PaintManager.paint(RepaintManager.java:1556) at java.desktop/javax.swing.RepaintManager.paint(RepaintManager.java:1323) at java.desktop/javax.swing.JComponent._paintImmediately(JComponent.java:5203) at java.desktop/javax.swing.JComponent.paintImmediately(JComponent.java:5013) at java.desktop/javax.swing.RepaintManager$4.run(RepaintManager.java:865) at java.desktop/javax.swing.RepaintManager$4.run(RepaintManager.java:848) at java.base/java.security.AccessController.doPrivileged(AccessController.java:389) at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:85) at java.desktop/javax.swing.RepaintManager.paintDirtyRegions(RepaintManager.java:848) at java.desktop/javax.swing.RepaintManager.paintDirtyRegions(RepaintManager.java:823) at java.desktop/javax.swing.RepaintManager.prePaintDirtyRegions(RepaintManager.java:772) at java.desktop/javax.swing.RepaintManager$ProcessingRunnable.run(RepaintManager.java:1884) at java.desktop/java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:313) at java.desktop/java.awt.EventQueue.dispatchEventImpl(EventQueue.java:770) at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:721) at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:715) at java.base/java.security.AccessController.doPrivileged(AccessController.java:389) at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:85) at java.desktop/java.awt.EventQueue.dispatchEvent(EventQueue.java:740) at java.desktop/java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:203) at java.desktop/java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:124) at java.desktop/java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:113) at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:109) at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:101) at java.desktop/java.awt.EventDispatchThread.run(EventDispatchThread.java:90)
Предполагаю, что проблема в методе repaint(), который находится в цикле...
ЧТО Я ДЕЛАЮ НЕ ТАК? :)