ScheduledExecutorService - 程序在一次性操作后不会结束

时间:2014-12-10 02:29:56

标签: java multithreading scheduled-tasks java-8 scheduledexecutorservice

我的程序中有一个计划任务,在给定的一段时间后关闭一个帧。但是,在执行任务之后,程序将继续运行,就像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。

为什么程序在任务执行后没有停止?

5 个答案:

答案 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());
        }
    }

 }