java多线程-线程的停止

文章目录

  • java多线程-线程的停止
    • 线程停止的原理
    • 如何正确停止线程
      • 在普通情况下停止线程
        • 代码展示
      • 在阻塞情况下停止线程
        • 代码展示
      • 线程在每次迭代后都阻塞
        • 代码展示
    • 停止线程的最佳实践
    • 错误停止的方法
      • 被弃用的stop,suspend和resume方法
      • 用volatile设置boolean标记位
    • interrupt源码查看
    • interrupt相关函数练习

线程停止的原理

使用interrupt来通知,而不是强制

java提供了interrrupt让一个线程来通知另一个线程停止

如果想中断一个线程,但是那个线程不想去中断,那就无能为力,我们没有强制去中断线程的手段,因为线程停止前需要做一定的收尾工作

所以正确停止线程,是如何用interrupt来通知那个线程,以及被停止的线程如何进行配合

如何正确停止线程

在普通情况下停止线程

代码展示

  • 调用interrupt没有作用
  • 下面这段代码,执行interrupt之后,线程并没有被中断
  • 因为被执行的线程并没有相应中断的方式
public class stopThreadWithoutSleep  implements Runnable{public static void main(String[] args) throws InterruptedException {Thread thread = new Thread(new stopThreadWithoutSleep());thread.start();Thread.sleep(1000);thread.interrupt();}@Overridepublic void run() {int num = 0;while(num <= Integer.MAX_VALUE / 2) {if (num % 10000 == 0) {System.out.println(num + "是10000的倍数");}num++;}System.out.println("结束");}
}/*
由于太长,只展示结尾部分的结果
1073710000是10000的倍数
1073720000是10000的倍数
1073730000是10000的倍数
1073740000是10000的倍数
结束
* */
  • 被执行线程加上相应中断的操作之后
  • 结果可知,被执行线程相应一秒之后就结束了
public class stopThreadWithoutSleep  implements Runnable{public static void main(String[] args) throws InterruptedException {Thread thread = new Thread(new stopThreadWithoutSleep());thread.start();Thread.sleep(1000);thread.interrupt();}@Overridepublic void run() {int num = 0;while(!Thread.currentThread().isInterrupted() && num <= Integer.MAX_VALUE / 2) {if (num % 10000 == 0) {System.out.println(num + "是10000的倍数");}num++;}System.out.println("结束");}
}/*
由于太长,只展示结尾部分的结果
587830000是10000的倍数
587840000是10000的倍数
587850000是10000的倍数
587860000是10000的倍数
结束
* */

在阻塞情况下停止线程

代码展示

  • 中断之后,抛出异常
  • 线程在sleep的过程中,会catch到InterruptedException这个异常,从而相应中断
public class stopThreadWithSleep {public static void main(String[] args) {Runnable runnable = () -> {int num = 0;while (num <= 300 && !Thread.currentThread().isInterrupted()) {if (num % 100 == 0) {System.out.println(num + "是100的倍数");}num++;}try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}};Thread thread = new Thread(runnable);thread.start();try {Thread.sleep(500);} catch (InterruptedException e) {e.printStackTrace();}thread.interrupt();}
}/*
* 0是100的倍数
100是100的倍数
200是100的倍数
300是100的倍数
java.lang.InterruptedException: sleep interruptedat java.lang.Thread.sleep(Native Method)at com.jx.JavaTest.stopThread.stopThreadWithSleep.lambda$main$0(stopThreadWithSleep.java:15)at java.lang.Thread.run(Thread.java:748)
* */

线程在每次迭代后都阻塞

代码展示

  • 即使不在while判断是否中断,sleep也能中断异常
public class stopThreadWithSleepEveryLoop {public static void main(String[] args) {Runnable runnable = () -> {int num = 0;try {while (num <= 10000) {if (num % 100 == 0) {System.out.println(num + "是100的倍数");}num++;Thread.sleep(10);}} catch (InterruptedException e) {e.printStackTrace();}};Thread thread = new Thread(runnable);thread.start();try {Thread.sleep(5000);} catch (InterruptedException e) {e.printStackTrace();}thread.interrupt();}
}/*
* 0是100的倍数
100是100的倍数
200是100的倍数
300是100的倍数
java.lang.InterruptedException: sleep interruptedat java.lang.Thread.sleep(Native Method)at com.jx.JavaTest.stopThread.stopThreadWithSleepEveryLoop.lambda$main$0(stopThreadWithSleepEveryLoop.java:15)at java.lang.Thread.run(Thread.java:748)Process finished with exit code 0*
* */
  • 当catch写到while内,则不能正常中断
