2

У меня есть запланированная задача в моей программе, которая закрывает кадр по истечении заданного периода времени. Однако после выполнения задачи программа продолжает работать, как будто 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); 
    } 

} 

The лямбды, возможно, уже раздали, но это на самом деле Java 8.

Почему программа не останавливается после выполнения задачи была выполнена ?

+1

Вы должны вызвать' выключения() ' после выполнения всех задач, а не 'shutdownNow()'. Это соответствует [ExecutorSErvice API] (http://docs.oracle.com/javase/8/docs/api/java/util/concurrent /ExecutorService.html) –

+0

@HovercraftFullOfEels Ах, да, я знаю. Это не имеет значения. Не обращайте на это внимания :) Я отредактирую его там nyhoo ~ –

+0

Но вызов 'shutdown()' ** не ** не имеет значения, и ваш код ему нужен. –

ответ

7

ScheduledExecutorService поток пул, возвращенный Executors#newSingleThreadScheduledExecutor(), использует потоки не-демона. Пока вы не закрываете пул потоков, они все еще ожидают ожиданий. JVM не заканчивается, тогда как потоки не-демона живы.

Вы можете использовать перегруженный Executors#newSingleThreadScheduledExecutor(ThreadFactory) и предоставить свою собственную реализацию ThreadFactory, которая создает потоки демона. Обратите внимание, что это может привести к тому, что ваша задача может даже не работать, потому что JVM выйдет до запланированного времени задачи.

Сделайте то, что вы обнаружили и закрыли. Обратите внимание, что вы должны всегда закрывать его в безопасном месте, где операция не может потерпеть неудачу.

+0

Разочарование ... все еще нужно ждать 3 минуты, прежде чем я смогу принять это –

+0

Пока вы на нем, можете ли вы привести пример * где-то безопаснее *? –

+1

@OlaviMustanoja Это довольно сложно, не зная макета всего вашего приложения. Я переформулировал свой ответ. Я не знаю достаточно о swing (или программировании пользовательского интерфейса в целом). –

1

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); 
    } 
+1

Обратите внимание, что это может привести к тому, что ваша задача может даже не работать, поскольку JVM будет закрыта до запланированного времени задачи. –

+0

@SotiriosDelimanolis Справедливая точка. Это не представляет интереса, когда программа не делает ничего вне программы (например, файл IO, подключения к базе данных и т. Д.) –

0

я бы подойти к этому совершенно по-разному. Вы указываете:

У меня есть запланированная задача в моей программе, которая закрывает кадр после определенного периода времени.

Почему бы не использовать таймер Swing для этого, поскольку он был создан для хорошей работы с потоком событий Swing?

new Timer(1000, new ActionListener() { 

    public void actionPerformed(ActionEvent e) { 
     ((Timer) e.getSource()).stop(); 
     someWindow.dispose();   
    } 

}).start(); 
+0

Я действительно сделал это после публикации моего вопроса. Однако я решил не редактировать свой пост, потому что меня равномерно интересовала причина, по которой «ScheduledExecutorService» не позволяла программе заканчиваться после выполнения задачи. –

+0

Для меня это выглядит намного чище, если вы вызываете 'setRepeats (false)' в 'Timer' перед запуском, вместо того, чтобы позволить« остановить »таймер, например. 'Таймер t = новый таймер (1000, e-> someWindow.dispose()); t.setRepeats (ложный); t.start(); ' – Holger

0

Вы можете вызвать отключение от ScheduledExecutorService, как он будет ждать выполнения потока, а затем завершить пул потоков. Как вы можете видеть в Javadoc: «Инициирует упорядоченное завершение работы, в котором выполняются ранее поставленные задачи, но никаких новых задач не будет приниматься . Вызов не имеет дополнительного эффекта, если он уже выключен."

. Пример:

... 
scheduledExecutorService.schedule(runnable, delay, TimeUnit.MILLISECONDS); 
scheduledExecutorService.shutdown(); 
... 
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()); 
     } 
    } 

} 
Смежные вопросы