如何理解Volatile+Interrupt是停止线程优雅的姿势
本篇内容主要讲解“如何理解Volatile+Interrupt是停止线程优雅的姿势”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“如何理解Volatile+Interrupt是停止线程优雅的姿势”吧!
创新互联建站是一家朝气蓬勃的网站建设公司。公司专注于为企业提供信息化建设解决方案。从事网站开发,网站制作,网站设计,网站模板,微信公众号开发,软件开发,成都小程序开发,十载建站对iso认证等多个行业,拥有丰富设计经验。
使用stop方法
调用stop方法,会让正在运行的线程直接中止,有可能会让一些清理性的工作得不到完成。并且stop已经被标记为废弃的方法,不建议使用。
正确的使用姿势是使用两阶段终止的模式,即一个线程发送终止指令,另一个线程接收指令,并且决定自己在何时停止。
使用标志位
public class RunTask { private volatile boolean stopFlag; private Thread taskThread; public void start() { taskThread = new Thread(() -> { while (!stopFlag) { System.out.println("doSomething"); } }); taskThread.start(); } public void stop() { stopFlag = true; } }
「stopFlag上加volatile是保证可见性。我这个例子用了while循环不断判断,如果项目中用不到while的话,可以在关键节点判断,然后退出run方法即可」
使用interrupt方法
假如我们的任务中有阻塞的逻辑,如调用了Thread.sleep方法,如何让线程停止呢?
从线程状态转换图中寻找答案
从图中可以看到如果想让线程进入终止状态的前提是这个线程处于运行状态。当我们想要终止一个线程的时候,如果此时线程处于阻塞状态,我们如何把它转换到运行状态呢?
我们可以通过调用Thread#interrupt方法,将阻塞状态的线程转换到就绪状态,进入由操作系统调度成运行状态,即可终止。
那线程在运行状态中调用interrupt方法,会发生什么呢?
public class RunTaskCase1 { private Thread taskThread; public void start() { taskThread = new Thread(() -> { while (true) { System.out.println("doSomething"); } }); taskThread.start(); } public void stop() { taskThread.interrupt(); } }
依次调用start方法和stop方法,发现线程并没有停止。
「其实当线程处于运行状态时,interrupt方法只是在当前线程打了一个停止的标记,停止的逻辑需要我们自己去实现」
「Thread类提供了如下2个方法来判断线程是否是中断状态」
鸿蒙官方战略合作共建——HarmonyOS技术社区
isInterrupted
interrupted
这2个方法虽然都能判断状态,但是有细微的差别
@Test public void testInterrupt() throws InterruptedException { Thread thread = new Thread(() -> { while (true) {} }); thread.start(); TimeUnit.MICROSECONDS.sleep(100); thread.interrupt(); // true System.out.println(thread.isInterrupted()); // true System.out.println(thread.isInterrupted()); // true System.out.println(thread.isInterrupted()); }
@Test public void testInterrupt2() { Thread.currentThread().interrupt(); // true System.out.println(Thread.interrupted()); // false System.out.println(Thread.interrupted()); // false System.out.println(Thread.interrupted()); }
「isInterrupted和interrupted的方法区别如下」
Thread#isInterrupted:测试线程是否是中断状态,执行后不更改状态标志 Thread#interrupted:测试线程是否是中断状态,执行后将中断标志更改为false
「所以此时我们不需要自已定义状态,直接用中断标志即可,之前的代码可以改为如下」
public class RunTaskCase2 { private Thread taskThread; public void start() { taskThread = new Thread(() -> { while (!Thread.currentThread().isInterrupted()) { System.out.println("doSomething"); } }); taskThread.start(); } public void stop() { taskThread.interrupt(); } }
当线程处于阻塞状态时,调用interrupt方法,会抛出InterruptedException,也能终止线程的执行
「注意:发生异常时线程的中断标志为会由true更改为false。」
所以我们有如下实现 当线程处于运行状态:用自己定义的标志位来退出 当线程处于阻塞状态:用抛异常的方式来退出
public class RunTaskCase3 { private volatile boolean stopFlag; private Thread taskThread; public void start() { taskThread = new Thread(() -> { while (stopFlag) { try { System.out.println("doSomething"); TimeUnit.MICROSECONDS.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } } }); taskThread.start(); } public void stop() { stopFlag = true; taskThread.interrupt(); } }
当然也可以一直用中断标志来退出,「注意,当发生异常的时候需要重置中断标志位」。
public class RunTaskCase4 { private Thread taskThread; public void start() { taskThread = new Thread(() -> { while (!Thread.currentThread().isInterrupted()) { try { System.out.println("doSomething"); TimeUnit.MICROSECONDS.sleep(100); } catch (InterruptedException e) { // 重置中断标志位为true Thread.currentThread().interrupt(); e.printStackTrace(); } } }); taskThread.start(); } public void stop() { taskThread.interrupt(); } }
到此,相信大家对“如何理解Volatile+Interrupt是停止线程优雅的姿势”有了更深的了解,不妨来实际操作一番吧!这里是创新互联网站,更多相关内容可以进入相关频道进行查询,关注我们,继续学习!
名称栏目:如何理解Volatile+Interrupt是停止线程优雅的姿势
网站地址:http://hbruida.cn/article/pjjsis.html