【问题标题】:Thread.stop() - deprecatedThread.stop() - 已弃用
【发布时间】:2013-05-06 10:18:42
【问题描述】:

为什么在 Java 中不推荐使用 Thread.stop()?在他们的网站上,我看到以下内容:

为什么不推荐使用Thread.stop

因为它本质上是不安全的。停止线程会导致它解锁所有已锁定的监视器。 (当ThreadDeath 异常向上传播堆栈时,监视器被解锁。)如果以前受这些监视器保护的任何对象处于不一致状态,其他线程现在可能会查看这些处于不一致状态的对象。据说这些物体已损坏。当线程对损坏的对象进行操作时,可能会导致任意行为。这种行为可能很微妙且难以检测,也可能很明显。与其他未经检查的异常不同,ThreadDeath 以静默方式杀死线程;因此,用户没有警告他的程序可能已损坏。损坏可以在实际损坏发生后的任何时间出现,甚至在未来几小时或几天内。

我不明白他们所说的“监视器”是什么意思。无论如何,我的问题是如果不应该调用 Thread.stop(),那么应该如何停止 Java 线程?

【问题讨论】:

  • 监视器是多线程控制和通信的关键概念。您应该花时间阅读this 之类的内容,以便更好地理解。从技术上讲,不,没有任何确定的方法可以停止任何线程,如果它有内部机制允许它的事件,因为库的其他部分可能不会监视线程的状态

标签: java multithreading


【解决方案1】:

你问:

我的问题是如果没有办法停止 Java 中的线程,那么如何停止线程?

答案:在 Java 中,没有干净、快速或可靠的方法来停止线程。

线程终止并不是那么简单。一个正在运行的线程,通常被许多作者称为轻量级进程,它有自己的堆栈,并且是自己命运的主人(当然守护进程也是如此)。它可能拥有文件和套接字。它可能持有锁。突然终止并不总是那么容易:如果线程正在写入文件并且在完成写入之前被杀死,则可能会出现不可预知的后果。或者当它被击中头部时线程持有的监视器锁呢?

相反,线程依赖于一种称为中断合作机制。这意味着线程只能通知其他线程停止,而不是强制它们停止。

为了停止 Java 中的线程,我们依赖于一种称为中断的协作机制。这个概念很简单。要停止线程,我们所能做的就是向它传递一个信号,也就是中断它,请求线程在下一个可用机会时自行停止。就这样。不知道接收线程可能对信号做什么:它甚至可能懒得检查信号;甚至更糟的是忽略它。

来源:https://codeahoy.com/java/How-To-Stop-Threads-Safely/

【讨论】:

  • 只是为了确定,Or what about the monitor locks held by the thread when it is shot in the head 表示 .stop 会导致死锁?
  • @deFreitas 根据文档,它不会直接导致死锁。相反,它会突然且不安全地解锁锁。这可能会导致一些数据被损坏。考虑将新项目添加到同步双向链表中 - 您创建新记录并更新一些引用,但在更新所有引用之前线程已停止。但是,当线程停止时,锁会被释放,因此从末尾迭代不会只显示元素的倒序(与从头开始迭代相比)。
  • 这些不一致可能会导致各种奇怪的行为。也许死锁可能是其中之一,但可能不是您的意思。
  • 知道了,伤害无法预料
【解决方案2】:

正确的方法是使用连接。 join 不会过早停止线程的执行,而是等待线程完成执行,然后再移动到下一条语句。

Thread exampleThread = new Thread(){
    public void run(){
        try {

            Thread.sleep(2000);

        } catch (InterruptedException ex) {
            //handle the exception
        }
    }
};

exampleThread.start();
exampleThread.join();

这里的 exampleThread.join() 将等到 exampleThread 完成执行后再移动到下一条语句。然而,确保线程完成执行的责任在于程序员。 本质上没有办法停止线程,但如果设计正确,则不需要停止线程。

【讨论】:

  • 我知道加入。如果 exampleThread 永远不会死掉怎么办(例如无限循环)。我想知道如何杀死 exampleThread。
  • 嗯,通常你会使用一个布尔标志,它应该能够让线程脱离循环。否则你需要重新设计,你一开始就不应该有无限循环。
  • 为什么不呢?假设线程正在通过网络从客户端接收数据包并且应该一直在运行?如何在外部杀死它?
  • 如果你想在某个时候杀死线程,你应该有一个标志可以向线程发出信号,表明它需要停止,否则没有原则性的方法。
  • 你可以使用 Thread.interrupt()。但无论如何,您的线程必须设计为响应中断stackoverflow.com/questions/5915156/…
【解决方案3】:

当您的线程正确处理中断时,应该可以使用ExecutorService 接口立即终止它。根据 Oracle 文档,ExecutorService.shutdownNow() 方法会尝试停止所有正在执行的任务,而无需等待它们终止。然而,除了尽力阻止它们之外,没有任何保证。下面是一些示例代码:

class MyThread implements Runnable{
    @Override
    public void run() {
        for (int i = 1; i < 10000000; i++)
            try {
            System.out.println(i + " ThreadID: " + Thread.currentThread().getId());
            if (Thread.interrupted()) 
                    throw new InterruptedException();
            } catch (InterruptedException e) {
                return;
        }   
    }
}

ExecutorService executor = Executors.newFixedThreadPool(3);
            executor.submit(new MyThread());
            executor.submit(new MyThread());
            executor.submit(new MyThread());
            executor.shutdownNow();

如果没有终止,每个线程应该向控制台打印 10000000 次消息。 executor.shutdownNow() 方法立即停止所有三个线程。

【讨论】:

  • 如果还是要停止某个特定线程,可以使用 Future 类的 cancel() 方法发出中断信号。
【解决方案4】:

来自https://docs.oracle.com/javase/8/docs/api/java/lang/Thread.html

stop 的大多数用法应该被替换为简单地修改一些变量以指示目标线程应该停止运行的代码。目标线程应该定期检查这个变量,如果变量指示它要停止运行,则以有序的方式从它的 run 方法中返回。为了确保停止请求的及时通信,变量必须是易失的(或者对变量的访问必须同步 )。

【讨论】:

    【解决方案5】:

    停止线程的逻辑应该在你的线程实现中处理,这样你就可以确定一切都按照你想要的方式进行。 例如,您可以创建一个 cancel() 方法来更改线程的状态,该状态会被循环检查。像这样:

    class StoppableThread implements Runnable {
    
        boolean isCancelled = false;
    
    
        public void run() {
            while (!isCancelled) {
                System.out.println("Thread is running with all its might!");
    
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }   
        }
    
    
        public void cancel () {
            isCancelled = true;
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-02-12
      • 1970-01-01
      • 2012-07-05
      • 2016-03-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多