多线程基础篇(2)——理解中断

简介: 推荐书籍《Java并发编程的艺术》《Java编程思想》《Java核心技术》

1.何谓线程中断

    线程中断,可以理解为一个现成的标识属性,它表示一个运行中的线程是否被其他线程进行了中断操作,中断可以用来进行强制终结线程(使线程进入终止状态),即在执行run方法过程中直接退出(或者说跳过某段代码)。

    线程中断的方法:

    1)stop()方法:不在使用此方法,其中断线程是立即中断的,即使是在同步代码块中对数据进行操作时也会立即终止,详细不在赘述,只需知道该方法不在使用即可。

    2)interrupt()方法:其他线程调用此线程的interrupt()方法对其进行中断操作时,interrupt()方法将线程的中断状态设置为true,如果该线程正处于阻塞或即将处于阻塞状态,则会发生InterruptedException并被抛出,当抛出该异常或使用interrupted()方法判断是否中断时将会重置中断状态为false。

1.1 详解interrupt()方法实现线程中断操作(阻塞线程中断)

       1) 当其他线程调用某线程的interrupt()方法时,仅仅时将该线程的中断状态设置为true,并不是一定会立即将该线程中断使其进入终止状态,相当于其他线程对该线程说“兄弟,你要结束了”。如果这个线程处于阻塞或是即将进入阻塞状态时则会发生中断,也可以设置一些中断条件,通过与isInterrupted()方法进行&&操作实现中断。代码如下:

public class Demo8 extends Thread{  
    public static void main(String[] args) {  
        Demo8 itt = new Demo8();  
        itt.start();  
        try {  
            Thread.sleep(5000);  
        } catch (InterruptedException e) {  
            e.printStackTrace();  
        }  
        itt.interrupt();  
    } 

    public void run() {  
        // 这里调用的是非清除中断标志位的isInterrupted方法  
        while(!Thread.currentThread().isInterrupted()) {  
            System.out.println(Thread.currentThread().getName() + " 正在运行");  
            try {  
                System.out.println(Thread.currentThread().getName() + "线程开始阻塞");  
                Thread.sleep(1000);  
                System.out.println(Thread.currentThread().getName() + " 线程阻塞结束");  
            } catch (InterruptedException e) {  
                // TODO Auto-generated catch block  
                //由于调用sleep()方法清除状态标志位 所以这里需要再次重置中断标志位 否则线程会继续运行下去  
                Thread.currentThread().interrupt();  
                e.printStackTrace();  
            }  
        }  
        System.out.println("跳出循环");
        if (Thread.currentThread().isInterrupted()) {  
            System.out.println(Thread.currentThread().getName() + "线程被中断");  
        }  
    }  
      
}  

        2)有两种情况无法发生中断:不能中断正在获取synchronized锁或者试图执行IO操作的线程,代码如下

public class Demo9 {
	public static void main(String[] args) throws Exception {
		
	    InputStream in=System.in;//不会被中断
		Thread t1=new Thread(new IOBlocked(in));
		Thread t2=new Thread(new SynchronizedBlocked());
		t1.start();
		t2.start();
		try {
			Thread.sleep(2000);
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		t1.interrupt();
		t2.interrupt();
	}
}
class IOBlocked implements Runnable{
	private InputStream in;
	public IOBlocked(InputStream is){
		in=is;
	}
	public void run(){
		try{
			while(true){
				System.out.println("等待进行io操作");
				in.read();//试图进行IO操作
			}
		}catch (IOException e) {
			if(Thread.currentThread().isInterrupted()){
				System.out.println("IO thread is Interrupted");
			}else{
				throw new RuntimeException(e);
			}
		}
		System.out.println("io操作运行中");
	}
}
class SynchronizedBlocked implements Runnable{
	public synchronized void f(){
		//永不释放锁
		while(true){
			Thread.yield();
		}
	}
	public SynchronizedBlocked(){
		new Thread(){
			public void run(){
				SynchronizedBlocked.this.f();//在此线程中获取锁,并且不进行释放
			}
		}.start();
	}
	@Override
	public void run() {
		// TODO Auto-generated method stub
		System.out.println("尝试调用f()");
		f();//在此处尝试获取锁
		System.out.println("f()运行中");
	}
	
}

        3)对于无法中断的IO操作,我们可以通过关闭任务中发生阻塞的底层资源,如上代码中的System.in可以通过关闭流的方式来进行中断。

    4)对于无法中断互斥所引起的阻塞,我们可以使用ReentrantLock类的tryLock方法或.lockInterruptibly()方法即可解决。

1.2 检查线程中断(实现非阻塞线程中断)

    1)当调用某个线程的interrupt方法时,中断发生的唯一时刻是在任务即将进入到阻塞操作中时或者已经在阻塞操作内部,若在某个死循环中添加了可能会产生阻塞操作的代码,但恰巧没有发生任何阻塞的情况下,我们需要另一种方式来退出。

