如何中断一个线程?

一、了解interrupt、interrupted、isInterrupted

public void interrupt();

Thread#interrupt()并不能真正的中断线程,而是通知线程应该中断了。具体到底中断还是继续运行,应该由被通知的线程自己处理。

具体来说,当对一个线程调用interrupt()时:

  • 如果线程处于正常活动状态,那么会将该线程的中断标志位设置为true,仅此而已。被设置中断标志的线程将继续正常运行,不受影响。
  • 如果线程处于被阻塞状态(比如Object.wait, Thread.sleep, Object.join),会不断地轮询监听中断标志位,发现其被设置为true后,会停止阻塞并抛出InterruptedException异常。在抛出异常后立即将线程的中断标志位清除,即重新设置为false。
  • synchronized在获锁的过程中是不能被中断的,意思是说如果产生了死锁,则不能被中断。类似的,reentrantLock.lock()也是不可中断的。如果调用时被阻塞,则它一直阻塞到它获取到锁为止。
  • 如果调用带超时的reentrantLock.tryLock(long timeout, TimeUnit unit)或reentrantLock.lockInterruptibly(),那么线程在等待时被中断,将抛出一个InterruptedException异常,这是一个非常有用的特性,因为它允许程序打破死锁。
public static boolean interrupted();

检测当前线程是否已经中断,是则返回true,否则false,并清除中断状态。换言之,如果该方法被连续调用两次,第二次必将返回false,除非在第一次与第二次的瞬间线程再次被中断。如果中断调用时线程已经不处于活动状态,则返回false。

public boolean isInterrupted();

检测当前线程是否已经中断,是则返回true,否则false。中断状态不受该方法的影响。如果中断调用时线程已经不处于活动状态,则返回false。

如何中断一个线程

1.使用中断信号量中断非阻塞状态的线程
class Example2 extends Thread {
    volatile boolean stop = false;// 线程中断信号量

    public static void main(String args[]) throws Exception {
        Example2 thread = new Example2();
        System.out.println("Starting thread...");
        thread.start();
        Thread.sleep(3000);
        System.out.println("Asking thread to stop...");
        // 设置中断信号量
        thread.stop = true;
        Thread.sleep(3000);
        System.out.println("Stopping application...");
    }

    public void run() {
        // 每隔一秒检测一下中断信号量
        while (!stop) {
            System.out.println("Thread is running...");
            long time = System.currentTimeMillis();
            /*
             * 使用while循环模拟 sleep 方法,这里不要使用sleep,否则在阻塞时会 抛
             * InterruptedException异常而退出循环,这样while检测stop条件就不会执行,
             * 失去了意义。
             */
            while ((System.currentTimeMillis() - time < 1000)) {}
        }
        System.out.println("Thread exiting under request...");
    }
}

2.使用thread.interrupt()中断非阻塞状态线程
class Example2 extends Thread {
    public static void main(String args[]) throws Exception {
        Example2 thread = new Example2();
        System.out.println("Starting thread...");
        thread.start();
        Thread.sleep(3000);
        System.out.println("Asking thread to stop...");
        // 发出中断请求
        thread.interrupt();
        Thread.sleep(3000);
        System.out.println("Stopping application...");
    }

    public void run() {
        // 每隔一秒检测是否设置了中断标示
        while (!Thread.currentThread().isInterrupted()) {
            System.out.println("Thread is running...");
            long time = System.currentTimeMillis();
            // 使用while循环模拟 sleep
            while ((System.currentTimeMillis() - time < 1000) ) {
            }
        }
        System.out.println("Thread exiting under request...");
    }
}
3.使用thread.interrupt()中断阻塞状态线程
class Example3 extends Thread {
    public static void main(String args[]) throws Exception {
        Example3 thread = new Example3();
        System.out.println("Starting thread...");
        thread.start();
        Thread.sleep(3000);
        System.out.println("Asking thread to stop...");
        thread.interrupt();// 等中断信号量设置后再调用
        Thread.sleep(3000);
        System.out.println("Stopping application...");
    }

