关于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时并不会释放对象锁,因此其他线程并没有得到执行的机会

目录
相关文章
|
7天前
|
安全 Java 开发者
深入解读JAVA多线程:wait()、notify()、notifyAll()的奥秘
在Java多线程编程中,`wait()`、`notify()`和`notifyAll()`方法是实现线程间通信和同步的关键机制。这些方法定义在`java.lang.Object`类中,每个Java对象都可以作为线程间通信的媒介。本文将详细解析这三个方法的使用方法和最佳实践,帮助开发者更高效地进行多线程编程。 示例代码展示了如何在同步方法中使用这些方法,确保线程安全和高效的通信。
27 9
|
10天前
|
存储 安全 Java
Java多线程编程的艺术:从基础到实践####
本文深入探讨了Java多线程编程的核心概念、应用场景及其实现方式,旨在帮助开发者理解并掌握多线程编程的基本技能。文章首先概述了多线程的重要性和常见挑战,随后详细介绍了Java中创建和管理线程的两种主要方式:继承Thread类与实现Runnable接口。通过实例代码,本文展示了如何正确启动、运行及同步线程,以及如何处理线程间的通信与协作问题。最后,文章总结了多线程编程的最佳实践,为读者在实际项目中应用多线程技术提供了宝贵的参考。 ####
|
7天前
|
监控 安全 Java
Java中的多线程编程:从入门到实践####
本文将深入浅出地探讨Java多线程编程的核心概念、应用场景及实践技巧。不同于传统的摘要形式,本文将以一个简短的代码示例作为开篇,直接展示多线程的魅力,随后再详细解析其背后的原理与实现方式,旨在帮助读者快速理解并掌握Java多线程编程的基本技能。 ```java // 简单的多线程示例:创建两个线程,分别打印不同的消息 public class SimpleMultithreading { public static void main(String[] args) { Thread thread1 = new Thread(() -> System.out.prin
|
9天前
|
安全 Java
Java多线程集合类
本文介绍了Java中线程安全的问题及解决方案。通过示例代码展示了使用`CopyOnWriteArrayList`、`CopyOnWriteArraySet`和`ConcurrentHashMap`来解决多线程环境下集合操作的线程安全问题。这些类通过不同的机制确保了线程安全,提高了并发性能。
|
10天前
|
Java
java小知识—进程和线程
进程 进程是程序的一次执行过程,是系统运行的基本单位,因此进程是动态的。系统运行一个程序即是一个进程从创建,运行到消亡的过程。简单来说,一个进程就是一个执行中的程序,它在计算机中一个指令接着一个指令地执行着,同时,每个进程还占有某些系统资源如CPU时间,内存空间,文件,文件,输入输出设备的使用权等等。换句话说,当程序在执行时,将会被操作系统载入内存中。 线程 线程,与进程相似,但线程是一个比进程更小的执行单位。一个进程在其执行的过程中产生多个线程。与进程不同的是同类的多个线程共享同一块内存空间和一组系统资源,所以系统在产生一个线程,或是在各个线程之间做切换工作时,负担要比
21 1
|
1月前
|
存储 消息中间件 资源调度
C++ 多线程之初识多线程
这篇文章介绍了C++多线程的基本概念,包括进程和线程的定义、并发的实现方式,以及如何在C++中创建和管理线程,包括使用`std::thread`库、线程的join和detach方法,并通过示例代码展示了如何创建和使用多线程。
43 1
C++ 多线程之初识多线程
|
25天前
|
Java 开发者
在Java多线程编程中,创建线程的方法有两种:继承Thread类和实现Runnable接口
【10月更文挑战第20天】在Java多线程编程中,创建线程的方法有两种:继承Thread类和实现Runnable接口。本文揭示了这两种方式的微妙差异和潜在陷阱,帮助你更好地理解和选择适合项目需求的线程创建方式。
19 3
|
25天前
|
Java 开发者
在Java多线程编程中,选择合适的线程创建方法至关重要
【10月更文挑战第20天】在Java多线程编程中,选择合适的线程创建方法至关重要。本文通过案例分析,探讨了继承Thread类和实现Runnable接口两种方法的优缺点及适用场景,帮助开发者做出明智的选择。
16 2
|
25天前
|
Java
Java中多线程编程的基本概念和创建线程的两种主要方式:继承Thread类和实现Runnable接口
【10月更文挑战第20天】《JAVA多线程深度解析:线程的创建之路》介绍了Java中多线程编程的基本概念和创建线程的两种主要方式:继承Thread类和实现Runnable接口。文章详细讲解了每种方式的实现方法、优缺点及适用场景,帮助读者更好地理解和掌握多线程编程技术,为复杂任务的高效处理奠定基础。
28 2
|
25天前
|
Java 开发者
Java多线程初学者指南:介绍通过继承Thread类与实现Runnable接口两种方式创建线程的方法及其优缺点
【10月更文挑战第20天】Java多线程初学者指南:介绍通过继承Thread类与实现Runnable接口两种方式创建线程的方法及其优缺点,重点解析为何实现Runnable接口更具灵活性、资源共享及易于管理的优势。
28 1

热门文章

最新文章