java学习总结——线程中断

      首先解释一下为什么需要有线程中断。当我们操作一些软件时,会出现下面的情景。进入某个页面之后,会出现一个进度条,显示loading(意味着正在加载资源)。同时,我们也会发现在进度条的附近,会有一个"取消"按钮。当我们发现资源加载耗时很长,我们不想等下去的时候,单击“取消”按钮。这个时候就会退出资源加载的页面,返回上一个页面。这里的“取消”按钮操作就属于一种中断操作,它终止了资源加载这个操作的运行。

       同理,在java中,我们也时常需要停止一些正在运行的线程。这个时候就需要使用到java线程的中断机制。java中的线程中断并不意味着线程停止运行,线程的中断只是线程的一个属性值。当你使用线程的中断机制中断线程后,这个值就会被修改。此时,调用相应的方法就可以检测到用户的中断请求。在检测到这个中断请求后,就会执行相应的中断逻辑代码;当然,在这中断逻辑代码中,是可以选择终止线程,也可以选择继续运行线程的,具体的逻辑需要使用者自己去定义。

       在java中,只需要调用线程的interrupt()方法就可以发出线程中断请求。此时用户使用相应的检测方法就可以检测到这个请求。java中提供了两种线程中断检测方式:1、isInterrupt()方法;2、InterruptedException异常

一、isInterrupt()方法检测线程中断

public class ThreadTest09 {

	public static void main(String[] args) throws Exception {
		    ThreadThread threadThread = new ThreadThread();
		    threadThread.start();
		    Thread.sleep(1000);
		    threadThread.interrupt();
	}
}

public class ThreadThread extends Thread{
	
	 
	public ThreadThread(){}
	
	@Override
	public void run() {
		while(true){		  
			 if(Thread.currentThread().isInterrupted()){
			    	System.out.println("线程已中断,执行中断线程逻辑,停止线程运行!!");
			    	return;
			 }
		}
	}
}
在上面的代码中,创建并启动了一个线程,线程执行一个死循环。在1秒钟后,调用interrupted方法发出中断请求;循环方法体中检测到线程中断请求时,则打印出信息,然后停止run方法发的执行。这就是一个简单的线程中断并停止线程运行的示例。当然,这里我们用return关键字直接结束了run方法的运行,如果我们在打印出了信息之后,不调用return 关键字,那么线程将会继续执行;也就是上面所说的线程中断了,并不代表线程会停止运行。下面的示例就演示了线程中断了,但还在继续执行:
public class ThreadTest09 {

	public static void main(String[] args) throws Exception {
		    ThreadThread threadThread = new ThreadThread();
		    threadThread.start();
		    Thread.sleep(1000);
		    threadThread.interrupt();
	}
}

public class ThreadThread extends Thread{
	
	 
	public ThreadThread(){
		
	}
	
	@Override
	public void run() {
		while(true){
			  
			 if(Thread.currentThread().isInterrupted()){
			    	System.out.println("线程已中断,执行中断线程逻辑,停止线程运行!!");
			    	break; //这里不使用return 关键字,run方法会继续执行
			 }
		}
		System.out.println("线程继续运行!!");
	}
}
接下来在对比一下Thread.interrupted()(也是用来检测线程是否中断的方法)方法和isInterrupted()方法,示例代码:

public class ThreadTest09 {

	public static void main(String[] args) throws Exception {
		    ThreadThread threadThread = new ThreadThread();
		    threadThread.start();
		    Thread.sleep(1000);
		    threadThread.interrupt();
	}
}

//使用isInterrupted方法
public class ThreadThread extends Thread{
	
	 
	public ThreadThread(){
		
	}
	
	@Override
	public void run() {
		while(true){
			 if(Thread.currentThread().isInterrupted()){
			    	System.out.println("线程已中断,执行中断线程逻辑,线程继续运行!!");
			 }
			 
			 if(Thread.currentThread().isInterrupted()){
			    	System.out.println("再次检测,线程已中断,执行中断线程逻辑,停止线程运行!!");
			    	return;
			 }
		}
	}
}
//输出结果:
//线程已中断,执行中断线程逻辑,线程继续运行!!
//再次检测,线程已中断,执行中断线程逻辑,停止线程运行!!

//使用Thread.Interrupted()方法
public class ThreadThread extends Thread{
	
	 
	public ThreadThread(){
		
	}
	
	@Override
	public void run() {
		while(true){
			 if(Thread.interrupted()){  //使用Thread.Interrupted()方法
			    	System.out.println("线程已中断,执行中断线程逻辑,线程继续运行!!");
			 }
			 
			 if(Thread.currentThread().isInterrupted()){
			    	System.out.println("再次检测,线程已中断,执行中断线程逻辑,停止线程运行!!");
			    	return;
			 }
		}
	}
}
//输出结果:
//线程已中断,执行中断线程逻辑,线程继续运行!!

