我想通过使用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());
}
}
}
}
答案 0 :(得分:3)
使用线程的中断状态来终止循环。这比你自己创建的旗帜更好,因为它使你的任务可以用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()
之后(在你的“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()
就足够了。
答案 1 :(得分:2)
一种方法是使用stop
方法将volatile boolean
设置为true
。
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进程,它也应该中断线程。
答案 2 :(得分:1)
有一个Thread.stop()
方法,但已经deprecated,因为它不安全。
您可以修改某个变量来指示目标线程应该停止运行,而不是使用弃用的方法。
答案 3 :(得分:1)
您可以使用flag
方法中的某些run
来检查是否退出方法,这样您就可以间接退出run
方法。
目前不建议通过任何其他方法停止线程。
见link