public class CantInterrupt {public static void main(String[] args) {Runnable runnable = () -> {int num = 0;while (num <= 10000) {if (num % 100 == 0) {System.out.println(num + "是100的倍数");}num ++;try {Thread.sleep(10);} catch (InterruptedException e) {e.printStackTrace();}}};Thread thread = new Thread(runnable);thread.start();try {Thread.sleep(5000);} catch (InterruptedException e) {e.printStackTrace();}thread.interrupt();}
}/*
* 0是100的倍数
100是100的倍数
200是100的倍数
300是100的倍数
java.lang.InterruptedException: sleep interruptedat java.lang.Thread.sleep(Native Method)at com.jx.JavaTest.stopThread.CantInterrupt.lambda$main$0(CantInterrupt.java:14)at java.lang.Thread.run(Thread.java:748)
400是100的倍数
500是100的倍数
600是100的倍数
700是100的倍数
800是100的倍数
900是100的倍数Process finished with exit code -1* */
  • 即使在while的判断条件中,加上检测中断的机制,也不能正常中断
  • 因为java的sleep函数,一旦相应中断,就会将中断的标志位删除
public class CantInterrupt {public static void main(String[] args) {Runnable runnable = () -> {int num = 0;while (num <= 10000 && !Thread.currentThread().isInterrupted()) {if (num % 100 == 0) {System.out.println(num + "是100的倍数");}num++;try {Thread.sleep(10);} catch (InterruptedException e) {e.printStackTrace();}}};Thread thread = new Thread(runnable);thread.start();try {Thread.sleep(5000);} catch (InterruptedException e) {e.printStackTrace();}thread.interrupt();}
}/*
0是100的倍数
100是100的倍数
200是100的倍数
300是100的倍数
java.lang.InterruptedException: sleep interruptedat java.lang.Thread.sleep(Native Method)at com.jx.JavaTest.stopThread.CantInterrupt.lambda$main$0(CantInterrupt.java:14)at java.lang.Thread.run(Thread.java:748)
400是100的倍数
500是100的倍数Process finished with exit code -1* */

停止线程的最佳实践

  • 在方法签名中抛出异常,在run方法中强制进行try catch
public class StopThreadInProd implements Runnable{public static void main(String[] args) throws InterruptedException {Thread thread = new Thread(new StopThreadInProd());thread.start();Thread.sleep(1000);thread.interrupt();}@Overridepublic void run() {while (true) {System.out.println("start");try {throwInMethod();} catch (InterruptedException e) {System.out.println("保存日志/关闭程序");e.printStackTrace();}}}private void throwInMethod() throws InterruptedException {Thread.sleep(2000);}
}/*
* start
保存日志/关闭程序
start
java.lang.InterruptedException: sleep interruptedat java.lang.Thread.sleep(Native Method)at com.jx.JavaTest.stopThread.StopThreadInProd.throwInMethod(StopThreadInProd.java:26)at com.jx.JavaTest.stopThread.StopThreadInProd.run(StopThreadInProd.java:17)at java.lang.Thread.run(Thread.java:748)
start
startProcess finished with exit code -1*
* */
  • 在catch语句中调用Thread.currentThread().interrupt恢复中断状态
  • 结果:抛出异常,程序结束
public class StopThreadInProd2 implements Runnable{public static void main(String[] args) throws InterruptedException {Thread thread = new Thread(new StopThreadInProd2());thread.start();Thread.sleep(1000);thread.interrupt();}@Overridepublic void run() {while (true) {if (Thread.currentThread().isInterrupted()) {System.out.println("Interrupt");break;}reInterrupt();}}private void reInterrupt() {try {Thread.sleep(2000);} catch (InterruptedException e) {Thread.currentThread().interrupt();e.printStackTrace();}}
}/*
java.lang.InterruptedException: sleep interruptedat java.lang.Thread.sleep(Native Method)at com.jx.JavaTest.stopThread.StopThreadInProd2.reInterrupt(StopThreadInProd2.java:25)at com.jx.JavaTest.stopThread.StopThreadInProd2.run(StopThreadInProd2.java:19)at java.lang.Thread.run(Thread.java:748)
Interrupt
*
* */
  • 依照上面的代码,如果方法没有没有重新抛出异常
  • 结果:程序抛出异常,但是程序没有停止运行
