我的程序中有一个计划任务,在给定的一段时间后关闭一个帧。但是,在执行任务之后,程序将继续运行,就像ScheduledExecutorService
仍在另一个线程上运行一样。
这是我的代码的相关部分:
int delay = 1000;
ScheduledExecutorService ex = Executors.newSingleThreadScheduledExecutor();
ex.schedule(() -> {
System.out.println("executed");
getWindow().closeWindow();
// ex.shutdown();
}, delay, TimeUnit.MILLISECONDS);
此处任务在1秒延迟后执行,"执行"打印一次,框架关闭,程序即使在此代码后仍然运行。如果我取消注释ex.shutdownNow();
,程序将按预期成功结束。但是,我无法弄清楚为什么会这样。我也没能从互联网的其他部分找到任何东西。
MCVE:
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
public class Main {
public static void main(String[] args) {
int delay = 1000;
ScheduledExecutorService ex = Executors.newSingleThreadScheduledExecutor();
ex.schedule(() -> {
System.out.println("executed");
// ex.shutdown();
}, delay, TimeUnit.MILLISECONDS);
}
}
lambdas可能已经放弃了,但这确实是Java 8。
为什么程序在任务执行后没有停止?
答案 0 :(得分:9)
ScheduledExecutorService
返回的Executors#newSingleThreadScheduledExecutor()
线程池使用非守护程序线程。在关闭线程池之前,这些仍在等待任务。当非守护程序线程处于活动状态时,JVM不会结束。
您可以使用重载的Executors#newSingleThreadScheduledExecutor(ThreadFactory)
并提供自己的ThreadFactory
实现来创建守护程序线程。请注意,这可能会导致您的任务甚至无法运行,因为JVM会在任务的预定时间之前退出。
当你发现并关闭它时。请注意,您应该将其永远关闭在安全的地方,操作不会失败。
答案 1 :(得分:4)
The Java Virtual Machine runs until all threads that are not daemon threads have died。并且Executors.defaultThreadFactory()
将每个新线程创建为非守护程序线程。但是,如果你想在那个方向冒险,那么Executors.newSingleThreadScheduledExecutor();
会超载ThreadFactory
作为参数。
public static void main(String[] args) {
int delay = 1000;
class DaemonFactory implements ThreadFactory
{
@Override
public Thread newThread(Runnable r)
{
Thread t = new Thread(r);
t.setDaemon(true);
return t;
}
}
ThreadFactory tf = new DaemonFactory();
ScheduledExecutorService ex = Executors.newSingleThreadScheduledExecutor(tf);
ex.schedule(() -> {
System.out.println("executed");
}, delay, TimeUnit.MILLISECONDS);
}
答案 2 :(得分:0)
我会完全不同地接近这一点。你说:
我的程序中有一个计划任务,在一段时间后关闭一个帧。
为什么不为此使用Swing Timer,因为这是为了与Swing事件线程配合使用?
new Timer(1000, new ActionListener() {
public void actionPerformed(ActionEvent e) {
((Timer) e.getSource()).stop();
someWindow.dispose();
}
}).start();
答案 3 :(得分:0)
您可以从ScheduledExecutorService调用shutdown,因为它将等待线程执行,然后完成线程池。正如您在Javadoc中看到的那样:"启动一个有序关闭,其中先前提交的任务被执行,但没有新的任务将 被接受。如果已经关闭,调用没有其他影响。"
示例:
...
scheduledExecutorService.schedule(runnable, delay, TimeUnit.MILLISECONDS);
scheduledExecutorService.shutdown();
...
答案 4 :(得分:0)
我从onCreate()启动调度程序并在onDestroy()方法中停止它以停止调度程序服务。
public MyActivity extends Activity
{
ScheduledExecutorService scheduledExecutorService;
ScheduledFuture<?> scheduledFuture;
private int apiThreshold = 10;//seconds
onCreate()
{
startScheduler();
}
onDestroy()
{
if (scheduledFuture != null)
{
stopScheduler();
}
shutDownService();
super.onDestroy();
}
public void startScheduler() {
Debug.e(TAG, "inside start scheduler");
scheduledExecutorService = Executors.newScheduledThreadPool(1);
scheduledFuture = scheduledExecutorService.scheduleAtFixedRate(new Runnable() {
@Override
public void run() {
// call method to do your task/perform your repeated task
}
}, 4, apiThreshold, TimeUnit.SECONDS);
}
public void shutDownService()
{
if (scheduledExecutorService != null) {
Log.e(“test,"in shutDown service close if not null");
scheduledExecutorService.shutdownNow(); // shutdown will allow the final iteration to finish
// executing where shutdownNow() will kill it immediately
Log.e(“test,"is service shutdown(true/false)=="+scheduledExecutorService.isShutdown());
}
}
}