Java - 安全的退出线程
stop() 存在的问题
使用 stop() 来退出线程是不安全的。它会解除由线程获取的所有锁,可能导致数据不一致。
举个例子:
public class StopTest {
public static void main(String[] args) throws Exception {
Person person = new Person();
person.setNameAndAge("Tom", 10);
MyThread thread = new MyThread(person);
thread.start();
Thread.sleep(500);
thread.stop();
System.out.println(person.toString());
}
}
class MyThread extends Thread {
Person person;
public MyThread(Person person) {
this.person = person;
}
@Override
public void run() {
person.setNameAndAge("Lin", 20);
}
}
class Person{
private String name;
private int age;
public String getName() {
return name;
}
public int getAge() {
return age;
}
synchronized public void setNameAndAge(String name,int age){
this.name = name;
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
this.age = age;
}
@Override
public String toString() {
return getName() + "," + getAge();
}
}
打印输出:
Lin,10
按理说,setNameAndAge() 是一个同步方法,对象 person 总能保证对 name 和 age 同时赋值。因此上例中我们期待的输出应该是 “Lin,20”,由于调用的是 stop(),它会马上释放锁(即使正在同步块中),使得数据不一致。
所以要停止或退出线程,请忘记 stop()。
interrupt() 能退出线程吗?
public class InterruptTest {
public static void main(String[] args) throws Exception {
MyThread thread = new MyThread();
thread.start();
Thread.sleep(100);
thread.interrupt();
}
}
class MyThread extends Thread {
@Override
public void run() {
BufferedWriter writer = null;
try {
writer = new BufferedWriter(new FileWriter("C:/log.txt"));
for (int i = 0; i < 5000000; i++) {
String str = "";
if (i == 1) {
str = i + "";
} else {
str = "\n" + i;
}
writer.write(str);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
writer.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
可以看到输出的文件总行数为 500000,说明 interrupt() 并没有马上终止循环。
interrupt() 仅仅是在当前线程打了一个停止标记,并没有真的停止线程。
异常法退出线程
上代码:
public class Test {
public static void main(String[] args) {
MyThread thread = new MyThread();
thread.start();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
thread.interrupt();
}
}
class MyThread extends Thread {
@Override
public void run(){
boolean flag = true;
while (flag) {
if (this.isInterrupted()) {
System.out.println("线程即将停止");
try {
throw new InterruptedException();
} catch (InterruptedException e) {
flag = false;
}
}
}
System.out.println("已经跳出循环,线程停止");
}
}
打印输出:
线程即将停止 已经跳出循环,线程停止
run 方法执行完,线程自然就结束了。
使用 return 退出线程
public class Test2 {
public static void main(String[] args) {
MyThread2 thread = new MyThread2();
thread.start();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
thread.interrupt();
}
}
class MyThread2 extends Thread {
@Override
public void run() {
while (true) {
if (this.isInterrupted()) {
System.out.println("线程停止");
return;
}
}
}
}
打印输出:
线程停止
Java - 安全的退出线程的更多相关文章
- Java线程监听,意外退出线程后自动重启
Java线程监听,意外退出线程后自动重启 某日,天朗气清,回公司,未到9点,刷微博,顿觉问题泛滥,惊恐万分! 前一天写了一个微博爬行程序,主要工作原理就是每隔2分钟爬行一次微博,获取某N个关注朋友微博 ...
- Java并发编程:线程池的使用
Java并发编程:线程池的使用 在前面的文章中,我们使用线程的时候就去创建一个线程,这样实现起来非常简便,但是就会有一个问题: 如果并发的线程数量很多,并且每个线程都是执行一个时间很短的任务就结束了, ...
- Java多线程系列--“JUC线程池”03之 线程池原理(二)
概要 在前面一章"Java多线程系列--“JUC线程池”02之 线程池原理(一)"中介绍了线程池的数据结构,本章会通过分析线程池的源码,对线程池进行说明.内容包括:线程池示例参考代 ...
- Java并发编程:线程间协作的两种方式:wait、notify、notifyAll和Condition
Java并发编程:线程间协作的两种方式:wait.notify.notifyAll和Condition 在前面我们将了很多关于同步的问题,然而在现实中,需要线程之间的协作.比如说最经典的生产者-消费者 ...
- Java多线程-新特性-线程池
Sun在Java5中,对Java线程的类库做了大量的扩展,其中线程池就是Java5的新特征之一,除了线程池之外,还有很多多线程相关的内容,为多线程的编程带来了极大便利.为了编写高效稳定可靠的多线程程序 ...
- Java笔记(二十)……线程间通信
概述 当需要多线程配合完成一项任务时,往往需要用到线程间通信,以确保任务的稳步快速运行 相关语句 wait():挂起线程,释放锁,相当于自动放弃了执行权限 notify():唤醒wait等待队列里的第 ...
- Java中的守护线程 & 非守护线程(简介)
Java中的守护线程 & 非守护线程 守护线程 (Daemon Thread) 非守护线程,又称用户线程(User Thread) 用个比较通俗的比如,任何一个守护线程都是整个JVM中所有非守 ...
- Java并发编程:线程池的使用(转)
Java并发编程:线程池的使用 在前面的文章中,我们使用线程的时候就去创建一个线程,这样实现起来非常简便,但是就会有一个问题: 如果并发的线程数量很多,并且每个线程都是执行一个时间很短的任务就结束了, ...
- 初步探究java中程序退出、GC垃圾回收时,socket tcp连接的行为
初步探究java中程序退出.GC垃圾回收时,socket tcp连接的行为 今天在项目开发中需要用到socket tcp连接相关(作为tcp客户端),在思考中发觉需要理清socket主动.被动关闭时发 ...
随机推荐
- IIS下Asp.Net应用程序多进程设置及Session共享
背景: 目前项目中在单个进程的应用程序经常会遇到w3c.exe崩溃的情况,于是就设想是否可以通过IIS多进程的方案来避免出现该问题. 于是搜了下“怎么实现多进程的方案”,找到了这篇文章:http:// ...
- Thinkstation center M8600t装RHEL7不能联网,网卡驱动没装问题
Thinkstation center M8600t装RHEL7时不能联网,配置ip也不可以,后来发现网卡驱动没有安装.可以通过装网卡驱动的方式解决问题,解决方法如下: root登录 lspci | ...
- C++笔记(二)------ 头文件
类似#include<string>与#include<string.h>等头文件的区别 标准的C++头文件没有.h扩展名,带有.h的头文件一般都是C语言的.例如#includ ...
- JS调用OC方法并传值,OC调用JS方法并传值////////////////////////zz
iOS开发-基于原生JS与OC方法互相调用并传值(附HTML代码) 最近项目里面有有个商品活动界面,要与web端传值,将用户在网页点击的商品id 传给客户端,也就是js交互,其实再说明白一点 ...
- Android 短信广播接收相关问题
本人是Android新手,最近做了一个关于监听手机短信功能的应用,我在网上看资料了解到广播分为有序广播和无序广播,有序广播:无序广播又称普通广播,其中的利弊我也一时没搞清楚,我用的是有序广播实现的,具 ...
- IBM WebSphere MQ的oracle的jdbc
一.IBM WebSphere MQ7.0的jdbc支持数据库有: DB2 Informix Informix_With_Date_Format Microsoft_SQL_Server Oracle ...
- wex5 实战 用户点评与提交设计技巧
最近遇到很多同学做毕业设计,其中有一项是用户点评与提交.功能并不复杂,同学们又不会,做为一个完整的功能,如果用wex5来设计开发,事半功倍.今天就以景区实战来向大家展示wex5的高效与强大.半天可以设 ...
- Solution for Error FRM-92095: Oracle Jnitiator version too low
Solution for Error FRM-92095: Oracle Jnitiator version too low By Pan.Tian on 六月 04, 2013 Symtom: Af ...
- Codeforces 747C:Servers(模拟)
http://codeforces.com/problemset/problem/747/C 题意:有n台机器,q个操作.每次操作从ti时间开始,需要ki台机器,花费di的时间.每次选择机器从小到大开 ...
- HDU 4292:Food(最大流)
http://acm.hdu.edu.cn/showproblem.php?pid=4292 题意:和奶牛一题差不多,只不过每种食物可以有多种. 思路:因为食物多种,所以源点和汇点的容量要改下.还有D ...