【问题标题】:Program not stopping thread程序不停止线程
【发布时间】:2013-11-21 22:50:31
【问题描述】:

所以我有一个线程,我以前无法运行,但现在由于该站点上的一位成员而得到解决,可以在 here 找到该问题。

为了停止我的线程,我在线程类中创建了一个布尔值并将其设置为 false,如果它设置为 true,那么线程应该停止。我什至通过打印线程来检查何时停止线程,但它打印 true (它应该)但线程继续运行。

我的线程 (CheckFiles.java) 类如下所示。

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;

class CheckFiles extends Thread {

    static boolean stop = false;

    public void run() {
        while (!stop) {
            System.out.println("Thread " + stop);
            try {

                String line;

                BufferedReader b = new BufferedReader(new FileReader(UserInterface.location));

                while((line = b.readLine()) != null) {

                    Ststem.out.println(line);
                }

            } catch (IOException e) { System.out.println(e); }

        }
    }

}

要停止线程,我有一个按钮,它的代码如下所示。

 stopChecking.addMouseListener(new MouseAdapter() {
        @Override
        public void mousePressed(MouseEvent e) {

            CheckFiles.stop = true;
            System.out.println(CheckFiles.stop); //Prints true when pressed

        }
    });

为什么我的线程没有停止,或者有更好的方法吗?

编辑:当我尝试中断线程时出现语法错误

无法从 Thread 类型对非静态方法 interrupt() 进行静态引用

此外,当我使布尔停止 volatile 时,线程仍在运行。

【问题讨论】:

  • 你有两个错误;您需要同时使用volatile 并中断阻塞线程。
  • 这两种我都试过了,并在原帖中添加了错误。
  • 搜索那个错误;这是一个骗子,但我还不能在几分钟内将其标记为重复。

标签: java multithreading


【解决方案1】:

线程在b.readLine() 上阻塞,因为该行代码导致线程执行暂停,直到有一些可用输入。

要“强制”停止,请使用Thread.interrupt()

例如:

stopChecking.addMouseListener(new MouseAdapter() {
    @Override
    public void mousePressed(MouseEvent e) {

        //To clarify the following uses a INSTANCE of CheckFiles, called CheckFiles.
        //In other words, somewhere there was a declaration with the format:
        // CheckFiles CheckFiles = ...

        CheckFiles.stop = true;
        CheckFiles.interrupt(); //Or whatever the name of your thread instance is
        System.out.println(CheckFiles.stop); //Prints true when pressed

    }
});

内部读取循环也应该这样修改:

while(!stop && (line = b.readLine()) != null){
    Ststem.out.println(line);
}

由于中断只是解除 I/O 阻塞,我们需要检查 stop 是否仍然是 false,然后再进行另一次阻塞读取。

正如其他人所建议的,另一种方法是在设置stop = true; 之后直接调用b.close()


编辑:

正如 Vakh 所说,您还应该将布尔值设为 volatile,以便所有线程都可以立即看到对 stop 变量的更新。

【讨论】:

  • 我不能中断线程,在原帖中添加了错误。
  • @user2612619 您需要注意的事项很少。 1. 不要将您的停止变量设为static,否则当您只想停止一个线程时,您将停止所有线程。 2. 在您的实际线程实例对象上执行interrupt() 方法。通过执行CheckFile.interrupt(),您正在静态访问interrupt() 方法,因为您直接通过类而不是实例来引用它。
  • 如果我不将变量设为静态,那么我无法从按钮所在的其他方法访问它。我也像您在示例中所做的那样打断它。
  • @user2612619 这就是我的观点,您不应该尝试使用静态方法修改一个线程实例的状态。我的示例只是假设您有一个名为 CheckFiles 的对象实例(请参阅语句后的注释
  • 那么我应该如何改变线程的状态呢?而我目前只有一个正在运行。
【解决方案2】:

您必须将stop 声明为volatile

static volatile boolean stop = false;

基本上,volatile 意味着访问 volatile 字段的每个线程都会在继续之前读取其当前值,而不是(可能)使用缓存值,这似乎发生在编译器假定 @ 987654326@ 值在您的线程中始终为 false,因为它从不为其写入其他值。

【讨论】:

  • 线程在声明为 volatile 后仍在运行。
【解决方案3】:

当你用 b.close() 停止 bufferedreader 时,不会停止线程吗?

【讨论】:

    【解决方案4】:

    使用线程中断标志进行终止:

    public class FileChecker implements Callable<Void> {
        private final File location;
    
        public FileChecker(File location) {
            this.location = location;
        }
    
        @Override
        public Void call() throws Exception {
            try {
                while (!Thread.currentThread().isInterrupted()) {
                    try (BufferedReader b = new BufferedReader(new FileReader(location))) {
                        String line;
                        while ((line = b.readLine()) != null) {
                            if (Thread.interrupted()) {
                                throw new InterruptedException();
                            }
                            System.out.println(line);
                        }
                    }
                }
            } catch (InterruptedException ex) {
                // restore interruption flag
                Thread.currentThread().interrupt();
            }
    
            return null;
        }
    }
    

    您现在可以使用ExecutorService 安排您的文件检查器:

    ExecutorService executor = Executors.newSingleThreadExecutor();
    Future<Void> future = executor.submit(new FileChecker(...));
    

    通过取消Future 或关闭执行程序来停止文件检查器:

    future.cancel(true);
    executor.shutdownNow();
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-01-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多