[英]How to stop threads of following type in Java used for watching folders for files using WatchService for folders by using jToggleButton
我想通過使用jToggleButton停止以以下方式生成的線程。 線程用於監視文件夾中的文件。 我嘗試了很多,並進行了大量搜索,但未成功。 任何機構都可以提供幫助並建議任何解決方案來停止生成的線程。 即使按下jToggleButton,這些線程在Netbeans調試中仍顯示為活動狀態。 我嘗試了用於停止的易失性條件,僅供參考:我有一個jToggle按鈕,用於啟動和停止線程。
該代碼是由Netbeans生成的,因此有一些額外的代碼,但是您可能只關注jToggleActionListener內部的代碼和另一個類中的代碼:謝謝您的幫助。
package threadnames;
import java.io.IOException;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardWatchEventKinds;
import java.nio.file.WatchService;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.logging.Level;
import java.util.logging.Logger;
public class NewJFrame extends javax.swing.JFrame {
public NewJFrame() {
initComponents();
}
@SuppressWarnings("unchecked")
// <editor-fold defaultstate="collapsed" desc="Generated Code">
private void initComponents() {
jToggleButton1 = new javax.swing.JToggleButton();
setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
jToggleButton1.setText("Stop");
jToggleButton1.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
jToggleButton1ActionPerformed(evt);
}
});
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
getContentPane().setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addGap(84, 84, 84)
.addComponent(jToggleButton1)
.addContainerGap(142, Short.MAX_VALUE))
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addGap(25, 25, 25)
.addComponent(jToggleButton1)
.addContainerGap(28, Short.MAX_VALUE))
);
pack();
}// </editor-fold>
private void jToggleButton1ActionPerformed(java.awt.event.ActionEvent evt) {
ExecutorService exec = Executors.newCachedThreadPool();
if (this.jToggleButton1.isSelected()) {
try {
// TODO add your handling code here:
Path home = Paths.get(System.getProperty("user.dir"));
WatchService watcher;
watcher = home.getFileSystem().newWatchService();
home.register(watcher, StandardWatchEventKinds.ENTRY_CREATE);
Runnable task = new FileWatch(watcher);
exec.submit(task);
boolean terminated;
terminated = exec.awaitTermination(1, TimeUnit.SECONDS);
if (terminated) {
System.out.println("All tasks completed.");
} else {
System.out.println("Some tasks are still running.");
}
} catch (IOException | InterruptedException ex) {
Logger.getLogger(NewJFrame.class.getName()).log(Level.SEVERE, null, ex);
}
} else {
exec.shutdownNow();
}
}
public static void main(String args[]) {
try {
for (javax.swing.UIManager.LookAndFeelInfo info javax.swing.UIManager.getInstalledLookAndFeels()) {
if ("Nimbus".equals(info.getName())) {
javax.swing.UIManager.setLookAndFeel(info.getClassName());
break;
}
}
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | javax.swing.UnsupportedLookAndFeelException ex) {
java.util.logging.Logger.getLogger(NewJFrame.class
.getName()).log(java.util.logging.Level.SEVERE, null, ex);
}
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
new NewJFrame().setVisible(true);
}
});
}
// Variables declaration - do not modify
public javax.swing.JToggleButton jToggleButton1;
// End of variables declaration
}
這是run()的另一個類:
package threadnames;
import java.nio.file.WatchEvent;
import java.nio.file.WatchKey;
import java.nio.file.WatchService;
import java.nio.file.Watchable;
final class FileWatch implements Runnable {
private final WatchService watcher;
FileWatch(WatchService watcher) {
this.watcher = watcher;
}
@Override
public void run() {
while (!Thread.currentThread().isInterrupted()) {
WatchKey key;
try {
key = watcher.take();
} catch (InterruptedException ex) {
Thread.currentThread().interrupt();
break;
}
Watchable dir = key.watchable();
System.out.println(dir);
for (WatchEvent<?> evt : key.pollEvents()) {
System.out.println(" " + evt.context());
}
}
}
}
使用線程的中斷狀態終止循環。 這比您創建自己的標志更好,因為它使您的任務可與ExecutorService
一起使用; 您可以通過提交時收到的Future
取消特定任務,也可以使用shutdownNow()
中斷所有任務。
除非您的任務在創建和管理的線程中運行,否則在檢測到中斷后重新聲明中斷狀態是最安全的,以便調用者也可以處理它。 換句話說,所有線程和任務都需要具有定義的中斷策略並相應地使用。
這是一個使用WatchService
的示例Runnable
任務:
final class FileWatch implements Runnable {
private final WatchService watcher;
FileWatch(WatchService watcher) { this.watcher = watcher; }
@Override
public void run()
{
while (!Thread.currentThread().isInterrupted()) {
WatchKey key;
try {
key = watcher.take();
}
catch (InterruptedException ex) {
Thread.currentThread().interrupt();
break;
}
Watchable dir = key.watchable();
System.out.println(dir);
for (WatchEvent<?> evt : key.pollEvents()) {
System.out.println(" " + evt.context());
}
}
}
}
使用這種服務的方法如下:
public static void main(String... argv)
throws Exception
{
Path home = Paths.get(System.getProperty("user.home"));
WatchService watcher = home.getFileSystem().newWatchService();
home.register(watcher, StandardWatchEventKinds.ENTRY_CREATE, StandardWatchEventKinds.OVERFLOW);
Runnable task = new FileWatch(watcher);
ExecutorService exec = Executors.newCachedThreadPool();
exec.submit(task);
Thread.sleep(3000);
exec.shutdownNow();
boolean terminated = exec.awaitTermination(1, TimeUnit.SECONDS);
if (terminated)
System.out.println("All tasks completed.");
else
System.out.println("Some tasks are still running.");
}
因為FileWatch
任務正確支持中斷,所以您將看到此測試顯示在調用shutdownNow()
之后所有任務都已完成。 如果將使用其他終止方法的任務添加到ExecutorService
,您將看到它們繼續運行。
目前的代碼存在兩個問題。 這是對jToggleButton1ActionPerformed()
事件處理程序的分析,該事件處理程序在按下按鈕時由Swing事件調度線程( EDT )調用。
When the button is pressed, create a new ExecutorService as a local variable. If toggle selected, submit a file watching task to the executor, and block the EDT for 1 second, or until the executor is shutdown. Otherwise, shutdown the newly-created executor. Discard reference to the executor.
第一個問題是,由於執行程序服務永遠不會存儲在局部變量之外的任何地方,一旦該方法退出,對該特定實例的引用將永遠丟失,並且無法在其上調用shutdownNow()
。
第二個問題是,如果確實要阻止EDT(可能不是一個好主意)直到執行程序終止,則應在調用shutdownNow()
(在未選擇toggle的情況下,在“ else”子句中)(而不是在提交之后)之后執行此操作任務。 再次查看上面的示例,您將看到我僅在關閉執行程序后才等待終止。
將ExecutorService變量從方法中吊起,並使其成為類的成員變量。 這將允許切換按鈕處理程序訪問ExecutorService
的相同實例並將其關閉。 然后,將等待終止移動到未選擇的切換分支。
這是應該的流程:
When the button is pressed, If toggle selected, create a new executor service and assign it to a member variable, and submit a file watching task to the service. Otherwise, shutdown the executor, and wait for the service to terminate.
另外,您在這里使用newSingleThreadedExecutor()
就足夠了。
一種方法是使用將volatile boolean
為true
的stop
方法。
public class HelloRunnable implements Runnable {
private volatile boolean stop = false;
public void run() {
if (!stop) {
System.out.println("Hello from a thread!");
}
}
public void stop() {
stop = true;
}
public static void main(String args[]) {
for (int i = 0; i < 5; i++) {
HelloRunnable hr = new HelloRunnable();
new Thread(hr).start();
hr.stop();
}
}
}
如果線程可能被阻塞,您可以安排中斷它,但是當然不能保證中斷線程,因為它可能不會被阻塞,只是忙。
public class HelloRunnable implements Runnable {
private volatile boolean stop = false;
private volatile Thread thread = null;
public void run() {
thread = Thread.currentThread();
if (!stop) {
System.out.println("Hello from a thread!");
}
}
public void stop() {
stop = true;
if ( thread != null ) {
thread.interrupt();
}
}
public static void main(String args[]) {
for (int i = 0; i < 5; i++) {
HelloRunnable hr = new HelloRunnable();
new Thread(hr).start();
hr.stop();
}
}
}
如果使用WatchService.poll(...)或WatchService.take(),則這最后一種技術也應該起作用。
如果忙於大多數IO進程,它也應該中斷線程。
有一個Thread.stop()
方法,但已被棄用 ,因為它是不安全的。
您可以修改一些變量以指示目標線程應停止運行,而不是使用不建議使用的方法。
您可以在run
方法中使用一些flag
來檢查是否退出該方法,這樣就可以間接退出run
方法。 目前不建議通過任何其他方法停止線程。 見鏈接
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.