一。关于终止线程stop与interrupt

  一般来说,线程执行结束后就变成消亡状态,乍看之下我们并不需要人为进行干预(人为停止线程),不过凡事都有例外吧,在服务器或者其他应用场景下,线程为了提供服务而一直在不停的运转,因此必要时刻我们还需“人为干涉的”。

  通常情况下,终止线程有两种方式:stop与interrupt

  1) stop:暴力的停止线程(不管线程执行到哪段代码,立刻干掉),这个方法因为过于暴力会导致安全问题,因此JDK不推荐使用。

  2) interrupt:优雅停止,调用该方法会通知线程可以进行停止操作了,此时线程只是变成可停止状态(thread.isInterrupted的值为true),实际上并没有停止

  请看下段代码:

  

  1. package com.bdqn.lyrk.basic;
  2.  
  3. /**
  4. * 一个线程设置共享变量的值,保持ID与name值相同
  5. * 另外一个线程读取共享变量的值,发现ID与name值不同时打印
  6. *
  7. * @author chen.nie
  8. * @date 2018/1/30
  9. **/
  10. public class StopThreadUnsafe {
  11.  
  12. public static User user = new User();
  13.  
  14. public static class User {
  15. private int id;
  16. private String name;
  17.  
  18. public int getId() {
  19. return id;
  20. }
  21.  
  22. public void setId(int id) {
  23. this.id = id;
  24. }
  25.  
  26. public String getName() {
  27. return name;
  28. }
  29.  
  30. public void setName(String name) {
  31. this.name = name;
  32. }
  33.  
  34. public User() {
  35. id = 0;
  36. name = "0";
  37. }
  38.  
  39. @Override
  40. public String toString() {
  41. return "User [id=" + id + ",name=" + name + "]";
  42. }
  43. }
  44.  
  45. public static class ChangeObjectThread extends Thread {
  46.  
  47. @Override
  48. public void run() {
  49. while (true) {
  50. synchronized (user) {
  51. if (Thread.currentThread().isInterrupted()) {
  52. break;
  53. }
  54. int i = (int) System.currentTimeMillis() / 1000;
  55. user.setId(i);
  56. try {
  57. Thread.sleep(100);
  58. } catch (InterruptedException e) {
  59. Thread.currentThread().interrupt();
  60. }
  61. user.setName("" + i);
  62.  
  63. }
  64. Thread.yield();
  65. }
  66. }
  67. }
  68.  
  69. public static class ReadObjectThread extends Thread {
  70.  
  71. @Override
  72. public void run() {
  73. while (true) {
  74. synchronized (user) {
  75. if (user.getId() != Integer.parseInt(user.getName())) {
  76. System.out.println(user);
  77. }
  78. }
  79. Thread.yield();
  80. }
  81. }
  82. }
  83. }

  Main方法:

  1. package com.bdqn.lyrk.basic;
  2.  
  3. public class Main {
  4. public static void main(String[] args) throws InterruptedException {
  5. new StopThreadUnsafe.ReadObjectThread().start();
  6. while (true) {
  7. StopThreadUnsafe.ChangeObjectThread thread = new StopThreadUnsafe.ChangeObjectThread();
  8. thread.start();
  9. Thread.sleep(200);
  10. thread.stop();
  11. // thread.interrupt();
  12. }
  13. }
  14. }

  此时调用stop终止线程时,得到如下结果

  

  1. User [id=1197577,name=1197576]
  2. User [id=1197577,name=1197576]
  3. User [id=1197577,name=1197576]
  4. User [id=1197577,name=1197576]
  5. User [id=1197578,name=1197577]

原因很简单:stop方法会释放对象锁,并终止线程,当线程还没有与name赋值时,已经被干掉了因此其他线程在读取时,很有可能读到NAME与ID值不一致的情况

二。守护线程Daemon

