【Java】Java线程中断(Interrupt)与阻塞(park)的区别

对于很多刚接触编程的人来说,对于线程中断和线程阻塞两个概念,经常性是混淆起来用,单纯地认为线程中断与线程阻塞的概念是一致的,都是值线程运行状态的停止。其实这个观点是错误的,两者之前有很大的区别,下文就着重介绍两者之间的区别。

线程中断

在一个线程正常结束之前,如果被强制终止,那么就有可能造成一些比较严重的后果,设想一下如果现在有一个线程持有同步锁,然后在没有释放锁资源的情况下被强制休眠,那么这就造成了其他线程无法访问同步代码块。因此我们可以看到在 Java 中类似 Thread#stop() 方法被标为 @Deprecated。

针对上述情况,我们不能直接将线程给终止掉,但有时又必须将让线程停止运行某些代码,那么此时我们必须有一种机制让线程知道它该停止了。Java 为我们提供了一个比较优雅的做法,即可以通过 Thread#interrupt() 给线程该线程一个标志位,让该线程自己决定该怎么办。

接下来就用代码来延时下 interrupt() 的作用:

public class InterruptDemo {static class MyThread implements Runnable {@Overridepublic void run() {for (int i= 0; !Thread.currentThread().isInterrupted() && i < 200000; i++) {System.out.println(Thread.currentThread().getName() + ":i = " + i);}}}public static void main(String[] args) throws InterruptedException {Thread myThread = new Thread(new MyThread());myThread.start();// 让线程运行一段时间Thread.sleep(5);myThread.interrupt();// 等待 myThread 运行停止myThread.join();System.out.println("end");}}

可以看到,当前线程并没有按 for 循环中的结束量 20000 去跑,而是在被中断后,停止了当前了 for 循环。所以我们可以利用 interrupt 配置线程使用,使得线程在一定的位置停止下来。

不过到这里可能会让人产生一些疑惑,因为在这里看起来,当前线程像是被阻塞掉了,其实并不是的,我们可以利用下面这段代码来演示下:

public class InterruptDemo {static class MyThread implements Runnable {@Overridepublic void run() {for (int i= 0; i < 200000; i++) {System.out.println(Thread.currentThread().getName() + ":i = " + i);}}}public static void main(String[] args) throws InterruptedException {Thread myThread = new Thread(new MyThread());myThread.start();// 让线程运行一段时间Thread.sleep(5);myThread.interrupt();// 等待 myThread 运行停止myThread.join();System.out.println("end");}}


可见,线程一直打印到 20000,执行完毕后推出线程,并没有像我们预料中在某处中断。所以我们可以得出结论:单纯用 interrupt() 中断线程方法并不能停止当前正在运行的线程,需要配合其他方法才能正确停止线程。

了解完中断的基本概念后,线程的中断还有需要其他需要注意的点:

设置线程中断后,线程内调用 wait()、join()、slepp() 方法中的一种,都会抛出 InterruptedException 异常,且中断标志位被清除,重新设置为 false;
当线程被阻塞,比如调用了上述三个方法之一,那么此时调用它的 interrupt() 方法,也会产生一个 InterruptedException 异常。因为没有占有 CPU 的线程是无法给自己设置中断状态位置的;
尝试获取一个内部锁的操作(进入一个 synchronized 块)是不能被中断的,但是 ReentrantLock 支持可中断的获取模式:tryLock(long time, TimeUnit unit);
当代码调用中需要抛出一个 InterruptedException,捕获之后,要么继续往上抛,要么重置中断状态,这是最安全的做法。

线程阻塞

上面讲完了线程中断,它其实只是一个标志位,并不能让线程真正的停止下来,那么接下来就来介绍如何真正让线程停止下来。

对于这个问题,Java 中提供了一个较为底层的并发工具类:LockSupport,该类中的核心方法有两个:park(Object blocker) 以及 unpark(Thread thred),前者表示阻塞指定线程,后者表示唤醒指定的线程。

// java.util.concurrent.locks.LockSupportpublic static void park(Object blocker) {Thread t = Thread.currentThread();setBlocker(t, blocker);UNSAFE.park(false, 0L);setBlocker(t, null);
}public static void unpark(Thread thread) {if (thread != null)UNSAFE.unpark(thread);
}

该方法在 Java 的语言层面上比较简单,最终也是去调用 UNSAFE 中的 native 方法。真正涉及到底层的东西需要去理解 JVM 的源码,这里就不做太多的介绍。不过我们可以用一个简单的例子来演示下这两个方法:

public class LockSupportDemo {static class MyThread implements Runnable {@Overridepublic void run() {System.out.println(Thread.currentThread().getName() + "开始执行");LockSupport.park();System.out.println(Thread.currentThread().getName() + "执行结束");}}public static void main(String[] args) throws InterruptedException {Thread thread = new Thread(new MyThread(), "线程:MyThread");thread.start();Thread.sleep(100);System.out.println(Thread.currentThread().getName() + "主线程执行中");LockSupport.unpark(thread);System.out.println(Thread.currentThread().getName() + "主线程执行结束");}}

interrupt和park的区别相关推荐

