Java 这个简单的基于Swing的类是线程安全的吗?

Java 这个简单的基于Swing的类是线程安全的吗?,java,swing,thread-safety,Java,Swing,Thread Safety,我正在用Java制作一个概念验证游戏,并决定(为了练习,但主要是为了好玩)制作我自己的带有线程安全双缓冲的简单组件。然而,在并发性方面(特别是关于Swing),我不是很有经验,我想知道我的实现中是否有我没有的问题 执行情况如下: import java.awt.Graphics; import java.awt.image.BufferedImage; import javax.swing.JPanel; public class GamePanel extends JPanel {

我正在用Java制作一个概念验证游戏,并决定(为了练习,但主要是为了好玩)制作我自己的带有线程安全双缓冲的简单组件。然而,在并发性方面(特别是关于Swing),我不是很有经验,我想知道我的实现中是否有我没有的问题

执行情况如下:

import java.awt.Graphics;
import java.awt.image.BufferedImage;

import javax.swing.JPanel;

public class GamePanel extends JPanel
{

    private static final long serialVersionUID = 1L;

    private BufferedImage mBackImage = null;
    private BufferedImage mFrontImage = null;

    public BufferedImage getBackImage ()
    {
        return mBackImage;
    }

    public void swap ()
    {
        BufferedImage new_back;
        //
        synchronized (this)
        {
            new_back = mFrontImage;
            mFrontImage = mBackImage;
        }
        //
        int width = getWidth (), height = getHeight ();
        if (width > 0 && height > 0)
        {
            if (new_back == null || new_back.getWidth () != width
                    || new_back.getHeight () != height)
                new_back = new BufferedImage (width, height,
                        BufferedImage.TYPE_INT_ARGB);
            //
            mBackImage = new_back;
        }
        else
            mBackImage = null;
    }

    @Override
    public void paintComponent (Graphics g)
    {
        synchronized (this)
        {
            if (mFrontImage == null)
                super.paintComponent (g);
            else
                g.drawImage (mFrontImage, 0, 0, null);
        }
    }

}
我假设
getBackImage()
swap()
将仅由单个线程(游戏循环线程)调用。油漆通过摆动计时器触发,因此在EDT中。我相信围绕使用
mFrontImage
的简单同步块应该足以防止不必要的行为,允许游戏循环线程渲染到后面的图像并调用swap,而不必担心Swing重画。我遗漏了什么吗?

  • Swing是纯单线程的,所有事件都必须在EDT上完成,所以我看不出同步的原因(这个)

  • 在中用于dispaying

  • 对于任何
    交换类型
    ,您都可以查看

游戏线程中:

BufferedImage image = gamePanel.getBackPanel();
gamePanel.swap();
您的程序现在将处于事件调度队列和游戏线程可以访问相同映像的状态。这意味着,如果您在EDT将图像绘制到屏幕的同时绘制图像,则可以将有趣的东西绘制到面板上

为了自己读取和写入frontImage字段,那么您是线程安全的,因为所有访问都是在同步块内完成的。但是,可以更好地编写paintComponent方法,以减少在同步块中花费的时间。即:

@Override
public void paintComponent (Graphics g)
{
    BufferedImage localFrontImage;
    synchronized (this)
    {
        localFrontImage = mFrontImage;
    }
    if (localFrontImage == null)
        super.paintComponent (g);
    else
        g.drawImage (localFrontImage, 0, 0, null);

}

没有同步的可能场景?:1)EDT调用的绘制,
mFrontImage!=null
2)游戏循环线程调用
swap
mBackImage==null
时,
mFrontImage
现在为null 3)EDT调用
g.drawImage
mFrontImage==null
应该考虑到这一点。非常感谢。我想解决这个问题的简单方法是只有一个映像,并锁定对它的读写操作,但它不再是非常并发的…但是。。。只要在调用
getBackImage
swap
(并且只对返回的图像)之间完成所有绘制,那么一切都应该正常,是吗?也许在午夜尝试并发是个坏主意;)