public class InterruptThreadTest extends Thread{  
    public void run() {  
        // 这里调用的是非清除中断标志位的isInterrupted方法  
        while(!Thread.currentThread().isInterrupted()) {  
            long beginTime = System.currentTimeMillis();  
            System.out.println(Thread.currentThread().getName() + "is running");  
            // 当前线程每隔一秒钟检测线程中断标志位是否被置位  
            while (System.currentTimeMillis() - beginTime < 1000) {}  
        }  
        if (Thread.currentThread().isInterrupted()) {  
            System.out.println(Thread.currentThread().getName() + "is interrupted");  
        }  
    }  
      
    public static void main(String[] args) {  
        // TODO Auto-generated method stub  
        InterruptThreadTest itt = new InterruptThreadTest();  
        itt.start();  
        try {  
            Thread.sleep(5000);  
        } catch (InterruptedException e) {  
            // TODO Auto-generated catch block  
            e.printStackTrace();  
        }  
        // 设置线程的中断标志位  
        itt.interrupt();  
    }  
}  

    2)检查线程中断的方法:

        isInterrupted()方法判断当前线程是否为中断状态

        interrupted()方法判断当前线程是否为中断状态,并且会重置线程中断状态为false

    3)如何正确的安全的终止线程:中断状态是线程的一个标识位,而中断操作是一种简便的线程间交互 方式,而这种交互方式最适合用来取消或停止任务。除了中断以外,还可以利用一个boolean变 量来控制是否需要停止任务并终止该线程。这种通过标识位或者中断操作的方式能够使线程在终止时有机会去清理资源,而不是武断地将线程停止,因此这种终止线程的做法显得更加安全和优雅。

public class Shutdown {
	public static void main(String[] args) throws Exception {
		Runner one = new Runner();
		Thread countThread = new Thread(one, "CountThread");
		countThread.start();
		// 睡眠1秒,main线程对CountThread进行中断,使CountThread能够感知中断而结束
		Thread.sleep(1);
		countThread.interrupt();
		Runner two = new Runner();
		countThread = new Thread(two, "CountThread");
		countThread.start();
		// 睡眠1秒,main线程对Runner two进行取消,使CountThread能够感知on为false而结束
		Thread.sleep(1);
		two.cancel();
	}

	private static class Runner implements Runnable {
		private long i;
		private volatile boolean on = true;

		@Override
		public void run() {
			while (on && !Thread.currentThread().isInterrupted()) {
				i++;
			}
			System.out.println("Count i = " + i);
		}

		public void cancel() {
			on = false;
		}
	}
}

 

相关文章
|
4月前
|
存储 Linux 调度
Linux多线程【线程控制】
Linux多线程【线程控制】
57 0
|
4月前
|
存储 缓存 Linux
Linux多线程【初识线程】
Linux多线程【初识线程】
37 0
|
安全 算法 Java
去某东面试遇到并发编程问题:如何安全地中断一个正在运行的线程
一个位5年的小伙伴去某东面试被一道并发编程的面试题给Pass了,说”如何中断一个正在运行中的线程?,这个问题很多工作2年的都知道,实在是有些遗憾。 今天,我给大家来分享一下我的回答。
86 0
|
12月前
|
缓存 算法 安全
Linux设备驱动程序(五)——并发和竞态 2
Linux设备驱动程序(五)——并发和竞态
29 0
|
安全 Java API
Java线程中断的秘密
也学学why哥,在每篇文章加一段荒腔走板的内容。也就是随便聊聊,可能是自己近期的生活状态或者感悟,一些想法和思考,也可能是写这篇文章的初衷等等,甚至只是随便吹吹牛。
195 1
|
Java API
面试官问:如何中断一个线程,具体如何实现?(下)
面试官问:如何中断一个线程,具体如何实现?(下)
面试官问:如何中断一个线程,具体如何实现?(下)
|
程序员
面试官问:如何中断一个线程,具体如何实现?(上)
面试官问:如何中断一个线程,具体如何实现?(上)
148 0
|
Java 程序员 API
Java多线程系列篇之中断机制
Java多线程系列篇之中断机制:我们平时在使用多线程的时候都会遇到有可能需要中断线程操作,java提供了Thread.interrupted方法,但是就是简单调用就能中断线程了吗?下面带大家来看看具体如何用正确的姿势去中断线程
263 0
|
Java API
Java并发编程基础-理解中断
章节 什么是中断 中断线程的方法 线程中断状态的判断以及何时被中断的线程所处 isInterrupted() 状态为 false? 1.什么是中断 线程标识位 中断可以理解为线程的一个标识位属性,它标识一个运行中的线程是否被其他线程进行了中断操作。
782 0