源码解读(一):interrupt()、isInterrupted()和interrupted()以及InterruptedException

Java中的interrupt以及InterruptedException

1、 什么是中断(interrupt)

有时候我们会有这样的需求,让一个线程停止。在Java中提供stop、suspend、resume等方法控制一个线程,但是这些方法都线程不安全。随后就引用了今天的重点内容–中断(interrupt)
中断(interrupt) 是线程的一个状态;可以理解为Thread对象中存在一个boolean型变量,用于标记中断状态。其他线程只能通过修改这个变量来通知对应线程是否需要停止。被标记中断的线程在代码内部根据中断状态来响应中断操作的。这样该线程的生命周期被自己控制和管理,保证了线程安全性。

2、中断(interrupt)的使用

中断在Java中有三个主要的方法interrupt()、isInterrupted()和interrupted(),以及一个重要的异常InterruptedException。

  1. interrupt(),通过线程对象调用interrupt()方法,标记该线程为中断状态,无返回值。
  2. isInterrupted(),获取中断状态,返回true表示已标记,返回false表示未标记。
  3. interrupted(),返回并清除中断状态;该方法是Thread的静态方法。这个操作只能清除当前调用线程的中断状态,是无法清除其他线程中断状态的。
  4. InterruptedException,捕获响应interrupt()方法出现的异常,根据中断状态进行业务控制。
    为了更清楚的说明这四者之间的关系,我们先看看源码再用示例代码进行演示。

interrupt()方法源码

public void interrupt() {
		// 先判断是否操作线程
        if (this != Thread.currentThread())
            checkAccess();
		// 标记中断状态
        synchronized (blockerLock) {
            Interruptible b = blocker;
            if (b != null) {
                interrupt0();           // Just to set the interrupt flag
                b.interrupt(this);
                return;
            }
        }
        interrupt0();
    }

interrupted() 和isInterrupted()方法源码。

	// 返回并清除中断状态,静态方法,清除对象是当前线程
	public static boolean interrupted() {
        return currentThread().isInterrupted(true);
    }
	
	// 返回中断状态
	public boolean isInterrupted() {
        return isInterrupted(false);
    }
    
	// 返回中断状态,并根据ClearInterrupted判断是否清除标记,清除后为false
    private native boolean isInterrupted(boolean ClearInterrupted);

下面示例中,我们让线程t1获取锁,然后让t2调用lock.lockInterruptibly()使线程处在阻塞状态,随后又调用t2.interrupt()方法,标记t2中断状态,此时中断状态为true,由于lockInterruptibly()响应中断,程序立刻进入了InterruptedException分支,并清除标记状态。这里仅仅以lockInterruptibly()为例子进行说明,很多抛出InterruptedException异常的方法都是响应异常的,其流程也是相同的。例如TimeUnit.SECONDS.sleep(long timeout)、Thread.sleep(long millis)等等方法。

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;

public class Main {
    public static void main(String[] args) throws InterruptedException {
        ReentrantLock lock = new ReentrantLock();
        Thread t1 = new Thread(new Runnable() {
            @Override
            public void run() {
                lock.lock();
                try {
                    TimeUnit.SECONDS.sleep(3);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }finally {
                    lock.unlock();
                }
            }
        });
        Thread t2 = new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    // 响应中断
                    lock.lockInterruptibly();
                    //TimeUnit.SECONDS.sleep(10);
                } catch (InterruptedException e) {
                    // 抛出InterruptedException,中断标记被清除,下面返回false
                   System.out.println(Thread.currentThread().isInterrupted());
                    e.printStackTrace();
                }finally {
                    lock.unlock();
                }
            }
        });
        t1.start();
        TimeUnit.SECONDS.sleep(1);
        t2.start();
        TimeUnit.SECONDS.sleep(1);
        t2.interrupt();
    }
}

流程上和上面的代码类似,这里主要介绍了lock.lock(),此处不响应中断状态,即使此时已经标记中断状态,任然继续执行后续代码,直至执行到响应异常的代码,清除中断标记并跳转到异常分支中。

import java.util.concurrent.TimeUnit;
        import java.util.concurrent.locks.ReentrantLock;

public class Main {
    public static void main(String[] args) throws InterruptedException {
        ReentrantLock lock = new ReentrantLock();
        Thread t1 = new Thread(new Runnable() {
            @Override
            public void run() {
                lock.lock();
                try {
                    TimeUnit.SECONDS.sleep(3);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } finally {
                    lock.unlock();
                }
            }
        });
        Thread t2 = new Thread(new Runnable() {
            @Override
            public void run() {
                // 未标记中断状态,查看标记状态
                System.out.println("before:" + Thread.currentThread().isInterrupted());
                // 该方法不响应中断状态,继续执行代码
                lock.lock();
                // 已标记中断状态,查看标记状态
                System.out.println("after:" + Thread.currentThread().isInterrupted());
                try {
                    Thread.sleep(1);
                } catch (InterruptedException e) {
                    // 抛出InterruptedException,中断标记被清除,下面返回false
                    System.out.println("Catch Exception:" + Thread.currentThread().isInterrupted());
                    e.printStackTrace();
                } finally {
                    lock.unlock();
                }
            }
        });
        t1.start();
        TimeUnit.SECONDS.sleep(1);
        t2.start();
        TimeUnit.SECONDS.sleep(1);
        t2.interrupt();
    }
}

执行结果很直观反映了中断状态是如何使用的。
在这里插入图片描述

下面示例是关于Thread.interrupted()方法的使用,在这里调用Thread.interrupted()清除中断状态后,对比上面示例我们会发现,isInterrupted()返回的是false并且Thread.sleep(1)方法不会进入异常分支。

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;

public class Main {
    public static void main(String[] args) throws InterruptedException {
        ReentrantLock lock = new ReentrantLock();
        Thread t1 = new Thread(new Runnable() {
            @Override
            public void run() {
                lock.lock();
                try {
                    TimeUnit.SECONDS.sleep(3);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } finally {
                    lock.unlock();
                }
            }
        });
        Thread t2 = new Thread(new Runnable() {
            @Override
            public void run() {
                // 未标记中断状态,查看标记状态
                System.out.println("before interrupt:" + Thread.currentThread().isInterrupted());
                // 该方法不响应中断状态,继续执行代码
                lock.lock();
                // 已标记中断状态,查看标记状态
                System.out.println("after interrupt:" + Thread.currentThread().isInterrupted());
                // 返回中断状态,并清除中断状态
                System.out.println("doing interrupted:" + Thread.interrupted());
                // 已标记中断状态,查看标记状态
                System.out.println("after interrupted:" + Thread.currentThread().isInterrupted());
                try {
                    Thread.sleep(1);
                } catch (InterruptedException e) {
                    System.out.println("Catch Exception:" + Thread.currentThread().isInterrupted());
                    e.printStackTrace();
                } finally {
                    lock.unlock();
                }
            }
        });
        t1.start();
        TimeUnit.SECONDS.sleep(1);
        t2.start();
        TimeUnit.SECONDS.sleep(1);
        t2.interrupt();
    }
}

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值