如何优雅的中断线程?

摘要:

本文介绍了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
    }
	

你可能感兴趣的:(java,java,开发语言)