  1. Java-线程中sleep()、wait()和notify()和notifyAll()、suspend和resume()、yield()、join()、interrupt()的用法和区别

    Java线程中sleep().wait()和notify()和notifyAll().suspend和resume().yield().join().interrupt()的用法和区别 从操作系统的角 ...

  2. java 中断线程 wait_Java 线程中断(interrupt)与阻塞 (park)的区别

    很多Java开发人员(包括我),尤其是刚进入软件行业的新手,认为Java设置线程中断就是表示线程停止了,不往前执行了, Thread.currentThread().interrupt() 其实不是这 ...

  3. JUC 高并发编程(13):LockSupport 概述, wait 与 sleep与park的区别

    LockSupport LockSupport 是一个线程阻塞工具类,所有的方法都是静态方法,可以让线程在任意位置阻塞,阻塞之后也有对应的唤醒方法.归根结底,LockSupport调用的Unsafe中 ...

  4. 并发编程之二:线程创建方法、运行原理、常见方法(sleep,join,interrupt,park,守护线程等)

    线程创建方法.运行原理.常见方法 线程的创建方法 继承Thread 实现Runnable FutureTask 线程的运行原理 栈与栈帧 线程运行情况 线程的上下文切换(Thread Context ...

  5. Thread.sleep() / Object.wait() / Condition.await() / LockSupport.park() / LockSupport.unpark() 区别

    转自:https://www.cnblogs.com/tong-yuan/p/11768904.html Thread.sleep()和Object.wait()的区别 首先,我们先来看看Thread ...

  6. interrupt()中断对LockSupport.park()的影响

    文章目录 原理简单讲解 调用park()与unpark() park/unpark实现的伪代码 park/unpark的实验 interrupt()与park() interrupt()实现的伪代码 ...

  7. 并发编程之LockSupport的 park 方法及线程中断响应

    系列文章目录 Java并发编程技术知识点梳理(第一篇)操作系统底层工作的整体认识 Java并发编程技术知识点梳理(第二篇)并发编程之JMM&volatile详解 Java并发编程技术知识点梳理 ...

  8. 【高并发】又一个朋友面试栽在了Thread类的stop()方法和interrupt()方法上!

    来自:冰河技术 写在前面 新一轮的面试已经过去,可能是疫情的原因吧,很多童鞋纷纷留言说今年的面试题难度又提高了,尤其是对并发编程的知识.我细想了下,也许有那么点疫情的原因吧,但无论面试的套路怎么变,只 ...

  9. Java多线程(九)—— interrupt()和线程终止方式

    一.interrupt() 说明 interrupt()的作用是中断本线程. 本线程中断自己是被允许的:其它线程调用本线程的interrupt()方法时,会通过checkAccess()检查权限.这有 ...

最新文章

  1. Linux虚拟机安装配置准备工作之--- VMware ( Bridge )
  2. html5赛车小游戏,html5公路赛车小游戏
  3. Mac系统下安装Homebrew后无法使用brew命令
  4. FireFox 在新建标签页插入“片段”广告引社区争议
  5. Cucumber常用关键字
  6. H.264 NAL层解析
  7. foobar2000设置关闭按钮最小化到系统托盘
  8. oppo android多大内存,OPPO R9的内存容量是多少
  9. Node的文件操作、文件系统、数据流
  10. 100份开工礼送粉丝,体验嵌入式高级感!
  11. 计算机开机最快设置,那些电脑开机速度击败全国99%的人,他们是怎么做到的?...
  12. win10 安装硕正
  13. 解决input获取焦点后,旁边文字抖动问题
  14. Decorator装饰者【C++实现】
  15. 上传资源到静态服务器
  16. java物联网第二天 感悟下
  17. PEP8 - Python 代码风格指南中英对照
  18. 高压放大器驱动压电器件工作原理
  19. Linux系统安装驱动过程中ko文件加载错误(Required key not available)的解决办法
  20. 硅谷上市公司 Confluent 饶军:我能开公司,所有人都有机会

热门文章

  1. 如何在GitHub上创建自己的仓库?
  2. 2021年安全员-B证考试试题及安全员-B证操作证考试
  3. 【小技巧】2345——劫持Edge浏览器主页,它它它.....它又回来了
  4. 树莓派的应用--人体感应器HC-SR501
  5. 1.1 Java HTML前端网页
  6. 从今天开始学习python和英语
  7. Vue创建项目的步骤
  8. 如何编写snort的检测规则
  9. MP2451 使能脚电阻判断
  10. html tab顶部吸附,flutter,SliverPersistentHeader实现Tab顶部吸附固定效果