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主动.被动关闭时发 ...
随机推荐
- 关于Java中基本类型的长度相关基础知识
1. 用HeapByteBuffer放int占几个byte? 占4个.而且不论你是放1还是-1还是0xffff. 因为int的长度是4个byte,HeapByteBuffer的存储又是byte数组. ...
- Hive:Spark中如何实现将rdd结果插入到hive1.3.0表中
DataFrame写入hive API: registerTempTable函数是创建spark临时表 insertInto函数是向表中写入数据,可以看出此函数不能指定数据库和分区等信息,不可以直接进 ...
- 浅谈HTTPS和SSL/TLS协议的背景和基础
相关背景知识要说清楚HTTPS协议的实现原理,至少要需要如下几个背景知识.大致了解几个基础术语(HTTPS.SSL.TLS)的含义大致了解HTTP和TCP的关系(尤其是"短连接"和 ...
- ios开发错误之: Undefined symbols for architecture x86_64
错误如下: Undefined symbols for architecture x86_64: "_OBJC_CLASS_$_RoutingHTTPServer", refere ...
- vsftpd.conf
引用:http://www.linuxidc.com/Linux/2012-08/67389.htm 研究嵌入式开发,开始使用的是Linux平台,用的是Ubuntu环境,但是发现Ubuntu的图形界面 ...
- 该字符串未被识别为有效的 DateTime
开发语言C#,System.Data.SQLite.dll驱动. SQLserver数据库转换为SQLite数据库时,日期类型默认转为DATETIME. 执行查询SQL语句,数据为空(查询不到数据时) ...
- [原] MSSQL MDF文件太大问题
USE 你的库名; GO -- 数据库空间使用情况 EXEC sp_spaceused; -- 查下文件空间使用情况 SELECT file_id, name, [文件大小(MB)] = size / ...
- iphone 群发短信 闪退 彻底解决
用iphone5群发短信,经常闪退,一般人多的时候,最容易出现 试了很多办法,ifile改sms.db等权限等 没有根本解决 一次操作中,发现群发时,每个号码都会显示菊花,貌似在检测什么 突然意识到, ...
- apiCloud图片选择、处理、上传模块
将 apiCloud 开发app的图片上传流程,完整封装成了一个页面,页面处理一些必备的处理库外和css外 ,还需要依赖jquery 库,不过可以不管,页面默认使用cnd引用. 页面使用接口如下:pa ...
- 161228、Java IO流读写文件的几个注意点
平时写IO相关代码机会挺少的,但却都知道使用BufferedXXXX来读写效率高,没想到里面还有这么多陷阱,这两天突然被其中一个陷阱折腾一下:读一个文件,然后写到另外一个文件,前后两个文件居然不一样? ...