我在停止线程时遇到了一些麻烦。我有扫描文件夹中文件的方法。我想有按钮停止扫描。点击此按钮后线程将停止(扫描将停止)并且程序将重置。我已经尝试过命令thread.stop();
并且它有时工作(它不再工作了)。所以我在这里阅读了有关stackoverflow的一些主题并尝试thread.interrupt();
我的代码看起来像这样:
public class myApp extends javax.swing.JFrame {
Thread thread;
int fileCount = 0;
String path = "C:\\Program Files";
public void scanningMethod() {
thread = new Thread(new Runnable() {
public void run() {
while(!thread.interrupted()){
//Recursion method that counting files
dirScan(path);
}
}
});
thread.start();
}
private void stopButtonActionPerformed(java.awt.event.ActionEvent evt) {
//generated button in netBeans
thread.interrupt();
thread.stop();
}
private void dirScan(String dirPath) {
File[] podSoubory = new File(dirPath).listFiles();
for (int i = 0; i < podSoubory.length; i++) {
if (podSoubory[i].isDirectory()) {
String tempPath = podSoubory[i].getAbsolutePath();
System.out.println(tempPath);
if (podSoubory[i].isFile()) {
fileCount++;
}
}
}
}
另一种停止方法仅包含thread.interrupt();
(其中包含actionListener和stuff)。
可能我做错了什么。你能帮助我并告诉我如何在点击按钮后停止这个运行的线程吗? (我知道如何创建可点击按钮)。
答案 0 :(得分:3)
关于你的主要问题,为什么你的代码不能正常工作,我很抱歉,但我没有答案,因为不幸的是,我没有时间去分析你的所有代码码。我会说你的是危险的代码(如你所知),不仅仅是因为你的调用setText(...)
而且由于你的代码不遵守Swing线程规则,这些规则要求大多数Swing调用都是在Swing事件线程。您正在调用一些关键的Swing方法,包括后台线程中的cancel(true)
方法,这会导致间歇性的调试线程错误。
我建议:
true
方法,传入isCancelled()
参数以允许此调用取消正在运行的代码。publish(...)
州。doInBackground()
方法中的process(...)
调用中。import java.awt.BorderLayout;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.List;
import java.util.concurrent.ExecutionException;
import javax.swing.*;
public class InterruptedGui {
private static final int GAP = 3;
private MyWorker myWorker;
private StartWorkerAction startWorkerAxn = new StartWorkerAction(this,
"Worker");
private StopAllAction stopAllAction = new StopAllAction(this, "Stop All");
private JLabel statusLabel = new JLabel("");
private JTextArea finalTextArea = new JTextArea(20, 40);
private JPanel mainPanel = new JPanel();
public InterruptedGui() {
finalTextArea.setFocusable(false);
JPanel buttonPanel = new JPanel(new GridLayout(1, 0, GAP, 0));
buttonPanel.add(new JButton(startWorkerAxn));
buttonPanel.add(new JButton(stopAllAction));
JPanel statusPanel = new JPanel();
statusPanel.setLayout(new BoxLayout(statusPanel, BoxLayout.LINE_AXIS));
statusPanel.add(new JLabel("Status: "));
statusPanel.add(statusLabel);
mainPanel.setBorder(BorderFactory.createEmptyBorder(GAP, GAP, GAP, GAP));
mainPanel.setLayout(new BorderLayout());
mainPanel.add(buttonPanel, BorderLayout.PAGE_START);
mainPanel.add(new JScrollPane(finalTextArea,
JScrollPane.VERTICAL_SCROLLBAR_ALWAYS,
JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED));
mainPanel.add(statusPanel, BorderLayout.PAGE_END);
}
public JComponent getMainPanel() {
return mainPanel;
}
public void setStatus(String text) {
statusLabel.setText(text);
}
public MyWorker getMyWorker() {
return myWorker;
}
public void setMyWorker(MyWorker myWorker) {
this.myWorker = myWorker;
}
public void finalTextAreaSetText(String text) {
finalTextArea.setText(text);
}
private static void createAndShowGui() {
JFrame frame = new JFrame("Interrupted Gui");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(new InterruptedGui().getMainPanel());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
class MyWorker extends SwingWorker<String, String> {
private static final long SLEEP_TIME = 100;
private static final int MAX_COUNTER = 100;
private int counter = 0;
private InterruptedGui gui;
public MyWorker(InterruptedGui gui) {
this.gui = gui;
}
@Override
protected String doInBackground() throws Exception {
StringBuilder sb = new StringBuilder();
while (counter < MAX_COUNTER && !isCancelled()) {
counter++;
String statusText = "Counter is " + counter;
sb.append(statusText + "\n");
publish(statusText);
Thread.sleep(SLEEP_TIME);
}
return sb.toString();
}
@Override
protected void process(List<String> chunks) {
for (String statusText : chunks) {
gui.setStatus(statusText);
}
}
}
@SuppressWarnings("serial")
class StartWorkerAction extends AbstractAction {
private InterruptedGui gui;
public StartWorkerAction(InterruptedGui gui, String name) {
super(name);
this.gui = gui;
int mnemonic = (int) name.charAt(0);
putValue(MNEMONIC_KEY, mnemonic);
}
@Override
public void actionPerformed(ActionEvent e) {
MyWorker myWorker = gui.getMyWorker();
if (myWorker != null && !myWorker.isDone()) {
return; // still running current worker
}
gui.finalTextAreaSetText("");
myWorker = new MyWorker(gui);
gui.setMyWorker(myWorker);
myWorker.addPropertyChangeListener(new WorkerPropertyListener(gui));
myWorker.execute();
}
}
class WorkerPropertyListener implements PropertyChangeListener {
private InterruptedGui gui;
public WorkerPropertyListener(InterruptedGui gui) {
this.gui = gui;
}
@Override
public void propertyChange(PropertyChangeEvent evt) {
if (evt.getNewValue() == SwingWorker.StateValue.DONE) {
MyWorker myWorker = gui.getMyWorker();
if (myWorker != null && !myWorker.isCancelled()) {
try {
String finalText = myWorker.get();
gui.finalTextAreaSetText(finalText);
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
}
}
}
@SuppressWarnings("serial")
class StopAllAction extends AbstractAction {
private InterruptedGui gui;
public StopAllAction(InterruptedGui gui, String name) {
super(name);
this.gui = gui;
int mnemonic = (int) name.charAt(0);
putValue(MNEMONIC_KEY, mnemonic);
}
@Override
public void actionPerformed(ActionEvent e) {
MyWorker myWorker = gui.getMyWorker();
if (myWorker == null) {
return;
}
myWorker.cancel(true);
}
}
方法中处理这些数据,这种方法可以保证在Swing事件线程上调用。例如:
CHARACTER SET
答案 1 :(得分:3)
您对线程中断的工作方式存在误解,当您调用Thread#interrupt
时,所有发生的事件都会在flag
实例中引发Thread
,您可以使用{interrupted
实例进行检查1}}或isInterrupted
。
在您的代码中,您有一个for-loop
for (int i = 0; i < podSoubory.length; i++) {
if (podSoubory[i].isDirectory()) {
String tempPath = podSoubory[i].getAbsolutePath();
System.out.println(tempPath);
if (podSoubory[i].isFile()) {
fileCount++;
}
}
这意味着在此for-loop
存在之前,while(!thread.interrupted()){
语句不会被评估。
您需要做的是在代码中的周期点测试isInterrupted
,例如......
for (int i = 0; i < podSoubory.length && !Thread.currentThread().isInterrupted(); i++) {
if (podSoubory[i].isDirectory()) {
String tempPath = podSoubory[i].getAbsolutePath();
System.out.println(tempPath);
if (podSoubory[i].isFile()) {
fileCount++;
}
}
}
这会添加对isInterrupted
的检查,导入为isInterrupted
WON&#39;清除像Thread#interrupted
这样的中断标记,这样可以让您的代码的其他部分更进一步也测试interrupted
标志。
当您中断Thread
时,for-loop
和while-loop
都会检查interrupted
标志的状态,并允许两个循环退出。
作为一个可运行的例子......
import java.awt.EventQueue;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class MyApp {
public static void main(String[] args) {
new MyApp();
}
public MyApp() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
public TestPane() {
setLayout(new GridBagLayout());
JButton stop = new JButton("Stop");
stop.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
thread.interrupt();
// Join is used here to prove a point, be careful
// with using this within the context of the EDT
try {
thread.join();
} catch (InterruptedException ex) {
ex.printStackTrace();
}
stop.setEnabled(false);
}
});
add(stop);
scanningMethod();
}
Thread thread;
int fileCount = 0;
String path = "C:\\Program Files";
public void scanningMethod() {
thread = new Thread(new Runnable() {
public void run() {
while (!thread.isInterrupted()) {
//Recursion method that counting files
dirScan(path);
System.out.println(thread.isInterrupted());
}
}
});
thread.start();
}
private void dirScan(String dirPath) {
File[] podSoubory = new File(dirPath).listFiles();
for (int i = 0; i < podSoubory.length && !Thread.currentThread().isInterrupted(); i++) {
if (podSoubory[i].isDirectory()) {
String tempPath = podSoubory[i].getAbsolutePath();
System.out.println(tempPath);
if (podSoubory[i].isFile()) {
fileCount++;
}
}
}
}
}
}
您可能需要查看Concurrency in Java了解更多详情
另外,Thread#stop
已被弃用,绝不应该使用JavaDocs ...
<强>已过时即可。这种方法本质上是不安全的。使用停止线程 Thread.stop使它解锁已锁定的所有监视器 (作为未经检查的
ThreadDeath
例外的自然结果 传播堆栈)。如果以前受保护的任何物体 由这些监视器处于不一致状态,受损物体 对其他线程可见,可能导致任意 行为。 stop的许多用法应该简单地用代码替换 修改某个变量以指示目标线程应该停止 运行。目标线程应定期检查此变量,并且 如果变量,则以有序的方式从其run方法返回 表示它将停止运行。如果目标线程等待 长期(例如,在条件变量上),中断 应该使用方法来中断等待。有关更多信息,请参阅 Why are Thread.stop, Thread.suspend and Thread.resume Deprecated?
答案 2 :(得分:-1)
我建议通过Runnable接口实现一个线程。在这种情况下,您需要实现run()和kill()方法。将本地共享变量作为标志引入。在kill方法中,将标志设置为false,在run方法中执行操作,直到标志为真。
一般情况下,我建议熟悉在这种情况下可能对您有用的等待/通知机制以及Java Executioner框架。
最重要的是,请搜索stackoverflow以获取类似问题,之前已经回答过。例如,Java: How to stop thread?。
希望这有帮助。