2014-01-19 4 views
0

Я пытаюсь закончить ExecutorService executorService.shutdown();, и если это не сработало, с executorService.shutdown();. Проблема заключается в том, что execerService не может быть остановлен и программа все еще работает.Не удается остановить ExecutorService

Вот мой класс, который должен начать WatchService смотреть каталог изменений:

public class FileWatcher { 
    /** 
    * This Class starts a WatchService to get changes on a specific folder. 
    */ 

    Path dir; 

    private final ConfigManager configManager; 

    private final FileHandler fileHandler; 

    private ExecutorService executorService; 

    public FileWatcher(ConfigManager configManager, FileHandler fileHandler) { 
     this.configManager = configManager; 
     this.fileHandler = fileHandler; 
    } 

    public void start() { 
     dir = configManager.getConfig().getJdfPath(); 

     //executorService = Executors.newFixedThreadPool(1); 
     executorService = Executors.newSingleThreadExecutor(); 
     Runnable runWatcher; 
     runWatcher = new Runnable() { 
      @Override 
      public void run() { 
       try { 
        startWatcher(); 
       } catch (IOException e) { 
        e.printStackTrace(); 
       } catch (InterruptedException e) { 
        e.printStackTrace(); 
       } 
      } 
     }; 

     executorService.execute(runWatcher); 
    } 

    private void startWatcher() throws IOException, InterruptedException { 
     /** 
     * Create a new WatchService which detects created and modified files. To 
     * let it detect deleted files add ENTRY_DELETE to dir.register(). 
     */ 

     WatchService watcher = FileSystems.getDefault().newWatchService(); 
     WatchKey key = dir.register(watcher, ENTRY_CREATE, ENTRY_MODIFY); 

     while (!Thread.currentThread().isInterrupted()) { 
      key = waitForEvents(watcher, key); 

     } 
    } 

    private WatchKey waitForEvents(WatchService watcher, WatchKey key) { 

     /** 
     * The WatchService tells the FileHandler the Filename of the changed or 
     * new file in the given folder. 
     */ 

     try { 
      key = watcher.take(); 
     } catch (InterruptedException e) { 
      executorService.shutdown(); 

     } catch (ClosedWatchServiceException e) { 
      executorService.shutdown(); 

     } 

     for (WatchEvent<?> event : key.pollEvents()) { 

      fileHandler.setPath((Path) event.context()); 
     } 
     key.reset(); 
     return key; 
    } 

    public void stop() { 
     stopWatcher(); 
    } 

    private void stopWatcher() { 
     executorService.shutdown(); // Disable new tasks from being submitted 
     try { 
      // Wait a while for existing tasks to terminate 
      if (!executorService.awaitTermination(10, TimeUnit.SECONDS)) { 
       executorService.shutdownNow(); // Cancel currently executing tasks 
       // Wait a while for tasks to respond to being cancelled 
       if (!executorService.awaitTermination(10, TimeUnit.SECONDS)) 
        System.err.println("Pool did not terminate"); 
      } 
     } catch (InterruptedException ie) { 
      // (Re-)Cancel if current thread also interrupted 
      executorService.shutdownNow(); 
      // Preserve interrupt status 
      Thread.currentThread().interrupt(); 
     } 
    } 
} 

Я получил метод stopWatcher() от оракула Java API] 1. Я написал простой класс для проверки класса FileWatcher.

public class TestFileWatcher { 
    static Path path; 
    static ConfigManager configmanager; 

    public static void main(String[] args) { 

     path = Paths.get("D:/testfolder"); 
     FileHandler filehandler = new FileHandler() { 

      @Override 
      public void setPath(Path path) { 
       System.out.println("file: " + path); 

      } 

      @Override 
      public Path getPath() { 
       // TODO Auto-generated method stub 
       return null; 
      } 
     }; 

     final Config config; 
     config = new Config() { 

      @Override 
      public Path getJdfPath() { 
       // TODO Auto-generated method stub 
       return path; 
      } 
     }; 

     configmanager = new ConfigManager() { 

      @Override 
      public void injectConfig(Config config) { 
       // TODO Auto-generated method stub 

      } 

      @Override 
      public Config getConfig() { 
       // TODO Auto-generated method stub 
       return config; 
      } 
     }; 



     configmanager.injectConfig(config); 
     filehandler.setPath(path); 
     final FileWatcher filewatcher = new FileWatcher(configmanager, filehandler); 
     filewatcher.start(); 
     Timer timer = new Timer(); 


     boolean stopped; 

     TimerTask closeWatcherTask = new TimerTask(){ 
      @Override 
      public void run() { 

       System.out.println("filewatcher stopped."); 
       filewatcher.stop(); 

      } 
     }; 
     long duration = 2000; 
     timer.schedule(closeWatcherTask, duration); 
     return; 

    } 

} 

Так что, когда я начинаю тестовое приложение, чтобы запустить FileWatcher и закончить его через 2 секунды после того, программа говорит мне: Pool did not terminate. Что я могу изменить, чтобы закончить его правильно?

Кстати, ConfigManager и FileHandler являются интерфейсами, где я получаю Путь, который у меня есть для изменения.

+0

Вы можете сделать дамп потока в том месте, где он печатает «Бассейн не заканчивается», чтобы узнать, где он висит. –

ответ

0

shutDown() сообщит исполнителю, что он не принимает никаких новых заданий & отменяет все задачи, которые еще не запущены. Запускаемые задачи разрешены.

Вы зацикливание на неопределенный срок в

while (!Thread.currentThread().isInterrupted()) { 
     key = waitForEvents(watcher, key); 
    } 

потому что InterruptedException не устанавливает прерванное флаг.

Если вы изменяете

try { 
     key = watcher.take(); 
    } catch (InterruptedException e) { 
     executorService.shutdown(); 
    } catch (ClosedWatchServiceException e) { 
     executorService.shutdown(); 
    } 

Для

try { 
     key = watcher.take(); 
    } catch (InterruptedException e) { 
     Thread.currentThread().interrupt(); 
    } catch (ClosedWatchServiceException e) { 
     Thread.currentThread().interrupt(); 
    } 

и добавить executorService.shutdown(); после цикла While (или держать его там, где он есть) не должно быть никаких проблем.

+0

Спасибо, с этими изменениями, я не получаю ошибку «Пул не заканчивается». Но, похоже, мое тестовое приложение не прекращается. Как я могу управлять тестовым приложением, вызывает «return» и завершает работу, если все задачи завершены? – Peter

+0

@ rei0d в 'stopWatcher' вы просто« shutDown() », и это будет * не * прерывать выполняемые задачи, они никоим образом не уведомляются об этом. Используйте 'shutdownNow()' там (не нужно делать это дважды) – zapl

+0

Итак, я изменил метод stopWatcher() на: 'executorService.shutdownNow();' и удалил все остальное в нем.Мне удалось подождать несколько секунд после запуска FileWatcher со сном(), а не с помощью TimerTask. Теперь тестовое приложение завершает работу, и я думаю, что все работает. Благодарю. – Peter

2

Не анализируя свой код, он не отключается, поскольку ни один из потоков не завершил/не использует ресурсы. Легко загрязнен решение сделать усилие остановки с ExecuterService.shutdownNow() которой говорится в Javadoc:

Попытки остановить все активно выполняющиеся задачи, останавливает обработку ожидающих задач, и возвращает список задач, которые ожидают выполнение.

Так что попробуйте это и проанализировать список Runnables возвращенных ExecuterService.shutdownNow() вы получаете назад, чтобы увидеть, какой поток висит, а затем сделать шаг за шагом отладки и посмотреть, что вызывает повесить.

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