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

时间:2012-02-21 21:47:16

标签: java swing thread-safety

我正在用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()只会被一个线程(游戏循环线程)调用。涂料通过Swing计时器触发,因此在EDT中。我相信使用mFrontImage的简单同步块应该足以防止不需要的行为,允许游戏循环线程渲染到后面的图像并调用交换而不用担心Swing重绘。我错过了什么吗?

2 个答案:

答案 0 :(得分:1)

  • Swing是纯单线程的,所有事件必须在EDT上完成,然后我看不到synchronized (this)的原因

  • Icon中使用JLabel发送Images in the Swing GUI

  • 对于swap's types中的任何一个
  • ,您已查看CardLayout

答案 1 :(得分:1)

在游戏主题中:

BufferedImage image = gamePanel.getBackPanel();
gamePanel.swap();

您的程序现在处于Event Dispatch Queue和游戏线程可以访问同一图像的状态。如果您在EDT将图像绘制到屏幕的同时绘制图像,则可以将有趣的事物绘制到面板上。

为了自己读取和写入frontImage字段,你就是线程安全的,因为所有访问都是在synchronized块内完成的。但是,可以更好地编写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);

}