守护线程顾名思义,是系统的守护者,这个线程为系统的运行默默提供服务,当系统任务运行完毕,守护线程也就完成使命了,比如说垃圾回收线程,JIT线程都是守护线程,设置守护线程的方式:在调用start方法前,通过线程对象.setDaemon(true)

代码如下:

  1. package com.bdqn.lyrk.basic;
  2.  
  3. public class DaemonDemo {
  4. public static class DaemonT extends Thread {
  5. @Override
  6. public void run() {
  7. while (true){
  8. System.out.println("I am alive");
  9. try {
  10. Thread.sleep(1000);
  11. } catch (InterruptedException e) {
  12. e.printStackTrace();
  13. }
  14. }
  15. }
  16. }
  17.  
  18. public static void main(String[] args) throws InterruptedException {
  19. DaemonT daemonT = new DaemonT();
  20. daemonT.setDaemon(true);
  21. daemonT.start();
  22. Thread.sleep(5000);
  23. }
  24. }

运行结果

  1. I am alive
  2. I am alive
  3. I am alive
  4. I am alive
  5. I am alive
  6.  
  7. Process finished with exit code 0

我们可以看到,当主线程执行完毕后,守护线程也随之结束

三。wait与notify

  wait与notify是多线程协同工作的最基本手段,可是这两个方法属于Object的方法,当需要使用wait和notify时,必须配合synchronized使用,此时调用wait方法,当前线程会进入等待队列并释放当前的对象锁,直到线程被唤醒(notify),notify方法会随机唤醒一个在等待队列中的线程,notifyAll方法则唤醒所有在等待队列中的线程

代码示例:

  1. package com.bdqn.lyrk.basic;
  2.  
  3. public class SimpleWN {
  4. public static final Object object = new Object();
  5.  
  6. public static class T1 extends Thread {
  7.  
  8. @Override
  9. public void run() {
  10. synchronized (object) {
  11. System.out.println("开始执行线程...");
  12. try {
  13. object.wait();
  14. } catch (InterruptedException e) {
  15. e.printStackTrace();
  16. }
  17. System.out.println("结束执行线程...");
  18. }
  19. }
  20. }
  21.  
  22. public static class T2 extends Thread {
  23. @Override
  24. public void run() {
  25. synchronized (object) {
  26. System.out.println("5秒后准备唤醒线程..");
  27. try {
  28. Thread.sleep(5000);
  29. } catch (InterruptedException e) {
  30. e.printStackTrace();
  31. }
  32. object.notify();
  33. }
  34. }
  35. }
  36.  
  37. public static void main(String[] args) {
  38. T1 t1 = new T1();
  39. T2 t2 = new T2();
  40. t1.start();
  41. t2.start();
  42. }
  43. }

输出内容:

  1. 开始执行线程...
  2. 5秒后准备唤醒线程..
  3. 结束执行线程...
  4.  
  5. Process finished with exit code 0

注意以下几点:

1)当线程T1被notify过后,也必须要重新获取对象锁,才能够继续执行

2)sleep也能达到wait的效果,但是唯一区别时,sleep时并不会释放对象锁,因此其他线程并没有得到执行的机会

