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

Java 如何终止检测新文件的连续线程,java,multithreading,watchservice,Java,Multithreading,Watchservice,这是我第一次涉足WatchService和多线程 我有一个应用程序,需要在外部设备发出提示让用户做某事时进行检测。提示通过放入特定文件夹中的XML文件传递。该文件的标题始终为“PRM.xml”,并将覆盖以前的PRM文件(如果存在)。为了防止重新显示旧的提示,“我的代码”会在显示后删除PRM文件 应用程序是用户交互的,因此当用户在主线程上执行其他活动时,它总是在后台线程中侦听PRM.xml 问题是,当用户希望在主线程中结束会话时(通过键入sentinel“zzz”),侦听线程不会结束,并且应用程序

这是我第一次涉足WatchService和多线程

我有一个应用程序,需要在外部设备发出提示让用户做某事时进行检测。提示通过放入特定文件夹中的XML文件传递。该文件的标题始终为“PRM.xml”,并将覆盖以前的PRM文件(如果存在)。为了防止重新显示旧的提示,“我的代码”会在显示后删除PRM文件

应用程序是用户交互的,因此当用户在主线程上执行其他活动时,它总是在后台线程中侦听PRM.xml

问题是,当用户希望在主线程中结束会话时(通过键入sentinel“zzz”),侦听线程不会结束,并且应用程序只有在被监视的文件夹中发生另一个事件时才会终止

当用户指示主线程终止时,如何强制后台侦听线程退出?(我希望我包含了足够的代码以获得良好的响应。)

//方法“run”包含要在线程中执行的代码
公开募捐{
试一试{
//启动新的监视服务以监视新的提示
WatchService ws=dirToWatch.getFileSystem().newWatchService();
dirToWatch.register(ws,ENTRY\u CREATE);
//持续监视目录,直到主程序线程结束
而(!SmartTill.stCom.equals(“ZZZ”)){
//获取新目录事件
WatchKey wk=ws.take();
//循环遍历所有检索到的事件
for(WatchEvent事件:wk.pollEvents()){
if(event.context().toString().endsWith(fileToDetect)){
System.out.println(“调试:显示提示,删除PRM”);
//…对“displayPrompt”方法的调用转到此处。。。
delFile(path.get(dirToWatch+fileToDetect));
}//如果结束
}//结束
//重置按键(清除事件列表)
System.out.println(“键已被”+
(wk.reset()?“reset.”:“unregistered.”);
}//结束时
}//结束尝试
捕获(例外e){}
}//终点

尝试向主线程添加关机挂钩,这样当主应用程序退出时,您也可以正确终止侦听线程

要做的更改 根据您的代码,需要进行以下更改:

  • 允许从主线程关闭WatchService
  • 向Shutdown钩子添加一个新线程,以便它在应用程序关闭时关闭WatchService
  • 1.使WatchService可关闭 应该允许在实现侦听线程的类中关闭WatchService

    public void stopThread() {
        try {
            System.out.println("closing the ws");
            ws.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    
    2.在应用程序关闭时关闭WatchService 在主线程中,添加一个shutdown钩子,这样当应用程序关闭时,它将调用侦听线程类的
    stopThread()
    方法

    Runtime.getRuntime().addShutdownHook(new Thread(new Runnable(listenThreadObj) {
        public void run() {
            listenThreadObj.stopThread();
        }
    }));
    
    示例代码 监听线程
    当主线程关闭时,它将运行ShutdownCleaner线程。

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

    要做的更改 根据您的代码,需要进行以下更改:

  • 允许从主线程关闭WatchService
  • 向Shutdown钩子添加一个新线程,以便它在应用程序关闭时关闭WatchService
  • 1.使WatchService可关闭 应该允许在实现侦听线程的类中关闭WatchService

    public void stopThread() {
        try {
            System.out.println("closing the ws");
            ws.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    
    2.在应用程序关闭时关闭WatchService 在主线程中,添加一个shutdown钩子,这样当应用程序关闭时,它将调用侦听线程类的
    stopThread()
    方法

    Runtime.getRuntime().addShutdownHook(new Thread(new Runnable(listenThreadObj) {
        public void run() {
            listenThreadObj.stopThread();
        }
    }));
    
    示例代码 监听线程 当主线程关闭时,它将运行ShutdownCleaner线程

    当用户指示主线程终止时,如何强制后台侦听线程退出

    你应该中断线程。
    WatchService.take()
    方法抛出
    InterruptedException
    。这意味着当主线程完成时,它可以中断watch服务线程。这将导致
    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();
    
    当捕捉到中断异常时,重新中断线程始终是一个好模式,以便调用者也可以使用中断状态:

    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
    完成。它不如上面的中断那么好,因为它可以在代码中间停止“<代码>监视线程< /代码>”,做一些重要的文件IO。< /P>
    Thread watchThread = new Thread(new WatchRunnable());
    watchThread.setDaemon(true);
    watchThread.start();
    
    当用户指示主线程终止时,如何强制后台侦听线程退出

    你应该中断线程。
    WatchService.take()
    方法抛出
    InterruptedException
    。这意味着当主线程完成时,它可以中断watch服务线程。这将导致
    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时,重新中断线程以使
    @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");
    }