我正在用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重绘。我错过了什么吗?
答案 0 :(得分:1)
Swing是纯单线程的,所有事件必须在EDT上完成,然后我看不到synchronized (this)
的原因
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);
}