- 面试不多,难度低,但是容易混淆
- 此处线程的“打断”不是把线程打折腿
- 不是线程的停止与中断
- 名字不好===>容易混淆
线程打断的3个方法
- 不是特别重要
- 第一个比后两个重要,第一个除了可以配合对于这个标志位的检查,能正确结束一个线程之外也不是很重要
- 读jdk源码时,可能会碰到线程打断相关的知识点,所以要知道
interrupt()
- t.interrupt()设中断标志位
- 打断某个线程(设置标志位===>有没有被打断过、有没有被申请打断过)
- 原来是false,调用该方法给标志位设成true
- 只是申请一下,设置一下标志位,只是给了线程一个信(号),至于线程收到这个信(号)之后要不要处理,该如何处理,这要看线程自身,看自己如何安排
-
isInterrupted()
查询某线程是否被打断过(查询标志位)
- 是否被设置过那个标志位
- 设过了来查,没设过来查
static interrupted()
- 查询当前线程(当前正在执行的线程RUNNING)是否被打断过,并重置打断标志
- 容易与第二个混淆,不需要线程对象,直接用类调用即可
- 查询是否被设置过标志位,假如设置过了(标志位为true),就重置标志位===>即将标志位设回为false
代码示例
SleepHelper帮助类(只是简答地将try……catch……扔到帮助类中)
在演示式的代码中写很多try……catch……,看起来费劲
package com.mashibing.util;import java.util.concurrent.TimeUnit;public class SleepHelper {public static void sleepSeconds(int seconds) {try {TimeUnit.SECONDS.sleep(seconds) ;} catch (InterruptedException e) {e.printStackTrace();}}}
interrupt()与isInterrupted()
- 线程结束可以采用这种方法
- 设置一个循环,每一次循环都检查一下是否有人设置了标志位;假如有人设置了,就可以退出循环(break),结束线程===>优雅地结束线程的方案
package com.mashibing.juc.c_000_threadbasic;import com.mashibing.util.SleepHelper;/*** interrupt()与isInterrupted()* 设置标志位 + 查询标志位*/public class T05_Interrupt_and_isInterrupted {public static void main(String[] args) {Thread t = new Thread(() -> {for (; ; ) {// 查询出来后并不能将标志位重置if (Thread.currentThread().isInterrupted()) {System.out.println("Thread is interrupted!");System.out.println(Thread.currentThread().isInterrupted());// break;}}});t.start();// 两秒后设中断标志位SleepHelper.sleepSeconds(2);t.interrupt();}}
interrupt与interrupted()
- interrupted()方法是一个静态成员变量(静态方法),拿的是当前线程
- interrupted()方法返回当前标志位的状态并将标志位复位(恢复)
package com.mashibing.juc.c_000_threadbasic;import com.mashibing.util.SleepHelper;/*** interrupt与interrupted()*/public class T06_Interrupt_and_interrupted {public static void main(String[] args) {Thread t = new Thread(() -> {for (; ; ) {if (Thread.interrupted()) {System.out.println("Thread is interrupted!");System.out.println(Thread.interrupted());}}});t.start();SleepHelper.sleepSeconds(2);t.interrupt();//思考一下,如果在这里写System.out.println("main: " + t.interrupted());//输出的是哪个线程的中断状态// 输出false,虽然写的是t.interrupt,但是由于这个方法interrupted()是一个静态成员变量(静态方法),拿的是当前线程;这里的当前线程是主线程}}
interrupt与sleep() wait() join()
- 在sleep时、wait时、join时,一旦对其设置了标志位(interrupt打断了线程),就会抛(出)异常InterruptedException
- 抛出这个异常之后,下一步怎么处理;
- 要不要catch,还是throws
- catch之后如何处理
- 主动权还是在线程本身
- 在不间断运行的服务器里,如果有sleep方法(不建议有)、wait方法(这个有可能有)、join方法(也很少用),要想用interrupt方法让他停止的话,必须得catch住interrupt异常,然后对异常做出正确的响应===>应用程序要退出,记录日志退出;忽略这个异常,继续向下执行,循环;这个主要交给写程序的程序员处理了,没有固定的处理方式;看了这个异常怎么处理是自己的事情,并不是一打断就会终止线程
- (一旦抛出InterruptException的异常之后)catch住exception之后,默认情况下,java会自动地将(中断)标志位复位===>既然已经catch住了,说明你要处理了,赶紧给你复位复回去,以免别人再次打断,那个打断状态抓不着
package com.mashibing.juc.c_000_threadbasic;import com.mashibing.util.SleepHelper;/*** interrupt与sleep() wait() join()*/public class T07_Interrupt_and_sleep {public static void main(String[] args) {Thread t = new Thread(() -> {try {Thread.sleep(10000);} catch (InterruptedException e) {System.out.println("Thread is interrupted!");System.out.println(Thread.currentThread().isInterrupted());}});t.start();SleepHelper.sleepSeconds(5);t.interrupt();}}
package com.mashibing.juc.c_000_threadbasic;import com.mashibing.util.SleepHelper;/*** interrupt与sleep() wait() join()*/public class T08_Interrupt_and_wait {private static Object o = new Object();public static void main(String[] args) {Thread t = new Thread(() -> {synchronized (o) {try {o.wait();} catch (InterruptedException e) {System.out.println("Thread is interrupted!");System.out.println(Thread.currentThread().isInterrupted());}}});t.start();SleepHelper.sleepSeconds(5);t.interrupt();}}
interrupt与synchronized
- 打断一个线程能不能将一个正在竞争锁、争抢锁的线程给打断,会不会抛异常
- 不可能,不会抛异常和打断线程
- 线程在争抢锁的过程中是不可能被interrupt打断或者干扰掉的
package com.mashibing.juc.c_000_threadbasic;import com.mashibing.util.SleepHelper;/*** interrupt与synchronized*/public class T09_Interrupt_and_sync {private static Object o = new Object();public static void main(String[] args) {Thread t1 = new Thread(() -> {synchronized (o) {// sleep方法不会释放锁,10s内这把锁归t1所有SleepHelper.sleepSeconds(10);}});t1.start();SleepHelper.sleepSeconds(1);Thread t2 = new Thread(() -> {// t2去抢那把锁,只有等t1线程执行完了才能抢到,那么这是能将线程打断吗?synchronized (o) {}System.out.println("t2 end!");});t2.start();SleepHelper.sleepSeconds(1);// 只是设标志位,不是将线程打折腿// 设标志位之后该抢锁还是得抢锁,不会理会标志位设不设t2.interrupt();}}
interrupt与lock
- 设标志位能不能干扰(最好不要说打断)juc中的ReentrantLock这种新型的锁
- 经验证,也不会干扰到
- 如果说有一个线程持有了一把锁总是不释放,另外一个线程去申请这把锁的时候,中间过程是干扰(interrupt)不到的
- 像干扰到怎么做===>lock与synchronized的重要区别,lock可以使用lockInterruptibly()方法
package com.mashibing.juc.c_000_threadbasic;import com.mashibing.util.SleepHelper;import java.util.concurrent.locks.ReentrantLock;/*** interrupt与lock*/public class T10_Interrupt_and_lock {private static ReentrantLock lock = new ReentrantLock();public static void main(String[] args) {Thread t1 = new Thread(() -> {lock.lock();try {Thread.sleep(10000);} catch (InterruptedException e) {e.printStackTrace();} finally {lock.unlock();}System.out.println("t1 end!");});t1.start();SleepHelper.sleepSeconds(1);Thread t2 = new Thread(() -> {lock.lock();try {} finally {lock.unlock();}System.out.println("t2 end!");});t2.start();SleepHelper.sleepSeconds(1);t2.interrupt();}}
interrupt与lockInterruptibly()
- 解决interrupt不能干扰到lock锁住的线程的问题
- 线程在抢锁的过程中还盯着有没有人设自己的标志位,如果有人设自己的标志位,则抛异常
- catch住异常之后怎么处理,是继续抢这把锁,还是要放弃了,交给线程,交给程序员自己处理
- 如果想打断锁争抢的过程,如果想允许interrupt方法干扰抢锁过程,用ReentrantLock中的lockInterruptibly方法
package com.mashibing.juc.c_000_threadbasic;import com.mashibing.util.SleepHelper;import java.util.concurrent.locks.ReentrantLock;/*** interrupt与lockInterruptibly()*/public class T11_Interrupt_and_lockInterruptibly {private static ReentrantLock lock = new ReentrantLock();public static void main(String[] args) {Thread t1 = new Thread(() -> {lock.lock();try {SleepHelper.sleepSeconds(10);} finally {lock.unlock();}System.out.println("t1 end!");});t1.start();SleepHelper.sleepSeconds(1);Thread t2 = new Thread(() -> {System.out.println("t2 start!");try {// 可以被打断的过程lock.lockInterruptibly();} catch (InterruptedException e) {e.printStackTrace();} finally {lock.unlock();}System.out.println("t2 end!");});t2.start();SleepHelper.sleepSeconds(1);t2.interrupt();}}
总结
- interrupt有一个很好的作用===>优雅地中断一个线程(中断线程有好多种方法)
