摘要:
本文介绍了java中线程终止背景以及3种线程终止方式。分别是:volatile 标志位、interrupt()方法终止、重写Thread.interrupt()方法终止阻塞的socket。
一、背景
注:无阻塞、无循环的线程是不需要终止的,这类线程必然会在有限时间内执行完毕。
1.1 为什么要终止线程?
1. 线程中存在无限循环,需要手动终止线程。
2. 线程中存在长时间的阻塞。例如:线程阻塞在锁的获取,阻塞在wait()方法上,或者阻塞在文件读写上,或者阻塞在Socket上,均会导致线程卡死。
1.2 线程应该从何处终止?
1. 循环体条件中
2. 等待时间的阻塞的地方中断,例如:sleep,等待锁
3. 等待IO的阻塞地方中断
1.3 如何终止线程?
从1.1可知,想要终止线程,只需要终止循环条件或打破阻塞即可。例如:修改while循环条件,终止时间阻塞,终止IO阻塞。
二、线程终止实践
2.1 废弃的方法
Thread.stop, Thread.suspend, Thread.resume
由于上述三个方法在执行时可能存在安全问题,已经被废弃。
2.2 volatile 循环条件标志位终止线程
适用于线程中存在循环业务代码情况。
代码示例:
线程中加入volatile boolean类型标志位,用于循环体中循环条件判断,决定线程是否终止。
static class MyThread extends Thread {
private volatile boolean on = true;
public void stopThread() {
on = false;
}
@Override
public void run() {
System.out.println("线程启动了");
while(on) {
}
System.out.println("线程终止了");
}
}
public static void main(String[] args) throws Exception{
MyThread thread = new MyThread();
thread.start();
Thread.sleep(3000);
thread.stopThread();
}
2.3 interrupte()方法终止线程
适用场景1:线程内存在循环
适用场景2:线程内存在阻塞方法,例如sleep(),wait(),join()等方法,循环可
场景1代码示例:
通过线程中断标志位决定线程是否终止。
static class MyThread extends Thread {
@Override
public void run() {
System.out.println("线程启动了");
while(!Thread.currentThread().isInterrupted()) { //通过线程中断标志位决定线程是否终止
}
System.out.println("线程终止了");
}
}
public static void main(String[] args) throws Exception{
MyThread thread = new MyThread();
thread.start();
Thread.sleep(3000);
thread.interrupt();
}
场景2代码示例:
通过捕获线程中阻塞方法中抛出的InterruptedException异常,主动终止线程。前提是阻塞方法能感应到中断标志位的改变,且能主动抛出异常。
static class MyThread extends Thread {
@Override
public void run() {
System.out.println("线程启动了");
while(true) {
try {
Thread.sleep(500000); //该方法在线程中断标志位是true时,会中断,并且抛出InterruptedException异常
} catch (InterruptedException e) {
break;//捕获后,终止线程
}
}
System.out.println("线程终止了");
}
}
public static void main(String[] args) throws Exception{
MyThread thread = new MyThread();
thread.start();
Thread.sleep(3000);
thread.interrupt();
}
2.4 重写线程interrupte()方法终止阻塞在socket上的线程
适用场景:线程中不包含任何循环,不包含任何时间阻塞方法。但是存在Socket之类的io阻塞。
代码示例:
重写线程的interrupt()方法:获取IO客户端,主动关闭IO客户端。IO客户端被中断后会抛出异常,异常处理中终止线程。
static class CancelleableSocketThread extends Thread {
private final ServerSocket server;
public CancelleableSocketThread(int port) throws IOException {
server = new ServerSocket(port);
}
@Override
public void interrupt() {
try {
server.close();
System.out.println("server close");
} catch (IOException ignored) {
} finally {
super.interrupt();//调用Thread.interrupt
System.out.println("server close interrupt");
}
}
@Override
public void run() {
while (true) {
try {
Socket client = server.accept();
} catch (Exception se) {
System.out.println("server阻塞停止,退出");
break;
}
}
}
}
public static void main(String[] args) throws Exception {
CancelleableSocketThread cst = new CancelleableSocketThread(8080);
cst.start();
System.out.println("测试开始");
Thread.sleep(3000);
cst.interrupt();//调用重写的thread.interrupt方法,终止socket让socket抛出异常终止线程,同时也执行了Thread.interrupt
}