    public void run() {
        while (!Thread.currentThread().isInterrupted()) {
            System.out.println("Thread running...");
            try {
                /*
                 * 如果线程阻塞,将不会去检查中断信号量stop变量,所 以thread.interrupt()
                 * 会使阻塞线程从阻塞的地方抛出异常,让阻塞线程从阻塞状态逃离出来,并
                 * 进行异常块进行 相应的处理
                 */
                Thread.sleep(1000);// 线程阻塞,如果线程收到中断操作信号将抛出异常
            } catch (InterruptedException e) {
                System.out.println("Thread interrupted...");
                /*
                 * 如果线程在调用 Object.wait()方法,或者该类的 join() 、sleep()方法
                 * 过程中受阻,则其中断状态将被清除
                 */
                System.out.println(this.isInterrupted());// false

                //中不中断由自己决定,如果需要真真中断线程,则需要重新设置中断位,如果
                //不需要,则不用调用
                Thread.currentThread().interrupt();
            }
        }
        System.out.println("Thread exiting under request...");
    }
}
4.死锁状态线程无法被中断
class Example4 extends Thread {
    public static void main(String args[]) throws Exception {
        final Object lock1 = new Object();
        final Object lock2 = new Object();
        Thread thread1 = new Thread() {
            public void run() {
                deathLock(lock1, lock2);
            }
        };
        Thread thread2 = new Thread() {
            public void run() {
                // 注意,这里在交换了一下位置
                deathLock(lock2, lock1);
            }
        };
        System.out.println("Starting thread...");
        thread1.start();
        thread2.start();
        Thread.sleep(3000);
        System.out.println("Interrupting thread...");
        thread1.interrupt();
        thread2.interrupt();
        Thread.sleep(3000);
        System.out.println("Stopping application...");
    }

    static void deathLock(Object lock1, Object lock2) {
        try {
            synchronized (lock1) {
                Thread.sleep(10);// 不会在这里死掉
                synchronized (lock2) {// 会锁在这里,虽然阻塞了,但不会抛异常
                    System.out.println(Thread.currentThread());
                }
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
            System.exit(1);
        }
    }
}

参考Thread的中断机制(interrupt)

在Java中安全地中断线程通常涉及到使用`Thread`类的`interrupt()`方法,这是一个协作机制,允许一个线程通知另一个线程线程中断了。以下是安全中断线程的一些步骤和注意事项: 1. 使用`interrupt()`方法:这是最直接的中断线程的方式。当你调用一个线程的`interrupt()`方法时,如果该线程处于阻塞状态(例如在`sleep()`、`wait()`、`join()`方法调用中),它将接收到一个`InterruptedException`异常。如果线程处于运行状态,它的中断标志将被设置,但不会立即停止。 2. 检查中断状态:在你的线程代码中,应该定期检查当前线程中断状态,通过调用`Thread.currentThread().isInterrupted()`或者捕获`InterruptedException`异常来响应中断请求。 3. 处理中断异常:当线程在执行阻塞操作时,比如`Thread.sleep()`,应该捕获`InterruptedException`。在这种情况下,通常会清除中断状态(调用`Thread.interrupted()`),并且可能根据中断来终止线程的执行。 4. 不要忽略中断:永远不要忽视中断请求。在你的代码中应该有适当的逻辑来处理中断,这可能意味着停止当前操作或者清理资源然后退出线程。 5. 使用中断标志位:在某些情况下,线程可能在执行一个循环体中的代码,这个循环体没有调用阻塞方法,这时可以通过一个共享的中断标志位来安全地中断线程线程在每次循环检查这个标志位,如果发现被设置为中断状态,则退出循环。 示例代码(中断响应的线程): ```java public class InterruptibleThread extends Thread { public void run() { while (!Thread.currentThread().isInterrupted()) { // 执行任务... try { // 在某些点上进行阻塞操作... Thread.sleep(1000); } catch (InterruptedException e) { // 捕获到中断异常后,线程应该退出 Thread.currentThread().interrupt(); // 重新设置中断标志 break; // 跳出循环,准备退出线程 } } } } // 在其他地方中断线程 InterruptibleThread it = new InterruptibleThread(); it.start(); it.interrupt(); // 请求中断 ```
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值