2015-12-03 4 views
0

Я делаю анимацию. Я создаю кучу изображений, и я хочу добавить их в gif-кодер. Поскольку процесс добавления может занять некоторое время, я хочу, чтобы это было сделано в отдельном потоке. Моя идея была бы сделать это:Выполнить методы в потоке

public class MyThread implements Runnable { 

    private AnimatedGifEncoder encoder = new AnimatedGifEncoder(); 

    public void run() { 
     encoder.start("MyFile.gif"); 
    } 

    public void addFrame(BufferedImage img) { 
     encoder.add(img); 
    } 

} 

Тогда я бы назвал метод addFrame() из основного класса каждый раз, когда кадр должен быть добавлен. Однако, когда я подумал об этом, я пришел к выводу, что это не так, как это работает.

Другая идея состоит в том, чтобы создать новый объект потока каждый раз добавляется кадр:

public class MyMainClass { 
    while (generating) { 
     BufferedImage img = generateImg(); 

     new Thread(() -> { 
      encoder.addFrame(img); 
     }).start(); 
    } 
} 

Однако, мне это кажется очень тяжелым способом, чтобы сделать это.

Мой вопрос: Что такое лучший способ достичь этого? Если этого не происходит, идея создания нового объекта Thread действительно тяжелая?

+0

О вашей первой идее: ваш класс 'MyThread' - это _not_ нить. Это просто класс с методами с именем 'run()' и 'addFrame (...)'. Когда ваша программа выполняет 'новый поток (myThread).start() ', новый поток будет вызывать' myThread.run() '. И если ваш основной поток позже вызывает 'myThread.addFrame (...)', ну, это происходит в основном потоке_ и _not_ в новом потоке. –

+0

@jameslarge Я забыл указать, что я это сделаю. В любом случае, спасибо за то, что он не сработает! – Creator13

ответ

1

Вы можете использовать ExecutorService

ExecutorService es = Executors.newSingleThreadExecutor(); 

es.submit(() -> encoder.start("MyFile.gif")); 

es.submit(() -> encoder.addFrame(img)); 
+0

@BeyelerStudios Благодарим вас за исправление. –

1

О ваших первых идеях

Вашего MyThread класса не поток. Это просто класс с методами run() и addFrame(...). Когда ваша программа выполняет следующие действия, метод запуска будет называться в новом потоке:

MyThread myThread = new MyThread(); 
new Thread(myThread).start(); 

Но, если ваш основной поток позже вызывает myThread.addFrame(...), что происходит в основном потоке. Вы не можете написать код, который вызывает метод в другом потоке. Вызов метода происходит в потоке, который выполняет вызов. Всегда.

О вашей второй идее

Вы правы. Это тяжелый вес. Создание новых потоков дорого. Это одна из причин, почему были изобретены пулы потоков. (См. Ответ Питера Лори)

Другая причина, по которой были созданы пулы потоков, - позволить вашей программе управлять количеством потоков, выполняющих работу в любой момент времени. Ничто не останавливает основной поток в вашем втором примере от создания сотни новых рабочих потоков, или десять тысяч, или ... Один за другим.

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

В примере, приведенном в примере Питера Лоури, используется только один рабочий поток.

Другие методы класса java.util.concurrent.Executors создадут для вас различные профилированные пулы потоков, или вы можете сконфигурировать что-то еще более сложное, явно создав и сконфигурировав экземпляр java.util.concurrent.ThreadPoolExecutor.

+0

Большое спасибо за дополнительное объяснение. Еще один вопрос: вы говорите, что все действия выполняются в одном рабочем потоке. Означает ли это, что каждая заданная работа выполняется один за другим, в том порядке, в котором они представлены? – Creator13

+0

@ Creator13, Да. Пул потоков имеет блокирующую очередь для задач и имеет некоторое (возможно, переменное) количество рабочих потоков. Рабочие потоки петли навсегда, выбирая задачи из очереди и запуская их. Если очередь пуста, рабочие блокируются до тех пор, пока не будут добавлены дополнительные задачи. Причудливый пул потоков (например, «ThreadPoolExecutor») может убить некоторых работников, если очередь пуста достаточно долго или добавить некоторых работников, если очередь слишком длинна слишком долго. Тот, который возвращается «Executors.newSingleThreadExecutor()», имеет только одного работника, который выполняет задачи строго в том порядке, в котором они были добавлены. –

Смежные вопросы