为线程编写舒适的暂停/停止方法

时间:2018-09-05 18:47:51

标签: java multithreading java-threads

对于Java中的Thread子类,我试图编写一个方法checkPauseAndStop(),其目的是使单行代码更好,我可以在run()方法中定期调用该方法以检查是否有暂停/停止请求并采取相应行动。

虽然功能齐全,但是通过InterruptedException处理线程的停止,这迫使run()代码处于try-catch中,并且容易出错。
(例如Thread.sleep()不会再告诉您它可能会引发此类异常。

有没有什么好方法可以在方法内部处理停止线程而不会影响run()方法?

代码示例:

public class SuspendableThread extends Thread
{
   private Semaphore lock = new Semaphore(1);
   public void checkPauseRequest() throws InterruptedException
    {
        if (isInterrupted())
            throw new InterruptedException();

        lock.acquire();
        lock.release();

    }

    @Override
    public void run()
    {
        try
        {
            while (true)
            {
                // Do_stuff
                checkPauseRequest();
            }

        }
        catch (InterruptedException e)
        {
            return;
        }
    }

在这个特定示例中,根本没有必要。为了获得更大的效果,假设我们有50个或更多的连续块

// Do_stuff
checkPauseRequest();

而不是一个。

3 个答案:

答案 0 :(得分:1)

如果要捕获发送给线程的中断,例如要执行清理,则无法避免将整个run()代码块放入try / catch异常块中。原因是,如果您的线程通过条件变量或信号量(例如,调用wait())执行任何类型的线程间信号传递,则run()代码块将立即抛出{{1 }},如果为线程设置了中断状态标志。但是,如果您要主动检查线程的中断状态,最简单的方法是喷洒一堆中断点,也就是您的InterruptedException方法,并休眠几纳秒(您的如果设置了中断标志,则checkPause()方法将引发InterruptedException。这样就可以实现您的目标,而不会过多地损害线程性能。

答案 1 :(得分:1)

我会使用ScheduledExecutorService(可以用Executors.newSingleThreadScheduledExecutor创建)和enum RunningState { RUNNING, PAUSED, STOPPED }来构造它。

状态为RUNNING时,我们将继续安排延迟的任务(使用ScheduledExecutorService.schedule)。每个任务都会检查我们是否仍然RUNNING,如果是,则排队一次循环迭代(使用ExecutorService.submitExecutor.execute)。然后,它为下一次迭代计划一个新的延迟任务(与Timer一样,您可以潜在地使用它,但又会浪费另一个线程)。

如果状态为PAUSED,我们将继续安排延迟的任务,以继续检查是否转换回RUNNING状态。但是我们没有为实际的循环迭代安排工作项。

如果状态为STOPPED,那么我们将停止安排其他任何延迟的任务。

状态变量可以存储在简单的volatile字段中,该字段可以是静态的(如果只有这些东西之一)或可以包装在表示“线程”的对象中( '实际上不再是单个线程,但是从调用者的角度来看,它可以类似于一个线程。)

答案 2 :(得分:0)

请确保您要实现的目标确实有意义,并且不会属于让我们重新发明轮子类别。制作任何通用的“一刀切”停止方法并不是一件容易的事,尽管对于Java创建者来说也是如此。这就是不推荐使用Thread.stop()方法的原因。 (https://docs.oracle.com/javase/10/docs/api/java/lang/Thread.html#stop())(而且Thread.destroy()实际上并未实现AFAICT。)

有一个很好的解释:https://docs.oracle.com/javase/tutorial/essential/concurrency/interrupt.html