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

it2022-05-05  109

Java中的interrupt以及InterruptedException

1、 什么是中断(interrupt)2、中断(interrupt)的使用

1、 什么是中断(interrupt)

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

2、中断(interrupt)的使用

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

interrupt(),通过线程对象调用interrupt()方法,标记该线程为中断状态,无返回值。isInterrupted(),获取中断状态,返回true表示已标记,返回false表示未标记。interrupted(),返回并清除中断状态;该方法是Thread的静态方法。这个操作只能清除当前调用线程的中断状态,是无法清除其他线程中断状态的。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(); } }


最新回复(0)