Java Paint 'stuttering' -列表并发

标签 java multithreading arraylist concurrency paintevent

我的一个应用程序通过读取数组列表将对象绘制到屏幕上:

简单代码摘要:

@Override
public synchronized void paintComponent(Graphics g) {
  for(Object gO:paintList) {
    g.drawImage( gO.getObjImage(), gO.getXLoc(), gO.getYLoc(), outer.getTransparent(), null);
  }
}

问题是每次用户单击鼠标时我都会添加更多对象,因此如果用户单击得足够快,我可能会导致程序绘画卡顿,因为它在写入时无法读取(arrayList 是同步的)。开发人员处理此并发问题的常见做法是什么?

编辑:这是调用重绘的代码:

byte ticks = 0;
    while(true) {
        currentTime = System.nanoTime();
        if(ticks == 25) {
            drawPanel.repaint();
            ticks = 0;
        } else if (ticks%5 == 0) {//if ticks is a multiple of 5 (5,10,15,...)
            drawPanel.operations();
            ticks++;
        } else if(ticks < 25) {
            ticks++;
        }
        try {
            /*
            Refer to: 'http://stackoverflow.com/questions/1036754/difference-between-wait-and-sleep'
            on differences between Thread.sleep() and wait()
            */
            wait(1);//old timings: (long)(refreshRate*1000)
        } catch (InterruptedException ex) {
            Logger.getLogger(DeathWish.class.getName()).log(Level.SEVERE, null, ex);
        }
        //Debugging
        //System.out.println(ticks);
        currentTime = System.nanoTime();

*其中操作()计算“可绘制”对象属性的变化,删除满足特定条件的对象并将新对象添加到绘制列表中。从逻辑上讲,添加和写入应该分开吗? 如果没有足够的信息,我可以发布操作()方法,但我尝试不发布大量代码,以便更容易解释。

最佳答案

我猜你在同步方面遇到了一些问题:

  • ArrayList是一个不同步实现的列表
  • 同步方法意味着一次只有 1 个线程可以访问该方法,但函数内的变量根本不同步

您想要的是暂时同步您的列表。

你可以做类似的事情:

@Override
public void paintComponent(Graphics g) {
  synchronized(paintList) {
    for(Object gO:paintList) {
      g.drawImage( gO.getObjImage(), gO.getXLoc(), gO.getYLoc(), outer.getTransparent(), null);
    }
  }
}

在代码中添加对象到你的列表中做一些相同的事情。

从这里编辑:

如果您想消除添加线程和绘制线程之间的所有并发问题,可以这样做:

在添加图像的方法中:

public synchronized void addImage(...) {
  Something newImage = .....
  List<Something> newPaintList = new ArrayList<>(paintList.size() + 1);
  newPaintList.addAll(paintList);
  newPaintList.add(newImage);
  paintList = newPaintList;
}

并在paint方法中,删除同步部分。

@Override
public void paintComponent(Graphics g) {
  for(Object gO:paintList) {
    g.drawImage( gO.getObjImage(), gO.getXLoc(), gO.getYLoc(), outer.getTransparent(), null);
  }
}

这样,读取和写入之间就不会出现任何并发,因为对 PaintList 执行的唯一操作就是读取。

addImage应该同步以避免两个不同的线程同时添加图像,这可能会导致一个addImage被忽略。

关于Java Paint 'stuttering' -列表并发,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26183287/

相关文章:

java - 如何使用两个泛型获取参数化类型的类实例

Javadoc 错误 : "option --boot-class-path not allowed with target 11"

Android:无法从线程获取 Imei

java - 为什么一个对象在线程中初始化并从 main 访问时有时为 null?

php - ArrayList() 的 SilverStripe 随机顺序

android - 如何将选项添加到 Android 中现有微调器的顶部

java - twitter4j 是否提供在 2 个日期之间搜索推文的功能

java - Autowiring 错误 Spring

c# - 我需要在 ManualResetEvent 上调用 Close() 吗?

java - 尝试上传文件,数组有问题