java - 线程在中断或停止后不会停止

标签 java multithreading swing user-interface

我在停止线程时遇到了一些麻烦。我有扫描文件夹中文件的方法。我想要一个停止扫描的按钮。点击此按钮后,线程将停止(扫描将停止)并且程序将重置。我尝试过命令 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();(ofc它有actionListener和其他东西)。

可能我做错了什么。您能帮我告诉我如何在单击按钮后停止这个正在运行的线程吗? (我知道如何创建可点击的按钮)。

最佳答案

至于你的主要问题,即为什么你的代码不起作用,我很抱歉,但我没有答案,因为不幸的是,我没有时间仔分割析和分析你的所有内容代码。我想说的是,你的代码是危险的代码(如你所知),不仅仅是因为你的调用 Thread#stop()而且由于您的代码不遵守 Swing 线程规则,这些规则要求大多数 Swing 调用都在 Swing 事件线程上进行。您正在调用一些关键的 Swing 方法,包括 setText(...)后台线程中的方法,这可能会导致间歇性非常难以调试的线程错误。

我建议:

  • 出于多种原因,将 SwingWorkers 用于后台线程,但主要是为了您可以将后台线程中的数据安全地发布/处理到 GUI 中。
  • 如果你想杀死你的 SwingWorker,请调用它的 cancel(true)方法,传入 true参数允许此调用取消正在运行的代码。
  • 在您的 SwingWorker 中,检查 isCancelled()状态。
  • 您想要后台线程的任何文本或数据都应传递到 publish(...)在您的 SwingWorker 中调用 doInBackground()方法。
  • SwingWorker 然后可以在其 process(...) 内处理这些数据。方法,保证在 Swing 事件线程上调用的方法。
<小时/>

例如:

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);
    }
}

关于java - 线程在中断或停止后不会停止,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31975337/

相关文章:

java - Linux JVM 是否真的实现了线程优先级?

java - 如何在 Java EE 6 中的消息驱动 Bean 中进行事务处理接收?

java - 实现基本的 REST API - ServletException

Python多线程共享变量导致UnboundLocalError

java - JXTreeTable - 我的节点是可编辑的,但其他单元格不是

java - 在 android 中禁用多选列表首选项中的复选框单击

java - java.nio 的非阻塞选择问题

c++ - 公平队列丢失通知

java - KeyListener 的困惑

java - 使用 ArrayList 绘制图像(JPanel、JFrame)