怎么关闭一个 Java 线程 ( Thread ) ? 噢,不,正确的问题是怎么正确的关闭一个 Java 线程?
这个问题是不是很简单? 很简单啊,不就是使用 Thread.stop()
方法么?
但是,根据 ORACLE 的更新文档 ,Thread.stop()
方法可能导致监视器对象被破坏。
因此,我们必须使用其它更安全的方法,或在 Thread.stop()
方法上做一些改变。
使用一个标志 ( Flag )
假设存在一个任务,这个任务并不会自己自动结束,因此我们必须找到一些方式来停止该线程。
为了方便你的理解,我们从创建和启动线程的类开始,一步一步讲解。
首先,我们需要一个原子性的标志 ( flag )
public class ControlSubThread implements Runnable { private Thread worker; private final AtomicBoolean running = new AtomicBoolean(false); private int interval; public ControlSubThread(int sleepInterval) { interval = sleepInterval; } public void start() { worker = new Thread(this); worker.start(); } public void stop() { running.set(false); } public void run() { running.set(true); while (running.get()) { try { Thread.sleep(interval); } catch (InterruptedException e){ Thread.currentThread().interrupt(); System.out.println( "Thread was interrupted, Failed to complete operation"); } // do something here } } }
上面这段代码中,我们使用了 AtomicBoolean
而不是让 while
循环评估常量 true。
有了这个标志,我们就可以通过将其设置为 true/false 来启动/停止执行。
中断线程
当把 sleep()
设置为较长的间隔时,或者我们正在等待可能永远不会被释放的 锁 时会发生什么 ?
我们面临长期阻塞或永不干净的风险。
为了解决这类问题,我们可以创建一个 interrupt()
。
为了演示如何创建 interrupt()
,我们在刚刚的范例基础上添加一些方法和一个新标志。
public class ControlSubThread implements Runnable { private Thread worker; private AtomicBoolean running = new AtomicBoolean(false); private int interval; // ... public void interrupt() { running.set(false); worker.interrupt(); } boolean isRunning() { return running.get(); } boolean isStopped() { return stopped.get(); } public void run() { running.set(true); while (running.get()) { try { Thread.sleep(interval); } catch (InterruptedException e){ Thread.currentThread().interrupt(); System.out.println( "Thread was interrupted, Failed to complete operation"); } // do something } } }
上面这段代码中,我们添加了一个 interrupt()
方法,并在该方法中将运行标志设置为 false
,然后调用工作线程的 interrupt()
方法中断线程。
如果线程在调用此函数时处于休眠状态,则 sleep()
会退出并抛出一个 InterruptedException
异常,就像任何其它阻塞调用一样。
后记
哎,本来可以使用 Thread.stop()
解决的问题,结果为了考虑锁和监视器,整蛊了一个长的解决方案,这难道就是 Java 开发不能避免的?