在我的Java应用程序中,我有一个Runnable,例如:
this.runner = new Runnable({
@Override
public void run() {
// do something that takes roughly 5 seconds.
}
});
我大约需要每30秒(尽管这可能有所不同)在单独的线程中运行一次。代码的性质使我可以运行它,而不必理会它(无论成功还是失败)。我在我的应用程序中按以下一行代码执行以下操作:
(new Thread(this.runner)).start()
现在,这很好。但是,我想知道每个线程实例完成运行后是否应该进行某种清理?我正在VisualVM
中对该应用程序进行CPU性能分析,并且可以看到,在1小时的运行时间过程中,正在创建许多线程。这种担忧有效吗?还是一切正常?
我启动new Thread
而不是简单地将this.runner
定义为Thread
的原因是,有时我需要同时运行两次两次this.runner
(在第一次运行调用结束之前) ,如果我将this.runner
定义为Thread
,我将无法执行此操作,因为单个Thread
对象只能在初始执行完成后才能再次运行。
答案 0 :(得分:2)
使用后需要“清理”或“关闭”的Java对象通常会实现AutoCloseable
接口。这使得使用try-with-resources进行清理变得容易。 Thread
类未实现AutoCloseable
,并且没有“ close”或“ dispose”方法。因此,您无需进行任何显式清理。
但是
(new Thread(this.runner)).start()
不能保证立即开始计算Runnable
。您可能不在乎它是成功还是失败,但是我想您 do 根本不在乎它是否运行。您可能希望限制同时运行的这些任务的数量。例如,您可能只希望一次运行。因此,您可能想要join()
线程(或者也许是join with a timeout)。加入线程将确保线程将完成其计算。以超时方式加入线程会增加该线程开始计算的机会(因为当前线程将被挂起,从而释放可能运行另一个线程的CPU)。
但是,不建议创建多个线程来执行常规或频繁任务。您应该将submit任务添加到thread pool中。这样一来,您就可以控制最大的并发量,并为您提供其他好处(例如,优先处理不同的任务),并分摊expense of creating threads。
您可以配置线程池以使用固定长度( bounded )任务队列,并在队列已满时导致向execute submitted tasks itself themselves提交线程。这样,您可以保证(最终)执行提交给线程池的任务。 ThreadPool.execute(Runnable)
的文档说了
在将来的某个时间执行给定的任务
这表明该实现可以保证最终将运行所有已提交的任务 ,即使您不执行这些特定任务来确保已执行提交的任务。
答案 1 :(得分:1)
我建议您查看并发API。有许多通用的预定义方法。通过使用ExecutorService,您可以在将任务提交给执行者之后调用shutdown方法,该执行者停止接受新任务,等待先前提交的任务执行,然后终止执行者。 简短介绍: https://www.baeldung.com/java-executor-service-tutorial