package com.pc.screenproject;
public class Test {
private static boolean isStop = false;
/**
* 自定义退出标识isStop
* Before : isStop=false
* After : isStop=true
*/
private static void test0() {
isStop = false;
Thread t = new Thread(new Runnable() {
@Override
public void run() {
System.out.println("测试自定义退出标识isStop用法");
System.out.println("Before : isStop=" + isStop);
while (!isStop) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("After : isStop=" + isStop);
}
});
t.start();
try {
Thread.sleep(500);
isStop = true;
t.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
/**
* 非阻塞状态下
* Thread.currentThread().isInterrupted() : 获取中断标志位,调用不会清空中断标志位;
* 运行结果
* Before : false
* After : true
*/
private static void test1() {
Thread t = new Thread(new Runnable() {
@Override
public void run() {
System.out.println("测试非阻塞状态下isInterrupted用法");
System.out.println("Before : " + Thread.currentThread().isInterrupted());
while (!Thread.currentThread().isInterrupted()) {
;
}
System.out.println("After : " + Thread.currentThread().isInterrupted());
}
});
t.start();
try {
Thread.sleep(500);
t.interrupt();
t.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
/**
* 非阻塞状态下
* Thread.interrupted() : 获取中断标志位,调用一次就立即清空中断标志位;
* 运行结果
* Before : false
* After : false
*/
private static void test2() {
Thread t = new Thread(new Runnable() {
@Override
public void run() {
System.out.println("测试非阻塞状态下interrupted用法");
System.out.println("Before : " + Thread.currentThread().isInterrupted());
while (!Thread.interrupted()) {
;
}
System.out.println("After : " + Thread.currentThread().isInterrupted());
}
});
t.start();
try {
Thread.sleep(500);
t.interrupt();
t.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
/**
* 阻塞状态下
* sleep() : 抛出InterruptedException后中断标志位被清除,所以循环无法退出。标准做法是
* 1. 再次调用interrupt恢复中断;
* 2. 直接break退出;
* 运行结果
* Before : false
* After : false
*/
private static void test3() {
Thread t = new Thread(new Runnable() {
@Override
public void run() {
System.out.println("测试sleep阻塞状态下中断用法");
System.out.println("Before : " + Thread.currentThread().isInterrupted());
while (!Thread.interrupted()) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
// break;
}
}
System.out.println("After : " + Thread.currentThread().isInterrupted());
}
});
t.start();
try {
Thread.sleep(500);
t.interrupt();
t.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
test0();
test1();
test2();
test3();
}
}
线程安全退出总结:
- 自定义停止标识;如
test0()
- 通过
interrupt()
函数,这里分为两种情况:- 非阻塞情况,则通过
Thread.interrupted()
或者Thread.currentThread().isInterrupted()
- 阻塞情况,一般会抛出
InterruptedException
异常,则需要在try...catch
再次执行Thread.currentThread().interrupt()
或者break
,否则循环无法退出。
- 非阻塞情况,则通过
-
InterruptedException
异常会清除中断标识位,此时通过Thread.interrupted()
或者Thread.currentThread().isInterrupted()
查看则都为false
; - 捕获到
InterruptedException
异常之后,需要通过Thread.currentThread().interrupt()
再次设置一下中断标识位,才能保证中断标识位正常; -
Thread.interrupted()
和Thread.currentThread().isInterrupted()
的区别在于,Thread.currentThread().isInterrupted()
不改变中断标识位,而Thread.interrupted()
调用之后会重置中断标识位。