public class StopThreadInProd2 implements Runnable{public static void main(String[] args) throws InterruptedException {Thread thread = new Thread(new StopThreadInProd2());thread.start();Thread.sleep(1000);thread.interrupt();}@Overridepublic void run() {while (true) {if (Thread.currentThread().isInterrupted()) {System.out.println("Interrupt");break;}reInterrupt();}}private void reInterrupt() {try {Thread.sleep(2000);} catch (InterruptedException e) {//            Thread.currentThread().interrupt();e.printStackTrace();}}
}/*
java.lang.InterruptedException: sleep interruptedat java.lang.Thread.sleep(Native Method)at com.jx.JavaTest.stopThread.StopThreadInProd2.reInterrupt(StopThreadInProd2.java:25)at com.jx.JavaTest.stopThread.StopThreadInProd2.run(StopThreadInProd2.java:19)at java.lang.Thread.run(Thread.java:748)
*
* */

错误停止的方法

被弃用的stop,suspend和resume方法

  • 使用stop停止线程,会导致线程运行一半突然停止,没办法完成最基本的操作,会造成脏数据
  • 下面这段代码的结果会造成一个连队只有部分人领取到了装备
  • stop是不安全的,会直接停止监视器
  • suspend和resume不会破坏对象,但是会让线程挂起,不释放锁,容易造成死锁
public class StopThread implements Runnable{@Overridepublic void run() {// 模拟指挥军队,一共五个连队,每个连队一百人// 以连队为单位发放武器for (int i = 0; i < 5; i++) {System.out.println("连队" + i + "领取武器");for (int j = 0; j < 10; j++) {System.out.println(j);try {Thread.sleep(50);} catch (InterruptedException e) {e.printStackTrace();}}System.out.println("连队" + i + "领取完毕");}}public static void main(String[] args) {Thread thread = new Thread(new StopThread());thread.start();try {thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}thread.stop();}
}/*
* 连队0领取武器
0
1
2
3
4
5
6
7
8
9
连队0领取完毕
连队1领取武器
0
1
2
3
4
5Process finished with exit code 0* */

用volatile设置boolean标记位

