如何终止检测新文件的连续线程



这是我第一次进入手表服务和多线程。

我有一个应用程序,需要检测何时外部设备向用户做某事提示。该提示是通过XML文件掉入特定文件夹的方式传递的。该文件始终标题为" prm.xml",如果存在,将覆盖以前的PRM文件。为了防止重新显示旧提示,我的代码显示后删除PRM文件。

该应用程序是用户相互作用的,因此当用户在主线程上执行其他活动时,它始终在背景线程中收听prm.xml。

问题是,当用户想在主线程中结束他的会话时(通过键入前哨" zzz"),侦听线程将不会结束,并且应用程序仅在监视的文件夹中发生另一个事件时终止。。

当用户指示主线程终止时,我该如何强制背景侦听线程退出?(我希望我已经提供了足够的代码来获得良好的回复。)

// Method 'run' contains code to be executed in the thread
public void run() {
  try {
     // initiate new watch service to watch for new prompts
     WatchService ws = dirToWatch.getFileSystem().newWatchService();
     dirToWatch.register(ws, ENTRY_CREATE);
     // monitor directory continuously until main program thread ends
     while (!SmartTill.stCom.equals("ZZZ")) {
        // get new directory events
        WatchKey wk = ws.take();
        // loop through all retrieved events
        for (WatchEvent<?> event : wk.pollEvents()) {
           if (event.context().toString().endsWith(fileToDetect)) {
              System.out.println("DEBUG: Display Prompt, Delete PRM.");
              // ...call to "displayPrompt" method goes here...
              delFile(Paths.get(dirToWatch + fileToDetect));
           }// end if
        }// end for
     // reset the key (erase list of events)
     System.out.println("Key has been " + 
             (wk.reset() ? "reset." : "unregistered."));
     }// end while
  }// end try
  catch(Exception e){}
}// end run

当用户指示主线程终止时,我该如何强制背景侦听线程退出?

您应该中断线程。WatchService.take()方法抛出InterruptedException。这意味着,当主线程完成时,它可以中断手表服务线程。这将导致take()方法抛出InterruptedException,这使手表线有机会清理和退出while循环,然后从run()方法返回。

Thread watchThread = new Thread(new WatchRunnable());
watchThread.start();
// ...
// when the main thread wants the program to stop, it just interrupts the thread
watchThread.interrupt();
// although not necessary, main thread may wait for the watch-thread to finish
watchThread.join();

当您捕获InterruptedException时,始终是重新划分线程的好模式,以便呼叫者也可以使用中断状态:

WatchKey wk;
try {
   wk = ws.take();
} catch (InterruptedException ie) {
   // always recommended
   Thread.currentThread().interrupt();
   // leave the loop or maybe return from run()
   break;
}

重要的是要注意,中断线程不是某种神奇的调用。它在线程上设置了一个中断标志,该标志会导致某些方法明确投掷InterruptedException投掷。如果代码的其他部分想查看线程是否已中断,则应执行以下操作。

if (Thread.currentThread().isInterrupted()) {
    // clean up and exit the thread...
    break;
}

另一个解决方案将是使观察者线程成为守护程序线程。这意味着当主线程完成时,JVM将立即辞职,而不必等待watchThread完成。它不如上述中断那么好,因为它可能在其中中间停止watchThread进行一些重要的文件io。

Thread watchThread = new Thread(new WatchRunnable());
watchThread.setDaemon(true);
watchThread.start();

我遇到了同样的问题,我发现该解决方案正在起作用,

解决方案是覆盖中断方法(您的类应扩展线程而不是可运行的线程)并从那里关闭WatchService,这将在您的take()方法中扔掉loteWatchServiceException,因此您必须捕获此例外

>

覆盖中断

@Override
public void interrupt() {
    super.interrupt();
    System.out.println("Interupt is called");
    try {
            watcher.close();
        }
    } catch (IOException e) {
        e.printStackTrace();
    }
}

处理异常

try {
            key = watcher.take();
        } catch (InterruptedException x) {
            System.out.println("take() is interrupted");
            Thread.currentThread().interrupt();
            return;
        } catch (ClosedWatchServiceException e) {
            System.out.println(" take is killed from closedException");
            return;
        }

主线程

public static void main(String[] args) throws InterruptedException {
    WatchDir watchDir = new WatchDir(path);
    Thread.currentThread().sleep(1000);
    watchDir.shutDown();
    watchDir.interrupt();
    watchDir.join();
    System.out.println("the WatchDir thread is killed");
}

尝试在主线程中添加关闭挂钩,以便当主应用程序退出时,您也可以正确终止听力线程。

更改要完成

从您的代码中,需要完成以下更改:

  1. 允许从主线程关闭手表服务
  2. 在关闭挂钩上添加一个新线程,以便在应用程序关闭时关闭WatchService。

1。使WatchService Closible

应允许手表服务在实现聆听线程的类中关闭。

public void stopThread() {
    try {
        System.out.println("closing the ws");
        ws.close();
    } catch (IOException e) {
        e.printStackTrace();
    }
}

2。在应用程序关闭时关闭WatchService

在主线程中,添加关闭挂钩,以便在应用程序关闭时,它将调用听力线程类的stopThread()方法。

Runtime.getRuntime().addShutdownHook(new Thread(new Runnable(listenThreadObj) {
    public void run() {
        listenThreadObj.stopThread();
    }
}));

示例代码

听线

import java.io.IOException;
import java.nio.file.FileSystems;
import java.nio.file.Path;
import java.nio.file.StandardWatchEventKinds;
import java.nio.file.WatchEvent;
import java.nio.file.WatchKey;
import java.nio.file.WatchService;
public class ListeningThread implements Runnable {
    WatchService ws;
    public ListeningThread() {
        try {
            ws = FileSystems.getDefault().newWatchService();
            Path watchPath = FileSystems.getDefault().getPath("<path_to_directory>");
            watchPath.register(ws, StandardWatchEventKinds.ENTRY_CREATE);
            watchPath.register(ws, StandardWatchEventKinds.ENTRY_MODIFY);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    @Override
    public void run() {
        WatchKey wk;
        try {
            while ((wk = ws.take()) != null) {
                for (WatchEvent<?> we : wk.pollEvents()) {
                    System.out.println(we.kind());
                }
            }
        } catch (InterruptedException e) {
            System.out.println("WatchService closed");
            e.printStackTrace();
        }
    }
    public void stopThread() {
        try {
            System.out.println("closing the ws");
            ws.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

主线程

import java.util.Scanner;
public class MainThread {
    public static void addShutdownHook(ListeningThread thread) {
        Runtime.getRuntime().addShutdownHook(new Thread(new ShutdownCleaner(thread)));
    }
    public static void main(String[] args) {
        ListeningThread lt = new ListeningThread();
        Thread listenThread = new Thread(lt, "ListenThread");
        addShutdownHook(lt);
        listenThread.start();
        Scanner sc = new Scanner(System.in);
        sc.next();
        System.exit(0);
    }
    private static class ShutdownCleaner implements Runnable {
        private ListeningThread listenerThread;
        public ShutdownCleaner(ListeningThread lt) {
            this.listenerThread = lt;
        }
        @Override
        public void run() {
            // Shutdown runs
            if (listenerThread != null) {
                listenerThread.stopThread();
            }
        }
    }
}

当主线程关闭时,它将运行shutDownCleaner线程。

相关内容

  • 没有找到相关文章

最新更新