Совместное использование объекта и управление выполнением потока из основного потока

Я пытаюсь решить довольно простую задачу. У меня есть основной поток, который рисует кадр, и другой поток (FrameThread), который каждый раз подготавливает этот кадр. Оба потока должны совместно использовать один и тот же объект MyFrame. Я хочу управлять FrameThread из основного потока, то есть: MyFrame готов -> рисовать его в основном потоке -> поддерживать работу FrameThread. В настоящее время я сделал следующее:

private class FrameEngine
{
    private boolean isFrameReady = false;
    private MyFrame frame;

    public synchronized void generateFrame()
    {
        while(isFrameReady)
            wait();
        frame = FrameGenerator.nextFrame();
        isFrameReady = true;
        notifyAll();
    }

    public synchronized MyFrame getFrame()
    {
        while(!isFrameReady)   
            wait();
        isFrameReady = false;
        notifyAll();
        return frame;
    }
}    

После этого я создаю FrameThread:

private class FrameThread implements Runnable
{
    private final FrameEngine frame_eng;

    public FrameThread( FrameEngine engine )
    {
        frame_eng = engine;
    }
    @Override
    public void run()
    {
        while(true)
            frame_eng.generateFrame();
    }
}

И, наконец, основной поток:

FrameEngine frame_engine = new FrameEngine();
Thread frameThread = new Thread( new FrameThread( frame_engine ) );
frameThread.start();
...
while(true)
{
    ...
    drawFrame( frame_engine.getFrame() ); 
    ...
}

Итак, моя цель: FrameThread выполняется в фоновом режиме и останавливается сразу после того, как кадр готов. Я очень новичок в Java, и я чувствую, что есть гораздо лучший и безопасный способ добиться этого. Не могли бы вы дать мне совет по этому поводу? Спасибо.


person Kael    schedule 19.02.2012    source источник
comment
@HovercraftFullOfEels, вы правы, сэр.   -  person Juvanis    schedule 19.02.2012
comment
@Kael: ваш код кажется мне необычным, но я не эксперт по многопоточности. Является ли ваша программа графическим интерфейсом? Это java.awt.Frame? Если да, то почему бы не использовать Swing и javax.swing.JFrames? Если с графическим интерфейсом рассмотрите возможность использования SwingWorkers. И если вы не получите достойных ответов в ближайшее время, рассмотрите возможность предоставления более подробной информации, если это возможно.   -  person Hovercraft Full Of Eels    schedule 19.02.2012
comment
@Hovercraft Full Of Eels: я думаю, мне следует переименовать его. Это просто чистая Java, без дополнительных фреймворков.   -  person Kael    schedule 19.02.2012
comment
@Kael: спасибо за это разъяснение. Меня (и, возможно, других) всегда смущает, когда люди используют имена классов, которые уже имеют аналоги в основной библиотеке Java, и я рекомендую людям по возможности избегать этого.   -  person Hovercraft Full Of Eels    schedule 19.02.2012


Ответы (1)


Это классическая проблема производителя-потребителя. Я предлагаю вам избегать использования wait() и notify(), потому что их сложно сделать правильно даже опытным разработчикам.

Вместо этого ознакомьтесь с интерфейсом BlockingQueue и используйте пример в комментариях в качестве руководства. Кажется, это именно то, что вы ищете.

Если требуется, чтобы заранее генерировалось не более одного кадра, используйте ArrayBlockingQueue с емкостью 1.

Я также должен упомянуть, что как в вашем примере, так и в примере с BlockingQueue в приведенной выше ссылке семантика закрытия потоков производителя и потребителя не объясняется. Вам нужно будет добавить механизм остановки, иначе ваша программа не закроется сама по себе, даже после того, как основной поток умер.

person Nate    schedule 25.04.2012