我制作动画。我生成了一堆图像,我想将它们添加到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 :(得分:1)
您可以使用ExecutorService
ExecutorService es = Executors.newSingleThreadExecutor();
es.submit(() -> encoder.start("MyFile.gif"));
es.submit(() -> encoder.addFrame(img));
答案 1 :(得分:1)
关于您的第一个想法
您的MyThread
课程不是主题。它只是一个名为run()
和addFrame(...)
的方法的类。当程序执行以下命令时,将在新线程中调用run方法:
MyThread myThread = new MyThread();
new Thread(myThread).start();
但是,如果您的主线程稍后调用myThread.addFrame(...)
,那么主线程中会发生。您不能编写在另一个线程中调用方法的代码。方法调用发生在执行调用的线程中。总是
关于您的第二个想法
你是对的。这是重量级的。创建新线程非常昂贵。这就是发明线程池的一个原因。 (参见Peter Lawrey的回答)发明线程池的另一个原因是让程序管理在任何给定时间工作的线程数。没有什么能阻止你的第二个例子中的主线程创建一百个新的工作线程,或一万个,或者......一个接一个地。
使用线程池,线程与它们所做的工作分离。您可以为线程池提供一万个作业,但它可能只使用十个线程来完成它们。取决于线程池的配置方式。
Peter Lawrey的示例中的一个配置为仅使用一个工作线程。
java.util.concurrent.Executors
类的其他方法将为您创建不同配置的线程池,或者您可以通过显式构建和配置java.util.concurrent.ThreadPoolExecutor
实例来配置更复杂的内容。