关于java线程中stop interrupt daemon wait notify

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

一。关于终止线程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 }
View Code

 

  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 }
View Code

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

  

User [id=1197577,name=1197576]
User [id=1197577,name=1197576]
User [id=1197577,name=1197576]
User [id=1197577,name=1197576]
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 }
View Code

运行结果

I am alive
I am alive
I am alive
I am alive
I am alive

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 }
View Code

输出内容:

开始执行线程...
5秒后准备唤醒线程..
结束执行线程...

Process finished with exit code 0

注意以下几点: 

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

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

目录
相关文章
|
5天前
|
安全 Java 调度
Java编程时多线程操作单核服务器可以不加锁吗?
Java编程时多线程操作单核服务器可以不加锁吗?
18 2
|
6天前
|
Java 调度
Java-Thread多线程的使用
这篇文章介绍了Java中Thread类多线程的创建、使用、生命周期、状态以及线程同步和死锁的概念和处理方法。
Java-Thread多线程的使用
|
4天前
|
Java 数据中心 微服务
Java高级知识:线程池隔离与信号量隔离的实战应用
在Java并发编程中,线程池隔离与信号量隔离是两种常用的资源隔离技术,它们在提高系统稳定性、防止系统过载方面发挥着重要作用。
6 0
|
6天前
|
Java 数据处理 调度
Java中的多线程编程:从基础到实践
本文深入探讨了Java中多线程编程的基本概念、实现方式及其在实际项目中的应用。首先,我们将了解什么是线程以及为何需要多线程编程。接着,文章将详细介绍如何在Java中创建和管理线程,包括继承Thread类、实现Runnable接口以及使用Executor框架等方法。此外,我们还将讨论线程同步和通信的问题,如互斥锁、信号量、条件变量等。最后,通过具体的示例展示了如何在实际项目中有效地利用多线程提高程序的性能和响应能力。
|
7天前
|
安全 算法 Java
Java中的多线程编程:从基础到高级应用
本文深入探讨了Java中的多线程编程,从最基础的概念入手,逐步引导读者了解并掌握多线程开发的核心技术。无论是初学者还是有一定经验的开发者,都能从中获益。通过实例和代码示例,本文详细讲解了线程的创建与管理、同步与锁机制、线程间通信以及高级并发工具等主题。此外,还讨论了多线程编程中常见的问题及其解决方案,帮助读者编写出高效、安全的多线程应用程序。
|
2月前
|
存储 监控 Java
Java多线程优化:提高线程池性能的技巧与实践
Java多线程优化:提高线程池性能的技巧与实践
64 1
|
5天前
|
数据采集 负载均衡 安全
LeetCode刷题 多线程编程九则 | 1188. 设计有限阻塞队列 1242. 多线程网页爬虫 1279. 红绿灯路口
本文提供了多个多线程编程问题的解决方案,包括设计有限阻塞队列、多线程网页爬虫、红绿灯路口等,每个问题都给出了至少一种实现方法,涵盖了互斥锁、条件变量、信号量等线程同步机制的使用。
LeetCode刷题 多线程编程九则 | 1188. 设计有限阻塞队列 1242. 多线程网页爬虫 1279. 红绿灯路口
|
12天前
|
Java Spring
spring多线程实现+合理设置最大线程数和核心线程数
本文介绍了手动设置线程池时的最大线程数和核心线程数配置方法,建议根据CPU核数及程序类型(CPU密集型或IO密集型)来合理设定。对于IO密集型,核心线程数设为CPU核数的两倍;CPU密集型则设为CPU核数加一。此外,还讨论了`maxPoolSize`、`keepAliveTime`、`allowCoreThreadTimeout`和`queueCapacity`等参数的设置策略,以确保线程池高效稳定运行。
72 10
spring多线程实现+合理设置最大线程数和核心线程数
|
21天前
|
Java 数据库 Android开发
一个Android App最少有几个线程?实现多线程的方式有哪些?
本文介绍了Android多线程编程的重要性及其实现方法,涵盖了基本概念、常见线程类型(如主线程、工作线程)以及多种多线程实现方式(如`Thread`、`HandlerThread`、`Executors`、Kotlin协程等)。通过合理的多线程管理,可大幅提升应用性能和用户体验。
36 15
一个Android App最少有几个线程?实现多线程的方式有哪些?
|
6天前
|
Python
5-5|python开启多线程入口必须在main,从python线程(而不是main线程)启动pyQt线程有什么坏处?...
5-5|python开启多线程入口必须在main,从python线程(而不是main线程)启动pyQt线程有什么坏处?...
下一篇
无影云桌面