同步Java Canvas实例的paint方法?

问题描述

基本上,我以60 FPS运行Java模拟器,并且每次刷新屏幕时,它都会从数组绘制像素并将其绘制到屏幕上。我收到java.util.ConcurrentModificationException,即在paint()方法执行期间的某个时候,像素数组的内容修改了。有没有一种方法可以同步paint方法generatePalette方法来避免这种情况?还是有另一种/更好的解决方案?

代码

public class LCD extends Canvas implements Runnable {
    
    /**
     * 
     */
    private static final long serialVersionUID = 1L;
    private static final int FRAME_RATE = 1 / 60 * 1000;
    private BufferedImage canvas;
    private List<Pixel> pixels = new ArrayList<>();
    private int tilemapStart,tilemapEnd;
    private GBcpuBootRom cpu;
    private GBBus bus;
    
    public void init() {
        setTileMap(bus.cpuRUnsigned8(0xFF40));
        generatePalette(bus,bus.cpuRUnsigned8(0xFF40));
    }
    
    public LCD(int len,int hei,GBcpuBootRom cpu,GBBus bus) {
        canvas = new BufferedImage(len,hei,BufferedImage.TYPE_INT_ARGB);
        this.cpu =  cpu;
        this.bus = bus;
        Thread t = new Thread(this);
        t.start();
    }
    
    public void setTileMapExplicit(int start,int end) {
        tilemapStart = start;
        tilemapEnd = end;
    }
    
    public void setTileMap(int mFF40) {
        /*
         * Bit 3 (bit 5)
         * 0: 9800 to 9BFF
         * 1: 9C00 to 9FFF
         * 
         * Bit 4 (bit 4)
         * 0: 8800 to 97FF
         * 1: 8000 to 8FFF
         */
        
        if ( ((mFF40 & 0b00001000) >> 3) == 1) {
            tilemapStart = 0x9C00;
            tilemapEnd = 0xA000;
        }
        else {
            tilemapStart = 0x9800;
            tilemapEnd = 0x9C00;
        }
    }
    
    public void paint(Graphics g) {
        for(Pixel p:pixels) 
            try {
                canvas.setRGB(p.getX(),p.getY(),p.getColor().getRGB());
            }
            catch(Exception e) {
                /*
                 * If a pixel cannot be drawn
                 * skip it and move on to next.
                 */
                System.out.println("Cannot draw pixel: " + p.getX() + "," +
                    p.getY());
            }
        draw(g);
    }
    
    private void draw(Graphics g) {
        Graphics2D g2 = (Graphics2D) g;
        g2.drawImage(canvas,null,null);
    }
    
    public void generatePalette(GBBus bus,int mFF40)  {
        int hor = 0;
        int ver = 0;
        int x = 0;
        int y = 0;
        int inc = 8;
        int pixelCount = 0;
        
        /*
         * maxRowPixels
         * Each tile has 64 pixels
         * if 256 x 256 
         *      maxRowPixels = 2048 (32 * 64)
         * else if 160 x 144
         *      maxRowPixels = 1280 (20 * 64)
         */
        int maxRowPixels = canvas.getWidth() == 256 ? 2048 : 1280;
        Pixel[] palettes;
        Palette palette = new Palette();
        
        for(int i = tilemapStart; i < tilemapEnd; i++) {
            int dataAddr = spriteAddress((mFF40 & 0b00010000) >> 4,bus.cpuRUnsigned8(i));
            /*
             * Read range 0 to F
             * e.g.
             * 08000: 08000 to 0x800F
             * 
             * 08000,08002,08004,08006,* 08008,0800A,0800C,0800D,*/
            for(int k = 0; k < 16; k = k + 2) {
                int hByte = bus.cpuRUnsigned8(dataAddr + k);
                int lByte = bus.cpuRUnsigned8(dataAddr + (k + 1));
                palette.setHB(hByte);
                palette.setLB(lByte);
                palette.setXY(x,y);
                palette.init();
                palettes = palette.getPixels();
                for(Pixel pix: palettes)
                    pixels.add(pix);
                
                x += inc;
                pixelCount += inc;
                
                if(x % 8 == 0) {
                    x = hor;
                    y++;
                }
                
                /*
                 * 1 tile completed
                 * 8 x 8 = 64p
                 * p means pixels   
                 */
                if(pixelCount % 64 == 0) {
                    hor = hor + inc;
                    x = hor;
                    y = ver;
                }
                
                if(pixelCount % maxRowPixels == 0) {
                    x = 0;
                    hor = 0;
                    ver = ver + inc;
                    y = ver;
                }
            }
        }
    }

    @Override
    public void run() {
        Thread.currentThread();
        while(true) {
            cpu.compute();
            pixels.clear();
            init();
            try {
                Thread.sleep(1000);
            }
            catch(Exception e) {
                e.printstacktrace();
            }
            repaint();
        }
    }
        

}

这是我在第66行得到的异常(上述paint()方法中的for循环)

Exception in thread "AWT-EventQueue-0" java.util.ConcurrentModificationException
    at java.base/java.util.ArrayList$Itr.checkForComodification(ArrayList.java:1009)
    at java.base/java.util.ArrayList$Itr.next(ArrayList.java:963)
    at gameboyconcept.logo.LCD.paint(LCD.java:66)

解决方法

暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!

如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。

小编邮箱:dio#foxmail.com (将#修改为@)