关于java线程中stop interrupt daemon wait notify的更多相关文章

  1. java线程中的sleep/wait/notify/yield/interrupt方法 整理

    java线程中的sleep/wait/notify/yield/interrupt方法 sleep 该方法能够使当前线程休眠一段时间 休眠期间,不释放锁 休眠时间结束之后,进入可执行状态,加入到线程就 ...

  2. java线程中的interrupt,isInterrupt,interrupted方法

    在java的线程Thread类中有三个方法,比较容易混淆,在这里解释一下 (1)interrupt:置线程的中断状态 (2)isInterrupt:线程是否中断 (3)interrupted:返回线程 ...

  3. java线程中的sleep和wait区别

                                                                            面试题:java线程中sleep和wait的区别以及其资 ...

  4. Java 线程的终止-interrupt

    Java线程的终止——interrupt 取消/关闭的场景 我们知道,通过线程的start方法启动一个线程后,线程开始执行run方法,run方法运行结束后线程退出,那为什么还需要结束一个线程呢?有多种 ...

  5. 在Java 线程中返回值的用法

    http://icgemu.iteye.com/blog/467848 在Java 线程中返回值的用法 博客分类: Java Javathread  有时在执行线程中需要在线程中返回一个值:常规中我们 ...

  6. 并发编程——线程中sleep(),yield(),join(),wait(),notify(),notifyAll()区别

    前言 今天简单的讲一讲线程中sleep(),join(),yield(),wait(),notify(),notifyAll()这些方法的使用以及区别. 不过在讲这些方法之前,需要简单的介绍一下锁池和 ...

  7. 停止Java线程,小心interrupt()方法

    来源:http://blog.csdn.net/wxwzy738/article/details/8516253 程序是很简易的.然而,在编程人员面前,多线程呈现出了一组新的难题,如果没有被恰当的解决 ...

  8. Java - 线程Join与interrupt

    Java多线程系列--“基础篇”08之 join() 概要 本章,会对Thread中join()方法进行介绍.涉及到的内容包括:1. join()介绍2. join()源码分析(基于JDK1.7.0_ ...

  9. 为什么JAVA线程中没有Running状态?

    面试官问:为什么 Java 线程没有 Running 状态?我懵了 —— 转  芋道源码 什么是 RUNNABLE? 与传统的ready状态的区别 与传统的running状态的区别 当I/O阻塞时 如 ...

随机推荐

  1. Struts2之配置

    Struts2的默认配置文件是struts.xml放在/web-inf/classes目录下,struts配置文件的最大作用就是配置Action与请求之间的对应关系,并配置逻辑视图名和物理视图名之间的 ...

  2. LR录制脚本的时候打不开浏览器问题

    使用Chrome时,显示开始录制但是Action中无任何脚本,即脚本没成功生成. 使用Firefox(最新版),一直关闭程序,详细信息有StackHash_0a9e. 使用IE11时,也是显示开始录制 ...

  3. map的infowindow的show事件(ArcGIS API for JS)

  4. jupyter notebook下python2和python3共存(Ubuntu)

    提示NOTICE 时间:2018/04/06 主题:Ubuntu 下CAFFE框架 主角:Jupyter Notebook 简介: Jupyter Notebook(此前被称为 IPython not ...

  5. ASP.NET CORE 自定义视图组件(ViewComponent)注意事项

    *红色字体为固定命名,蓝色为一般命名规则,黄色为ASP.NET CORE 默认查找文件名 概要:1.简单ViewComponent的用法 2.ViewComponent控制器返回值  3.注意事项 1 ...

  6. SiteMesh在项目中的配置

    SiteMesh在项目中的配置 首先在web.xml里面增加siteMesh的配置: <filter> <filter-name>sitemesh</filter-nam ...

  7. 新概念英语(1-135)The latest report

    Lesson 135 The latest report 最新消息 Listen to the tape then answer this question. Is Karen Marsh going ...

  8. codeforces round 425 div2

    A. Sasha and Sticks 水题,判断一下次数的奇和偶就可以的. B. Petya and Exam 赛上的时候没有写出来,orz,记录一下吧. 题意:给出一个模式串,可能会有?和*两种符 ...

  9. 28.C++- 单例类模板(详解)

    单例类 描述 指在整个系统生命期中,一个类最多只能有一个实例(instance)存在,使得该实例的唯一性(实例是指一个对象指针)  , 比如:统计在线人数 在单例类里,又分为了懒汉式和饿汉式,它们的区 ...

  10. Scale

    Scale刻度组件. 当你希望用户输入某个范围内的一个数值,使用scale组件可以很好的代替Entry组件. 用法: 创建一个指定范围的Scale组件其实非常容易,你只需要指定from和to两个选项即 ...