  • 下面这段代码,通过改变标志位的值会成功终止线程
public class Volatile implements Runnable {private volatile boolean canceled = false;@Overridepublic void run() {int num = 0;try {while (num <= 10000 && !canceled) {if (num % 100 == 0) {System.out.println(num + " 是100的倍数");}num++;Thread.sleep(1);}} catch (InterruptedException e) {e.printStackTrace();}}public static void main(String[] args) throws InterruptedException {Volatile v = new Volatile();Thread thread = new Thread(v);thread.start();Thread.sleep(1000);v.canceled = true;}}/*
*0 是100的倍数
100 是100的倍数
200 是100的倍数
300 是100的倍数
400 是100的倍数
500 是100的倍数
600 是100的倍数Process finished with exit code 0*
* */
  • 当陷入阻塞的时候,是无法停止线程的
  • 下面这段代码的运行结果,并没有打印生产者停止运行,说明根本没有执行生产者的finally那部分代码
  • 同时程序也没停止
  • 原因见生产者代码 while循环中的注释
// 模拟生产者和消费者
public class cantStop {public static void main(String[] args) throws InterruptedException {// 阻塞队列// 满了之后,放不进去// 空的时候取数据,也会堵塞ArrayBlockingQueue storage = new ArrayBlockingQueue(10);Producer producer = new Producer(storage);Thread producerThread = new Thread(producer);producerThread.start();Thread.sleep(1000);Consumer consumer = new Consumer(storage);while (consumer.needMore()) {System.out.println(consumer.storage.take() + "被消费");Thread.sleep(100);}System.out.println("消费者不需要更多数据");// 消费者不需要数据,让生产者停下来producer.canceled = true;}}// 生产者
class Producer implements Runnable {public volatile boolean canceled = false;BlockingQueue storage;public Producer(BlockingQueue storage) {this.storage = storage;}@Overridepublic void run() {int num = 0;try {while (num <= 10000 && !canceled) {if (num % 100 == 0) {// 当堵塞队列满了之后,会堵塞在这里,而这段代码没有判断机制storage.put(num);System.out.println("num" + "生产");}num++;}} catch (InterruptedException e) {e.printStackTrace();} finally {System.out.println("生产者停止运行");}}
}// 消费者
class Consumer {BlockingQueue storage;public Consumer(BlockingQueue storage) {this.storage = storage;}public boolean needMore() {if (Math.random() > 0.9) {return false;}return true;}
}/*
* num生产
num生产
num生产
num生产
num生产
num生产
num生产
num生产
num生产
num生产
0被消费
num生产
消费者不需要更多数据*
* */
  • 将上面代码用interrupt进行中断
  • 程序成功停止
public class finxed {public static void main(String[] args) throws InterruptedException {finxed finxed = new finxed();// 阻塞队列// 满了之后,放不进去// 空的时候取数据,也会堵塞ArrayBlockingQueue storage = new ArrayBlockingQueue(10);Producer producer = finxed.new Producer(storage);Thread producerThread = new Thread(producer);producerThread.start();Thread.sleep(1000);Consumer consumer = finxed.new Consumer(storage);while (consumer.needMore()) {System.out.println(consumer.storage.take() + "被消费");Thread.sleep(100);}System.out.println("消费者不需要更多数据");// 消费者不需要数据,让生产者停下来producerThread.interrupt();}class Producer implements Runnable {public volatile boolean canceled = false;BlockingQueue storage;public Producer(BlockingQueue storage) {this.storage = storage;}@Overridepublic void run() {int num = 0;try {while (num <= 10000 && !Thread.currentThread().isInterrupted()) {if (num % 100 == 0) {storage.put(num);System.out.println("num" + "生产");}num++;}} catch (InterruptedException e) {e.printStackTrace();} finally {System.out.println("生产者停止运行");}}}class Consumer {BlockingQueue storage;public Consumer(BlockingQueue storage) {this.storage = storage;}public boolean needMore() {if (Math.random() > 0.9) {return false;}return true;}}}/*
* 2100被消费
num生产
2200被消费
num生产
2300被消费
num生产
消费者不需要更多数据
生产者停止运行
java.lang.InterruptedExceptionat java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.reportInterruptAfterWait(AbstractQueuedSynchronizer.java:2014)at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:2048)at java.util.concurrent.ArrayBlockingQueue.put(ArrayBlockingQueue.java:353)at com.jx.JavaTest.stopThread.volatiledmo.finxed$Producer.run(finxed.java:51)at java.lang.Thread.run(Thread.java:748)Process finished with exit code 0*
* */

interrupt源码查看

