Является ли этот простой класс на основе Swing потокобезопасным? - PullRequest
1 голос
/ 22 февраля 2012

Я делаю пробную игру на 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 должно быть достаточно для защиты от нежелательного поведения, позволяя потоку игрового цикла визуализировать заднее изображение и вызывать swap, не беспокоясь о перерисовках Swing.Я что-то упустил?

Ответы [ 2 ]

1 голос
/ 22 февраля 2012

В игровой теме:

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 голос
/ 22 февраля 2012
...