Java 在线程中运行方法

Java 在线程中运行方法,java,multithreading,Java,Multithreading,我正在制作动画。我正在生成一组图像,我想将它们添加到gif编码器中。由于添加过程可能需要相当长的时间,我希望这是在一个单独的线程中完成。我的想法是这样做: public class MyThread implements Runnable { private AnimatedGifEncoder encoder = new AnimatedGifEncoder(); public void run() { encoder.start("MyFile.gif")

我正在制作动画。我正在生成一组图像,我想将它们添加到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();
    }
}
然而,对我来说,这似乎是一个非常沉重的方式来做到这一点


我的问题:实现这一目标的更好方法是什么?如果没有,那么创建一个新的
线程
对象的想法真的有那么重吗?

您可以使用ExecutorService

ExecutorService es = Executors.newSingleThreadExecutor();

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

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

关于你的第一个想法

您的
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
实例来配置更复杂的东西。

关于您的第一个想法:您的
MyThread
类不是线程。它只是一个名为
run()
addFrame(…)
的类。当程序执行新线程(myThread).start()
时,新线程将调用
myThread.run()
。如果您的主线程以后调用了
myThread.addFrame(…)
,那么,这种情况发生在主线程中,而不是在新线程中。@jameslarge我忘记指定了,我会这样做。无论如何,谢谢你确认它不会起作用!谢谢你的额外解释。还有一个问题:您说所有操作都在一个工作线程中完成。这是否意味着每个作业都会按照提交的顺序一个接一个地执行?@Creator13,是的。线程池有一个任务阻塞队列,它有一些(可能是可变的)工作线程数。工作线程永远循环,从队列中挑选任务并运行它们。如果队列变空,工人将被阻止,直到添加更多任务。一个奇特的线程池(例如,
ThreadPoolExecutor
)可能会在队列足够长的时间内为空时杀死一些工作线程,或者在队列太长时间内为空时添加一些工作线程。
Executors.newSingleThreadExecutor()
返回的工作线程只有一个严格按照添加顺序执行任务的工作线程。