如何安全地停止我的“类实现 Runnable”?

Posted

技术标签:

【中文标题】如何安全地停止我的“类实现 Runnable”?【英文标题】:How can I safely stop my "class implements Runnable"? 【发布时间】:2016-03-07 07:13:40 【问题描述】:

Oracle Java SE Docs 建议这样做:

您可以避免使用 Thread.stop,方法是将小程序的停止和运行方法替换为:

private volatile Thread blinker;

public void stop() 
    blinker = null;


public void run() 
    Thread thisThread = Thread.currentThread();
    while (blinker == thisThread) 
        try 
            Thread.sleep(interval);
         catch (InterruptedException e)
        
        repaint();
    

有没有办法为class blinker implements Runnable 做同样的事情?

由于您必须使用blinker thisClass = this; 或类似名称,(blinker == thisClass) 不会总是评估为真吗?

或者这段代码就足够了:

class blinker implements Runnable 
    boolean stop = false;

    @override
    public void run() 

        while (!Thread.currentThread().isInterrupted()) 

            // code
            // ...

            if (stop)  Thread.currentThread().interrupt(); 

            // ...

        
    

【问题讨论】:

我.. 不相信 Oracle 建议这样做。通常的方式是Thread.interrupt()。不,Runnable 没有等价物,只需酌情使用 Thread.interrupt()Future.cancel(true) @markspace I wouldn't have believed it either 我刚刚读到了。这似乎是一个可怕的想法。仅仅因为它是 Oracle 并不意味着他们不能发布经过深思熟虑的代码。我认为这里的主要思想是“不要调用 Thread.stop()”。其他任何东西都是杂物。 OP:使用 Thread.interrupt(). 所以内部带有Thread.currentThread().interrupt()while (!Thread.currentThread().isInterrupted()) 是完全安全的吗? @markspace 在文档中的那个时候,他们没有覆盖被阻塞的线程。该页面的下一部分将介绍中断。这部分解释了停止的替代方法,虽然没有以最好的方式解释,但了解它非常重要。我同意文档写得很糟糕。 【参考方案1】:

可以做这样的事情:

class Blinker implements Runnable 
    Runnable blinker = this;

    public void stop() 
        blinker = null;
    

    public void run() 
        while(blinker == this) 

        
    

但这将毫无意义。 我认为您没有理解文档试图传达的观点,即不要使用无限循环来保持线程处于活动状态,使用Thread#stop() 来终止它们。相反,请使用条件,然后在您想要结束保持线程活动的循环时将其设置为 false。


您无需不断检查Thread#isInterrupted() 来保持线程处于活动状态。

while(!stop) 


会很好。您也不应该从线程内部中断线程。中断的目的是结束暂停线程的任务。这些任务被包围在try/catch 中,它捕获了InterruptedException。其他线程通常负责中断。


文档是指允许线程优雅地死掉。

在第一个示例中,run() 方法通过无限循环处理:while(true)。停止线程的唯一方法是强制某种停止,例如 usong Thread#stop:

public void run() 
    while (true) 
        try 
            Thread.sleep(interval);
         catch (InterruptedException e)
        
        repaint();
    

但不建议使用Thread#stop。相反,循环应该依赖于boolean,另一个线程(或当前线程)可以将其设置为truefalse

private volatile boolean running;

public void stop() 
    running = false;


public void run() 
    while (running) 
        try 
            Thread.sleep(interval);
         catch (InterruptedException e)
        
        repaint();
    

他们没有使用running 布尔值,而是使用blinker == thisThread,然后在他们想要结束循环时更改了blinker 的值:

private volatile Thread blinker;

public void stop() 
    blinker = null;


public void run() 
    Thread thisThread = Thread.currentThread();
    while (blinker == thisThread) 
        try 
            Thread.sleep(interval);
         catch (InterruptedException e)
        
        repaint();
    

【讨论】:

这实际上并没有回答 OP 的问题“如果 blinker 是实现 Runnable 的类的实例怎么办?” (释义)。 你为什么要吞下InterruptedException的? @dimo414 这是直接来自文档的代码。我只是做了一些修改来显示代码的目的。开始时吞下了异常,我想与文档保持一致。

以上是关于如何安全地停止我的“类实现 Runnable”?的主要内容,如果未能解决你的问题,请参考以下文章

如何在android中安全地停止线程? [复制]

Docker 那些事儿如何安全地停止删除容器

如何使用 Multipeer Connectivity 安全地停止发送图像

Docker 那些事儿:如何安全地停止删除容器?

Docker 那些事儿如何安全地停止删除容器

多线程对同一个对象操作