线程中断

1 为什么废弃Thread的stop函数?

对于有多线程开发经验的开发者,应该大多数在开发过程中都遇到过这样的需求,就是在某种情况下,希望立即停止一个线程。

比如:做Android APP开发,当打开一个界面时,需要开启线程请求网络获取界面的数据,但有时候由于网络特别慢,用户没有耐心等待数据获取完成就将界面关闭,此时就应该立即停止线程任务,不然一般会内存泄露,造成系统资源浪费,如果用户不断地打开又关闭界面,内存泄露会累积,最终导致内存溢出,APP闪退。

可能有不少开发者用过Thread的stop去停止线程,当然此函数确实能停止线程,不过Java官方早已将它废弃,不推荐使用,这是为什么?

  1. stop是通过立即抛出ThreadDeath异常,来达到停止线程的目的,此异常抛出有可能发生在任何一时间点,包括在catch、finally等语句块中,但是此异常并不会引起程序退出(笔者只测试了Java8)。
  2. 由于有异常抛出,导致线程会释放全部所持有的锁,极可能引起线程安全问题。

2 用Thread的interrupt结束线程

其实调用Thread对象的interrupt函数并不是立即中断线程,只是将线程中断状态标志设置为true,当线程运行中有调用其阻塞的函数(Thread.sleep,Object.wait,Thread.join等)时,阻塞函数调用之后,会不断地轮询检测中断状态标志是否为true,如果为true,则停止阻塞并抛出InterruptedException异常,同时还会重置中断状态标志;如果为false,则继续阻塞,直到阻塞正常结束。

2.1 结束未使用阻塞函数的线程

public class InterruptThread {
	static class NoBlockThread {
		Thread t = new Thread() {
			public void run() {
				while(true) {
					if(!this.isInterrupted()) {
						System.out.println("执行"+this.isInterrupted());
					} else {
						System.out.println("中断");
						break;
					}
				}
			};
		};
	}

	public static void main(String[] args) throws InterruptedException {
		NoBlockThread blockThread = new NoBlockThread();
		blockThread.t.start();
		Thread.sleep(4000);
		System.out.println("睡眠结束");
		blockThread.t.interrupt();
	}
}

2.2 结束使用阻塞函数的线程

public class InterruptThread {
	static class BlockThread {
		Thread t = new Thread() {
			public void run() {
				while(!Thread.currentThread().isInterrupted()) {
					try {
						Thread.sleep(1000);
						System.out.println("睡眠结束"+(Thread.currentThread() == this));
					} catch (InterruptedException e) {
						System.out.println("中断异常");
						// 恢复中断状态
						this.interrupt();// 再次中断线程
					}
				}
			};
		};
	}
	public static void main(String[] args) throws InterruptedException {
		BlockThread blockThread = new BlockThread();
		blockThread.t.start();
		Thread.sleep(4000);
		System.out.println("睡眠结束");
		blockThread.t.interrupt();
	}
}

查看2.2示例发现,关于阻塞(wait(),sleep(),join())等方法为什么还需要在catch中再次中断线程呢?
线程中断_第1张图片
可以看出 sleep() 方法被中断后会清除中断标记,所以循环会继续运行,所以需要在catch再次重置中断标志结束线程。

扩展:中断概述与中断方法解析

Java的中断是一种协作机制,也就是说通过中断并不能直接中断另外一个线程,而需要被中断的线程自己处理中断。

在Java的中断模型中,每个线程都有一个boolean标识,代表着是否有中断请求(该请求可以来自所有线程,包括被中断的线程本身)。例如,当线程t1想中断线程t2,只需要在线程t1中将线程t2对象的中断标识置为true,然后线程2可以选择在合适的时候处理该中断请求,甚至可以不理会该请求,就像这个线程没有被中断一样。

方法 描述
public static boolean interrupted 测试当前线程是否已经中断。线程的中断状态 由该方法清除。换句话说,如果连续两次调用该方法,则第二次调用将返回 false(在第一次调用已清除了其中断状态之后,且第二次调用检验完中断状态前,当前线程再次中断的情况除外)。此方法内部调用的死私有的Thread.currentThread().isInterrupted(true); 带true参数的isInterrupted方法意思是返回当前线程的中断状态,然后reset当前线程的中断状
public boolean isInterrupted() 测试线程是否已经中断。线程的中断状态不受该方法的影响。内部调用的私有的参数为false的isInterrupted(false)方法
public void interrupt() 中断线程,将中断状态设为true

你可能感兴趣的:(java)