对比上面的代码可以返现,都是检测线程是否中断的方法,但是执行结果却不一样。先看一下Thread.intterrupted()方法的源代码,再分析原因。源代码:

 /**
     * Tests whether the current thread has been interrupted.  The
     * <i>interrupted status</i> of the thread is cleared by this method.  In
     * other words, if this method were to be called twice in succession, the
     * second call would return false (unless the current thread were
     * interrupted again, after the first call had cleared its interrupted
     * status and before the second call had examined it).
     *
     * <p>A thread interruption ignored because a thread was not alive
     * at the time of the interrupt will be reflected by this method
     * returning false.
     *
     * @return  <code>true</code> if the current thread has been interrupted;
     *          <code>false</code> otherwise.
     * @see #isInterrupted()
     * @revised 6.0
     */
    public static boolean interrupted() {
        return currentThread().isInterrupted(true);
    }
从源代码的注释中已经对刚才的情况进行了说明,大意是:检测一个线程是否是已经中断,如果线程的状态已经中断,则这个方法会返回true,同时清除线程的中断状态。也就是说调用这个静态的interrupted方法,除了返回线程是否中断之外,它还会清除线程的中断状态。再对比一下isInterrupted方法的 源代码,就更清晰了。源代码:

/**
     * Tests whether this thread has been interrupted.  The <i>interrupted
     * status</i> of the thread is unaffected by this method.
     *
     * <p>A thread interruption ignored because a thread was not alive
     * at the time of the interrupt will be reflected by this method
     * returning false.
     *
     * @return  <code>true</code> if this thread has been interrupted;
     *          <code>false</code> otherwise.
     * @see     #interrupted()
     * @revised 6.0
     */
    public boolean isInterrupted() {
        return isInterrupted(false);
    }
源代码的注释部分有说明,大意是:检测一个线程是否已经中断,同时这个方法将不会影响线程的中断状态。换句话说就是isInterrupted方法不会修改线程的中断状态。

      最后,线程如果调用isActive方法返回false时,就没有所谓的中断一说了。此时调用isInterrupted()方法返回的是false,并不意味着线程没有被中断。

二、InterruptedException异常

      使用isInterrupted()方法存在一个不便利的地方,就是线程跨多个方法时,需要我们一层一层的去处理所有的中断逻辑,特别是递归调用的时候,这个缺点就更明显了。所以,在线程跨多个方法的时候,需要使用InterruptedException异常来响应中断请求。InterruptedException异常的使用是对isInterrupted()方法的一个补充。java文档对这个异常的解释如下:

/**
 * Thrown when a thread is waiting, sleeping, or otherwise occupied,
 * and the thread is interrupted, either before or during the activity.
 * Occasionally a method may wish to test whether the current
 * thread has been interrupted, and if so, to immediately throw
 * this exception.  
 */
这段话解释了 InterruptedException会被抛出的情况:

       1、当线程处于waiting,sleeping或者其他占用状态时,将抛出这个异常

       2、当线程在活动过程中或者激活之前,此时如果线程被中断,将抛出这个异常

       3、当调用线程检测中断的方法检测到线程已经被中断的时候,用户可以手动抛出这个异常,作为对中断的响应。
上面对这个异常的解释已经很清晰,这里通过代码演示一下。代码如下:

public class ThreadTest10 {

	public static void main(String[] args) throws Exception {
		    ThreadThread threadThread = new ThreadThread();
		    threadThread.start();
		    Thread.sleep(8000);//线程总共休眠6秒,8秒后中断线程,保证检测方法能够执行。
		    threadThread.interrupt();
	}
}

//输出结果
//Fri Jan 12 12:12:07 CST 2018
//线程已中断,执行中断逻辑,停止运行线程!!
//Fri Jan 12 12:12:15 CST 2018   (相差8秒)

public class ThreadThread extends Thread{
	
	 
	public ThreadThread(){}
 	
	@Override
	public void run() {
		try {
			getLock();
		} catch (InterruptedException e) {
			 //捕获到中断异常,进行相应逻辑处理
			System.out.println("线程已中断,执行中断逻辑,停止运行线程!!");
			return;
		}
	}

	private void getLock() throws InterruptedException {
		 TimeUnit.SECONDS.sleep(3);
		 getSubMethod();
	}

	private void getSubMethod() throws InterruptedException {
		TimeUnit.SECONDS.sleep(3);
		while(true){
			if(Thread.interrupted()){ //检测线程是否中断
				throw new InterruptedException();
			}
		}
	}
}

如果将上面的main(主线程)的休眠时间改为2秒,此时启动的线程还处于getLock方法中;但是我们仍然可以接受线程终止的信息,而且是立即输出。这是因为sleep方法会对interrupted方法做出相应,抛出InterruptedException异常,也就是上面说的第一种情况。代码如下:

public class ThreadTest10 {

	public static void main(String[] args) throws Exception {
		    ThreadThread threadThread = new ThreadThread();
		    threadThread.start();
		    Thread.sleep(2000);//线程总共休眠6秒,8秒后中断线程,保证检测方法能够执行。
		    threadThread.interrupt();
	}
}

//输出结果
//Fri Jan 12 12:16:52 CST 2018
//线程已中断,执行中断逻辑,停止运行线程!!
//Fri Jan 12 12:16:54 CST 2018  (相差2秒)






  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值