一、线程中断
Java 中有以3 种方法可以中断正在运行的线程:
- 使用(volatile修饰)退出标志,使线程正常退出,也就是当 run() 方法完成后线程中止;
- 也可使用 Atomic 变量作为退出标志,同样可以实现线程的中断;
- 使用 interrupt() 方法中断线程(只是中断线程执行,终止线程的睡眠(唤醒),并未终止线程)
1.volatile修饰的标记位
定义一个boolean型的标志位,在线程的run方法中根据这个标志位是true还是false来判断是否退出
/**
* 使用标志位终止线程
* */
public class ThreadStop {
public static void main(String[] args) {
ThreadStopRunnable runnable = new ThreadStopRunnable();
Thread t = new Thread(runnable);
t.setName("t");
t.start();
try {
Thread.sleep(1000 * 5);
} catch (InterruptedException e) {
e.printStackTrace();
}
//执行5秒之后终止线程,终止t线程的执行,将标记修改为false即可
runnable.runFlag = false;
System.out.println(Thread.currentThread().getName() + "\t" + "main is over");
}
}
class ThreadStopRunnable implements Runnable {
//volatile修饰符用来保证其它线程读取的总是该变量的最新的值
public volatile boolean runFlag = true;
@Override
public void run() {
for (int i = 1; i <= 100; i++) {
if (runFlag){
System.out.println(Thread.currentThread().getName() + "---->" + i);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}else {
//执行终止线程之前的代码,如保存数据等
return;
}
}
}
}
2.AtomicBoolean标记位
可以使用AtomicBoolean作为标记位,省去volatile关键字修饰。
/**
* 使用标志位终止线程
* */
public class ThreadStop {
public static void main(String[] args) {
ThreadStopRunnable runnable = new ThreadStopRunnable();
Thread t = new Thread(runnable);
t.setName("t");
t.start();
try {
Thread.sleep(1000 * 5);
} catch (InterruptedException e) {
e.printStackTrace();
}
//执行5秒之后终止线程,终止t线程的执行,将标记修改为false即可
runnable.runFlag.set(false);
System.out.println(Thread.currentThread().getName() + "\t" + "main is over");
}
}
class ThreadStopRunnable implements Runnable {
//volatile修饰符用来保证其它线程读取的总是该变量的最新的值
public AtomicBoolean runFlag = new AtomicBoolean(true);
@Override
public void run() {
for (int i = 1; i <= 100; i++) {
if (runFlag.get()){
System.out.println(Thread.currentThread().getName() + "---->" + i);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}else {
//执行终止线程之前的代码,如保存数据等
return;
}
}
}
}
3.interrupt() 中断
使用interrupt()方法,仅仅是给线程打上中断标记位,并没有实际中断线程(把中断的权利交给线程本身,更安全)
interrupt() 正在睡眠的线程会抛出InterruptedException异常。
/**
* 使用标志位终止线程
* */
public class ThreadStop {
public static void main(String[] args) {
ThreadStopRunnable runnable = new ThreadStopRunnable();
Thread t = new Thread(runnable);
t.setName("t");
t.start();
try {
Thread.sleep(1000 * 5);
} catch (InterruptedException e) {
e.printStackTrace();
}
t.interrupt();
System.out.println(Thread.currentThread().getName() + "\t" + "main is over");
}
}
class ThreadStopRunnable implements Runnable {
@Override
public void run() {
for (int i = 1; i <= 100; i++) {
if (!Thread.currentThread().isInterrupted()){
System.out.println(Thread.currentThread().getName() + "---->" + i);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
e.printStackTrace();
}
}else {
//执行终止线程之前的代码,如保存数据等
return;
}
}
}
}
t---->1
t---->2
t---->3
t---->4
t---->5
main main is over
java.lang.InterruptedException: sleep interrupted
at java.lang.Thread.sleep(Native Method)
at org.mark.spring.test.ThreadStopRunnable.run(ThreadStop.java:35)
at java.lang.Thread.run(Thread.java:748)
二、线程终止
通过查看 JDK 的 API,我们会看到 java.lang.Thread 类型提供了一系列的方法如 start()、stop()、resume()、suspend()、destory()等方法来管理线程。但是除了 start() 之外,其它方法都被声名为已过时(deprecated)
虽然 stop() 方法确实可以停止一个正在运行的线程,但是这个方法是不安全的,而且该方法已被弃用,最好不要使用它。
JDK 文档中还引入用一篇文章来解释了弃用这些方法的原因:《Why are Thread.stop, Thread.suspend and Thread.resume Deprecated?》
为何弃用stop:
1、调用 stop() 方法会立刻停止 run() 方法中剩余的全部工作,包括在 catch 或 finally 语句中的,并抛出ThreadDeath异常(通常情况下此异常不需要显示的捕获),因此可能会导致一些清理性的工作的得不到完成,如文件,数据库等的关闭
2、调用 stop() 方法会立即释放该线程所持有的所有的锁,导致数据得不到同步,出现数据不一致的问题