Java多线程学习(十一)中断机制interrupt学习

Java中,stop()和suspend()方法因可能导致数据丢失已被摒弃,取而代之的是优雅的中断机制——interrupt()。线程中断并不立即停止线程,而是设置线程的中断标志。线程通过isInterrupted()或interrupted()检测中断状态,其中interrupted()会清除标志位。当使用sleep(), wait(), join()等可阻塞方法时,中断会抛出InterruptedException,中断阻塞状态。然而,synchronized和I/O操作无法直接中断。" 111269322,8061668,JS实现input输入后跳转百度搜索,"['前端开发', 'JavaScript', 'HTML', '搜索引擎交互']

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在实际应用中,如果想停掉某个线程,那么可以调用线程的stop()方法或者suspend()方法来强制性的停止某个线程。但是这种方法是很粗暴的,它是强制性的停止线程,这样可能会导致线程之前工作的数据丢失,所以Java已经摒弃了这些强制终止的方法。

取而代之的是一种中断机制,interrupt()方法。在JVM中每个线程都有一个boolean类型的线程是否中断的标志,调用线程中断的方法只是将这个标志置为true,这是一种优雅的线程中断的方法,它告诉线程要中断了,而不是强制中断此线程。

线程在运行时需要检测这个标志位的状态,如果不检测,即使调用了中断方法线程也不会中断。

我们可以通过调用Thread.currentThread().isInterrupted()或者Thread.interrupted()来检测线程的中断标志是否被置位。这两个方法的区别是Thread.currentThread().isInterrupted()是线程对象的方法,调用它后不清除线程中断标志位;而Thread.interrupted()是一个静态方法,调用它会清除线程中断标志位。

中断非阻塞线程

比如,让主线程休眠一秒钟,保证线程1执行一段时间,然后在主线程中中断线程1,在线程1中用过检测标志位来查看线程是否该中断。如果中断了,保存计算结果。

public class InterruptTest2 {
    public static void main(String[] args) {
        Thread thread2 = new Thread(new Runnable() {
            @Override
            public void run() {
                int i = 0;
                while (!Thread.currentThread().isInterrupted()){
                    System.out.println("线程还在执行...");
                    for (; i < 1000000000; i++) {
                    }
                }
                if (Thread.currentThread().isInterrupted()){
                    System.out.println(i);
                }
            }
        });
        thread2.start();
        try {
            Thread.sleep(1000);
            thread2.interrupt();
            System.out.println("主线程中断线程1");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

 

中断阻塞线程

对于一些可阻塞的方法,比如sleep(),wait(),join()等方法,如果我们不用中断机制,而是自己去设置取消方法,那么当线程永久堵塞时,也就不能去检测标志位,那么线程就永远停不下来了。但是通过interrupt,这些可阻塞方法在JVM内部会检测interrupt标志位,当发现中断时,会抛出InterruptedException异常,来终止阻塞方法。

public class InterruptTest {
    public static void main(String[] args) {
        Thread thread = new Thread(new Runnable() {
            @Override
            public void run() {
                while (!Thread.currentThread().isInterrupted()){
                    System.out.println(Thread.currentThread().getName()+"正在执行");
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        //由于调用sleep()方法清除状态标志位 所以这里需要再次重置中断标志位 否则线程会继续运行下去。保留中断证据
                        Thread.currentThread().interrupt();
                        e.printStackTrace();
                    }
                    if (Thread.currentThread().isInterrupted()){
                        System.out.println(Thread.currentThread().getName()+"被中断了");
                    }
                }
            }
        });
        thread.start();
        try {
            System.out.println("主线程睡眠");
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("主线程中断其他线程");
        thread.interrupt();
        //线程一旦被中断,isInterrupted()方法便会返回true,而一旦sleep()方法抛出异常,它将清空中断标志,此时isInterrupted()方法将返回false。
        System.out.println("是否被中断1:"+thread.isInterrupted());
        System.out.println("主线程执行完成");
    }
}

对于非阻塞方法的中断,也可以通过抛出InterruptedException异常来传递中断。

 

不可中断线程

有一种情况是线程不能被中断的,比如调用synchronized关键字和reentrantLock.lock()获取锁的过程。输入和输出流类会阻塞等待 I/O 完成,但是它们不抛出 InterruptedException,而且在被中断的情况下也不会退出阻塞状态。

public class InterruptThreadTest5 {
	
    public void deathLock(Object lock1, Object lock2) {
        try {
            synchronized (lock1) {
            	System.out.println(Thread.currentThread().getName()+ " is running");
            	// 让另外一个线程获得另一个锁
                Thread.sleep(10);
                // 造成死锁
                synchronized (lock2) {
                    System.out.println(Thread.currentThread().getName());
                }
            }
        } catch (InterruptedException e) {
        	System.out.println(Thread.currentThread().getName()+ " is interrupted");
            e.printStackTrace();
        }
    }
	
	public static void main(String [] args) { 
		
		final InterruptThreadTest5 itt = new InterruptThreadTest5();
		final Object lock1 = new Object();
		final Object lock2 = new Object();
		Thread t1 = new Thread(new Runnable(){
			public void run() {
				itt.deathLock(lock1, lock2);
			}
		},"A"); 
		Thread t2 = new Thread(new Runnable(){
			public void run() {
				itt.deathLock(lock2, lock1);
			}
		},"B"); 
		
		t1.start();
		t2.start();
		try {
			Thread.sleep(3000);
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		// 中断线程t1、t2
		t1.interrupt();
		t2.interrupt();
	}
}

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值