  • 这段代码做的都是一些判断,真正执行中断的代码时interrupt0
  • interrupt0是native代码
public void interrupt() {if (this != Thread.currentThread())checkAccess();synchronized (blockerLock) {Interruptible b = blocker;if (b != null) {interrupt0();           // Just to set the interrupt flagb.interrupt(this);return;}}interrupt0();
}private native void interrupt0();

interrupt相关函数练习

  • isInterrupted获取中断标志,获取的是前面的线程
  • interrupted获取中断标志并重置,只关心执行的线程,所以下面代码执行的是main线程
public class InterruptedTest {public static void main(String[] args) throws InterruptedException {Thread thread = new Thread(new Runnable() {@Overridepublic void run() {while (true) {}}});thread.start();thread.interrupt();// 获取中断标志System.out.println(thread.isInterrupted()); // true// 获取中断标志并重置System.out.println(thread.interrupted()); //falseSystem.out.println(Thread.interrupted()); // falseSystem.out.println(thread.isInterrupted()); //truethread.join();System.out.println("over");}
}

java多线程-线程的停止【interrupt】相关推荐

  1. Java 多线程线程安全(面试概念解答二)

    Java 多线程线程安全 什么是线程安全? 为什么有线程安全问题? 线程安全解决办法? 同步代码块 同步函数 静态同步函数 多线程死锁 多线程的三大特性 原子性 可见性 有序性 Java内存模型 Vo ...

  2. Java多线程——线程的优先级和生命周期

    Java多线程--线程的优先级和生命周期 摘要:本文主要介绍了线程的优先级以及线程有哪些生命周期. 部分内容来自以下博客: https://www.cnblogs.com/sunddenly/p/41 ...

  3. java多线程 线程安全_Java中的线程安全

    java多线程 线程安全 Thread Safety in Java is a very important topic. Java provides multi-threaded environme ...

  4. JAVA --- 多线程 -- 线程的创建

    JAVA - 多线程 – 线程的创建 线程的概念: 说起线程,先说程序和进程,多任务的概念. 程序(program):是指令和数据的有序集合,本身没有任何运行的含义,是一个静态的概念. 进程(proc ...

  5. Java多线程(九)—— interrupt()和线程终止方式

    一.interrupt() 说明 interrupt()的作用是中断本线程. 本线程中断自己是被允许的:其它线程调用本线程的interrupt()方法时,会通过checkAccess()检查权限.这有 ...

  6. Java多线程-线程的创建(Thread类的基本使用)

    文章目录 一. 线程和Thread类 1. 线程和Thread类 1.1 Thread类的构造方法 1.2 启用线程的相关方法 2. 创建第一个Java多线程程序 3. 使用Runnable对象创建线 ...

  7. Java多线程-线程的同步与锁

    一.同步问题提出 线程的同步是为了防止多个线程访问一个数据对象时,对数据造成的破坏. 例如:两个线程ThreadA.ThreadB都操作同一个对象Foo对象,并修改Foo对象上的数据. package ...

  8. Java多线程 ——线程基础和锁锁锁

    Java多线程(一) 一.线程的定义 二.Synchronize线程同步 三.偏向锁.自旋锁.重量级锁 四.volatile关键字 4.1.普通变量运算的物理意义 4.2.有无解决的方案 4.3.vo ...

  9. 【Java系列】(四)Java多线程---线程安全

    前言: 记得大一刚学Java的时候,老师带着我们做了一个局域网聊天室,用到了AWT.Socket.多线程.I/O,编写的客户端和服务器,当时做出来很兴奋,回学校给同学们演示,感觉自己好NB,呵呵,扯远 ...

最新文章

  1. 我的FizzBuzz和一点感想
  2. Mac OS使用技巧十九:Safari碉堡功能之二查看网页源代码
  3. 修改系统UIAlertAction的按钮颜色
  4. P4945-最后的战役【dp,离散化】
  5. 手机游戏赚钱到底有多难?接入运营商或需一年
  6. 嵌入式成长轨迹25 【Linux应用编程强化】【Linux下的C编程 下】【实例:客户端/服务器端程序】...
  7. node.js——麻将算法(二)赖子玩法
  8. MySQL数据库优化技术之数据库表的设计
  9. 【优化分类】基于matlab遗传算法结合爬山算法优化极限学习机分类【含Matlab源码 1660期】
  10. kali linux添加环境变量
  11. 世界主要国家地区英文名称,缩写代码
  12. 【python + FFmpeg】对视频进行分辨率改变,(带音频)
  13. 动态规划基础之挖金矿问题
  14. PPT插入图片为任意形状
  15. 人、机客户服务质量 - 实时透视分析
  16. UITextField格式化银行卡号码解决方案
  17. 富文本ueditor工具应用于JavaWeb项目
  18. javascript函数总结
  19. stm32呼吸灯c语言程序,STM32使用PWM控制LED呼吸灯效果
  20. 分文件编辑报错信息有.bss

热门文章

  1. 计算机网络与通信之局域网
  2. IBinder对象在进程间传递的形式(二)
  3. Android修炼之道—Talker聊天小工具
  4. 【Python】出现SyntaxError: invalid syntax的原因总结
  5. Matplotlib绘制图片——膨胀算法
  6. Chomsky文法分类
  7. 一般迭代法与steffensen迭代法matlab实现
  8. 选择香港虚拟主机需要注意的,如何选购优质的虚拟主机
  9. mysql里面的时间函数
  10. xxe漏洞原理与防御