关于java线程中stop interrupt daemon wait notify
一。关于终止线程stop与interrupt
一般来说,线程执行结束后就变成消亡状态,乍看之下我们并不需要人为进行干预(人为停止线程),不过凡事都有例外吧,在服务器或者其他应用场景下,线程为了提供服务而一直在不停的运转,因此必要时刻我们还需“人为干涉的”。
通常情况下,终止线程有两种方式:stop与interrupt
1) stop:暴力的停止线程(不管线程执行到哪段代码,立刻干掉),这个方法因为过于暴力会导致安全问题,因此JDK不推荐使用。
2) interrupt:优雅停止,调用该方法会通知线程可以进行停止操作了,此时线程只是变成可停止状态(thread.isInterrupted的值为true),实际上并没有停止
请看下段代码:
package com.bdqn.lyrk.basic; /**
* 一个线程设置共享变量的值,保持ID与name值相同
* 另外一个线程读取共享变量的值,发现ID与name值不同时打印
*
* @author chen.nie
* @date 2018/1/30
**/
public class StopThreadUnsafe { public static User user = new User(); public static class User {
private int id;
private String name; public int getId() {
return id;
} public void setId(int id) {
this.id = id;
} public String getName() {
return name;
} public void setName(String name) {
this.name = name;
} public User() {
id = 0;
name = "0";
} @Override
public String toString() {
return "User [id=" + id + ",name=" + name + "]";
}
} public static class ChangeObjectThread extends Thread { @Override
public void run() {
while (true) {
synchronized (user) {
if (Thread.currentThread().isInterrupted()) {
break;
}
int i = (int) System.currentTimeMillis() / 1000;
user.setId(i);
try {
Thread.sleep(100);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
user.setName("" + i); }
Thread.yield();
}
}
} public static class ReadObjectThread extends Thread { @Override
public void run() {
while (true) {
synchronized (user) {
if (user.getId() != Integer.parseInt(user.getName())) {
System.out.println(user);
}
}
Thread.yield();
}
}
}
}
Main方法:
package com.bdqn.lyrk.basic;
public class Main {
public static void main(String[] args) throws InterruptedException {
new StopThreadUnsafe.ReadObjectThread().start();
while (true) {
StopThreadUnsafe.ChangeObjectThread thread = new StopThreadUnsafe.ChangeObjectThread();
thread.start();
Thread.sleep(200);
thread.stop();
// thread.interrupt();
}
}
}
此时调用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)
代码如下:
package com.bdqn.lyrk.basic;
public class DaemonDemo {
public static class DaemonT extends Thread {
@Override
public void run() {
while (true){
System.out.println("I am alive");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public static void main(String[] args) throws InterruptedException {
DaemonT daemonT = new DaemonT();
daemonT.setDaemon(true);
daemonT.start();
Thread.sleep(5000);
}
}
运行结果
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方法则唤醒所有在等待队列中的线程
代码示例:
package com.bdqn.lyrk.basic;
public class SimpleWN {
public static final Object object = new Object();
public static class T1 extends Thread {
@Override
public void run() {
synchronized (object) {
System.out.println("开始执行线程...");
try {
object.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("结束执行线程...");
}
}
}
public static class T2 extends Thread {
@Override
public void run() {
synchronized (object) {
System.out.println("5秒后准备唤醒线程..");
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
object.notify();
}
}
}
public static void main(String[] args) {
T1 t1 = new T1();
T2 t2 = new T2();
t1.start();
t2.start();
}
}
输出内容:
开始执行线程...
5秒后准备唤醒线程..
结束执行线程... Process finished with exit code 0
注意以下几点:
1)当线程T1被notify过后,也必须要重新获取对象锁,才能够继续执行
2)sleep也能达到wait的效果,但是唯一区别时,sleep时并不会释放对象锁,因此其他线程并没有得到执行的机会
关于java线程中stop interrupt daemon wait notify的更多相关文章
- java线程中的sleep/wait/notify/yield/interrupt方法 整理
java线程中的sleep/wait/notify/yield/interrupt方法 sleep 该方法能够使当前线程休眠一段时间 休眠期间,不释放锁 休眠时间结束之后,进入可执行状态,加入到线程就 ...
- java线程中的interrupt,isInterrupt,interrupted方法
在java的线程Thread类中有三个方法,比较容易混淆,在这里解释一下 (1)interrupt:置线程的中断状态 (2)isInterrupt:线程是否中断 (3)interrupted:返回线程 ...
- java线程中的sleep和wait区别
面试题:java线程中sleep和wait的区别以及其资 ...
- Java 线程的终止-interrupt
Java线程的终止——interrupt 取消/关闭的场景 我们知道,通过线程的start方法启动一个线程后,线程开始执行run方法,run方法运行结束后线程退出,那为什么还需要结束一个线程呢?有多种 ...
- 在Java 线程中返回值的用法
http://icgemu.iteye.com/blog/467848 在Java 线程中返回值的用法 博客分类: Java Javathread 有时在执行线程中需要在线程中返回一个值:常规中我们 ...
- 并发编程——线程中sleep(),yield(),join(),wait(),notify(),notifyAll()区别
前言 今天简单的讲一讲线程中sleep(),join(),yield(),wait(),notify(),notifyAll()这些方法的使用以及区别. 不过在讲这些方法之前,需要简单的介绍一下锁池和 ...
- 停止Java线程,小心interrupt()方法
来源:http://blog.csdn.net/wxwzy738/article/details/8516253 程序是很简易的.然而,在编程人员面前,多线程呈现出了一组新的难题,如果没有被恰当的解决 ...
- Java - 线程Join与interrupt
Java多线程系列--“基础篇”08之 join() 概要 本章,会对Thread中join()方法进行介绍.涉及到的内容包括:1. join()介绍2. join()源码分析(基于JDK1.7.0_ ...
- 为什么JAVA线程中没有Running状态?
面试官问:为什么 Java 线程没有 Running 状态?我懵了 —— 转 芋道源码 什么是 RUNNABLE? 与传统的ready状态的区别 与传统的running状态的区别 当I/O阻塞时 如 ...
随机推荐
- nyoj水池数目
水池数目 时间限制:3000 ms | 内存限制:65535 KB 难度:4 描述 南阳理工学院校园里有一些小河和一些湖泊,现在,我们把它们通一看成水池,假设有一张我们学校的某处的地图,这个地 ...
- zookeeper安装及环境变量设置
下载 首先去官网下载(自行选择版本):http://mirror.bit.edu.cn/apache/zookeeper/zookeeper-3.4.11/然后执行tar -zxvf解压 对于后台安装 ...
- 微信qq,新浪等第三方授权登录的理解
偶们常说的第三方是指的微信,qq,新浪这些第三方,因为现在基本每个人都有qq或者微信,那么我们就可以通过这些第三方进行登录.而这些网站比如慕课网是通过第三方获取用户的基本信息 它会有个勾选按钮,提示是 ...
- Java基础类库简介
Java基础类库简介 一.常用的基础类库:11个jar(Java Archive,Java归档)包 作为java语言使用者,我们可以感受到java语言带来的优势(平台无关.面向对象.多线程.高效易扩展 ...
- python 中os.path.join 双斜杠的解决办法
这两天在写东西的时候遇到了这个问题,主要是上传图片之后,无法在页面展示,原因就出在用join 拼接的路径中出现了"\"而造成的. >>> import os &g ...
- 前端基础之html-Day12
1.web服务本质 import socket def main(): sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.bi ...
- istio入门(01)istio的优势在哪里?
Istio能做什么?Istio 试图解决微服务实施后面临的问题.Istio 提供了一个完整的解决方案,对整个服务网格行为洞察和操作控制,以满足微服务应用程序的多样化需求. Istio在服务网络中提供了 ...
- istio入门(05)istio的架构概念2
- 05_Linux目录文件操作命令2_我的Linux之路
这一节我们继续来学习Linux中对文件和目录的操作命令 mkdir 创建目录 mkdir (选项)(参数) 在Linux端可以使用mkdir来创建目录,如果你没有加其他的路径名,那么默认是在当前目录下 ...
- spring2——IOC之Bean的装配
spring容器对于bean的装配提供了两个接口容器分别是"ApplicationContext接口容器"和"BeanFactory接口容器",其中" ...