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主动.被动关闭时发 ...
随机推荐
- C# 获取汉字拼音首字母
最近悟出来一个道理,在这儿分享给大家:学历代表你的过去,能力代表你的现在,学习代表你的将来. 十年河东十年河西,莫欺少年穷 学无止境,精益求精 本节探讨C#获取汉字拼音首字母的方法: 代码类东西, ...
- Ubuntu16.04配置phpmyadmin
原文 如何安装phpmyadmin-Mysql 数据库管理 使用界面管理器:系统->系统管理->新立得软件包管理器->搜索 phpmyadmin->右键标记安装.或直接使用一条 ...
- Google Code Jam Round 1A 2015 解题报告
题目链接:https://code.google.com/codejam/contest/4224486/ Problem A. Mushroom Monster 这题题意就是,有N个时间点,每个时间 ...
- css2 [lang|=en] 误区
[lang|=en] w3c说明:css2选择器,选择以en开头的的lang属性. w3c的这个解释是有误区的,en开头,但是en后面必须要有-,也就是说是选择的是en-开头
- table 边框
<table width="100%" border="0" cellpadding="2" cellspacing="0& ...
- Angular初学
简介: angularjs是基本js开发的一个前端类库,主要致力于减轻开发人员在开发Ajax应用过程中的痛苦,适合来做单应用. 客户端模板: Angualr中,模板和数据都会被发送到浏览器中,然后在客 ...
- http 协议集合,超级简单
using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Web; ...
- DNS-2
ipconfig 用法: ipconfig [/allcompartments] [/? | /all | /renew [adapter] | /release [adapter] | /renew ...
- MySQl查询区分大小写的解决办法
通过查询资料发现需要设置collate(校对) . collate规则: *_bin: 表示的是binary case sensitive collation,也就是说是区分大小写的 *_cs: ca ...
- RK 61 键盘 Ubuntu 下键位映射修改方案
在用户 Home 目录下面创建 .Xmodmap 文件,然后输入以下的内容: remove Lock = Caps_Lock remove Control = Control_L remove Con ...