java JUC并发编程 第三章 中断机制

news2025/1/9 19:28:40

系列文章目录

第一章 java JUC并发编程 Future: link
第二章 java JUC并发编程 多线程锁: link
第三章 java JUC并发编程 中断机制: link


文章目录

  • 系列文章目录
  • 1 LockSupport前言
    • 1.1 如何停止中断运行中的线程
      • 1.1.1 通过volatile变量实现
      • 1.1.2 通过AtomicBoolean实现
      • 1.1.3 通过Thread类自带的中断api实现
        • 1.1.3.1 interrupt()源码分析
        • 1.1.3.2 isInterrupted源码分析
    • 1.2当前线程的中断标识为true,是不是线程就立刻停止
    • 1.3 静态方法Thread.interrupted()的理解
  • 2 LockSuppor
    • 2.1 3种让线程等待和唤醒的方法
      • 2.1.1 方式1:使用Object中的wait()方法让线程等待,使用Object中的notify方法唤醒线程
        • 2.1.1.1 异常情况1
        • 2.1.1.2 异常情况2
      • 2.1.2 方式2:使用JUC包中的Condition的await方法让线程等待,使用signal方法唤醒线程
        • 2.1.2.1 异常情况1
        • 2.1.2.2 异常情况2
      • 2.1.3 方式3: LockSupport类可以阻塞当前线程以及唤醒指定被阻塞的线程
        • 2.1.3.1 问题多个park和unpark会阻塞么:会
        • 2.1.3.2 总结


1 LockSupport前言

在这里插入图片描述
在这里插入图片描述

interrupt:中断此线程
interrupted:测试当前线程是否已被中断
isInterrupted:测试此线程是否已被中断
什么是中断机制
在这里插入图片描述

1.1 如何停止中断运行中的线程

1.1.1 通过volatile变量实现

package com.util.interrup;

import java.util.concurrent.TimeUnit;

public class InterrupDemo {
    static  volatile  boolean isStop = false;

    public static void main(String[] args) {
        new Thread(()->{
            while (true){
                if(isStop){
                    System.out.println(Thread.currentThread().getName()+"isStop被修改为true,程序停止");
                    break;
                }
                System.out.println("----hello");
            }
        },"t1").start();
        try {TimeUnit.MILLISECONDS.sleep(20);} catch (InterruptedException e) {e.printStackTrace();}

        new Thread(()->{
            isStop=true;
        },"t2").start();
    }
}

1.1.2 通过AtomicBoolean实现

package com.atguigu.springcloud.util.interrup;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;

public class InterrupDemo {

    static AtomicBoolean atomicBoolean = new AtomicBoolean(false);

    public static void main(String[] args) {
        new Thread(()->{
            while (true){
                if(atomicBoolean.get()){
                    System.out.println(Thread.currentThread().getName()+"isStop被修改为true,程序停止");
                    break;
                }
                System.out.println("----hello");
            }
        },"t1").start();
        try {TimeUnit.MILLISECONDS.sleep(20);} catch (InterruptedException e) {e.printStackTrace();}

        new Thread(()->{
            atomicBoolean.set(true);
        },"t2").start();
    }

}

1.1.3 通过Thread类自带的中断api实现

package com.atguigu.springcloud.util.interrup;

import java.util.concurrent.TimeUnit;

public class InterrupDemo {

    public static void main(String[] args) {
        Thread t1 = new Thread(()->{
            while (true){
                if(Thread.currentThread().isInterrupted()){
                    System.out.println(Thread.currentThread().getName()+"isInterrupted被修改为true,程序停止");
                    break;
                }
                System.out.println("t1 ---- hello interrupt api");
            }
        },"t1");
        t1.start();

        try {TimeUnit.MILLISECONDS.sleep(20);} catch (InterruptedException e) {e.printStackTrace();}
        //t2向t1发出协商,将t1的中断标志位设为true希望t1停下来
        Thread t2 = new Thread(()->{
            t1.interrupt();
        },"t2");
        t2.start();
        //t1.interrupt();
    }
}

1.1.3.1 interrupt()源码分析

在这里插入图片描述
底层调用的是interrupt0() native的方法
在这里插入图片描述

1.1.3.2 isInterrupted源码分析

返回线程是否被中断过,中断的状态是否被重置,取决于当前ClearInterrupted的入参
在这里插入图片描述
在这里插入图片描述

1.2当前线程的中断标识为true,是不是线程就立刻停止

不会的

package com.atguigu.springcloud.util.interrup;

import java.util.concurrent.TimeUnit;

public class InterrupDemo2 {
    public static void main(String[] args) {
        //实例方法interrupt(),仅仅是设置线程的中断状态设置为true,不会停止线程。
        Thread t1  = new Thread(()->{
            for (int i = 0; i < 300; i++) {
                System.out.println("----i="+i);
            }
        },"t1");
        t1.start();
        System.out.println("t1线程默认的中断标志02:"+Thread.currentThread().isInterrupted());//false
        try {TimeUnit.MILLISECONDS.sleep(2);} catch (InterruptedException e) {e.printStackTrace();}
        t1.interrupt();//true
        System.out.println("t1线程调用interrupt()后的中断标志01:"+t1.isInterrupted());//true

        try {TimeUnit.MILLISECONDS.sleep(2000);} catch (InterruptedException e) {e.printStackTrace();}
        System.out.println("t1线程调用interrupt()后的中断标志03:"+t1.isInterrupted());//false:2秒t1线程结束了不活动的线程不会产生任何影响
    }
}

在这里插入图片描述
在这里插入图片描述

package com.atguigu.springcloud.util.interrup;

import java.util.concurrent.TimeUnit;

public class InterrupDemo3 {
    public static void main(String[] args) {
        /**
         * 1 中断标志位,默认false
         * 2 t2--->t1发出了中断协商,t2调用t1.interrupt(),中断标志位true
         * 3 中断标志位true,正常情况,程序停止
         * 4 中断标志位true,异常情况,InterruptedException,将会把中断状态被清除,并且将收到InterruptedException.中断标志位false
         * 导致无线循环
         * 5 在catch块中,需要再次给中断标志位设置为true,2次调用停止程序才ok
         */
        Thread t1 = new Thread(()->{
            while (true){
                if(Thread.currentThread().isInterrupted()){
                    System.out.println(Thread.currentThread().getName()+"线程----isInterrupted()=true,自己退出了");
                    break;
                }
                try {
                    Thread.sleep(200);
                }catch (InterruptedException e) {
                    Thread.currentThread().interrupt();//没有它,程序不会停止,中断不打断
                    e.printStackTrace();
                }
                System.out.println("----hello InterruptDemo3");
            }
        },"t1");
        t1.start();
        try {TimeUnit.SECONDS.sleep(1);}catch (InterruptedException e) {e.printStackTrace();}
        t1.interrupt();
    }

}

中断只是一种协商机制,修改中断标志位而已,不是立刻stop打断

1.3 静态方法Thread.interrupted()的理解

在这里插入图片描述
说明
在这里插入图片描述

package com.atguigu.springcloud.util.interrup;

public class InterrupDemo4 {
    public static void main(String[] args) {
        //测试当前线程是否被中断(检查中断标志),返回一个boolean并清楚中断状态。
        //第二次调用时中断状态已经被清除,将返回一个False.
        System.out.println(Thread.currentThread().getName()+"\t"+Thread.interrupted());//false  main线程的中断状态false
        System.out.println(Thread.currentThread().getName()+"\t"+Thread.interrupted());//false  main线程的中断状态false
        System.out.println("----1");
        Thread.currentThread().interrupt();//中断标志设置为true  main线程的中断状态设置为true
        System.out.println("----2");
        System.out.println(Thread.currentThread().getName()+"\t"+Thread.interrupted());//true 会把当前的中断状态清零并重新设置为false
        System.out.println(Thread.currentThread().getName()+"\t"+Thread.interrupted());//false main线程的中断状态false
    }
}

interrupt:是否需要清理中断标志位传的是true清理
isInterrupted:是否需要清理中断标志位传的是false不清理
在这里插入图片描述
总结
在这里插入图片描述

2 LockSuppor

在这里插入图片描述
在这里插入图片描述

2.1 3种让线程等待和唤醒的方法

2.1.1 方式1:使用Object中的wait()方法让线程等待,使用Object中的notify方法唤醒线程

package com.ge.healthcare.cn.apm.gateway.util;
public class LockSupportDemo {
    static Object objectLock = new Object();
    public static void main(String[] args) {
        new Thread(()->{
            synchronized (objectLock){
                System.out.println(Thread.currentThread().getName()+"  --------come in");
                try {
                    objectLock.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName()+" -----------------被唤醒");
            }
        },"A").start();
        new Thread(()->{
            synchronized (objectLock){
                objectLock.notify();
                System.out.println(Thread.currentThread().getName()+"  ------------通知");
            }
        },"B").start();
    }
}

2.1.1.1 异常情况1

package com.atguigu.springcloud.util;

public class LockSupportDemo {
    static Object objectLock = new Object();
    public static void main(String[] args) {
        new Thread(()->{
//            synchronized (objectLock){
                System.out.println(Thread.currentThread().getName()+"  --------come in");
                try {
                    objectLock.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName()+" -----------------被唤醒");
//            }
        },"A").start();
        new Thread(()->{
//            synchronized (objectLock){
                objectLock.notify();
                System.out.println(Thread.currentThread().getName()+"  ------------通知");
//            }
        },"B").start();
    }
}

如果要使用wait和notify必须将它包在synchronized锁块之间
在这里插入图片描述

2.1.1.2 异常情况2

先notify再wait,程序无法执行,无法唤醒

package com.atguigu.springcloud.util;

import java.util.concurrent.TimeUnit;

public class LockSupportDemo {
    static Object objectLock = new Object();
    public static void main(String[] args) {
        new Thread(()->{
            try {
            TimeUnit.SECONDS.sleep(1);}catch (InterruptedException e) {e.printStackTrace();}
            synchronized (objectLock){
                System.out.println(Thread.currentThread().getName()+"  --------come in");
                try {
                    objectLock.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName()+" -----------------被唤醒");
            }
        },"A").start();

        new Thread(()->{
            synchronized (objectLock){
                objectLock.notify();
                System.out.println(Thread.currentThread().getName()+"  ------------通知");
            }
        },"B").start();
    }
}

总结:wait和notify方法必须要在同步块或者方法里面,且成对出现使用
先wait后notify才行

2.1.2 方式2:使用JUC包中的Condition的await方法让线程等待,使用signal方法唤醒线程

package com.atguigu.springcloud.util;

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class LockSupportDemo {
    static Lock lock = new ReentrantLock();
    static Condition condition = lock.newCondition();
    public static void main(String[] args) {
        new Thread(()->{
            lock.lock();
            try {
                System.out.println(Thread.currentThread().getName()+"----------come in");
                try {
                    condition.await();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName()+"----------被唤醒");
            } finally {
                lock.unlock();
            }
        },"A").start();
        new Thread(()->{
            lock.lock();
            try {
                condition.signal();
                System.out.println(Thread.currentThread().getName()+"----------通知");
            } finally {
                lock.unlock();
            }
        },"B").start();
    }
}

2.1.2.1 异常情况1

注掉lock,unlock
同2.1.1.1

2.1.2.2 异常情况2

先signal后await
同2.1.1.2

总结:Condition中的线程等待和唤醒方法,需要先获取锁
一定要先await后signal,不要反了。

2.1.3 方式3: LockSupport类可以阻塞当前线程以及唤醒指定被阻塞的线程

通过park和unpark(thread)方法来实现阻塞和唤醒线程的操作
LockSupport是用来创建锁和其他同步类的基本线程阻塞原语
LockSupport类使用了一种名为Permit(许可)的概念来做到阻塞和唤醒线程的功能,每个线程都有一个许可(permit),但与Semaphore不同的是,许可的累加上限是1.
0L:如果没有通行证就永远不放行
在这里插入图片描述

在这里插入图片描述

package com.atguigu.springcloud.util;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.LockSupport;
import java.util.concurrent.locks.ReentrantLock;

public class LockSupportDemo {
    static Lock lock = new ReentrantLock();
    public static void main(String[] args) {

        Thread a = new Thread(()->{
            System.out.println(Thread.currentThread().getName()+"--------------come in");
            LockSupport.park();//被阻塞....等待通知放行,它要通过时需要许可证
            System.out.println(Thread.currentThread().getName()+"--------------被唤醒");
        },"a");
        a.start();
        try {
            TimeUnit.SECONDS.sleep(3L);} catch (InterruptedException e) { e.printStackTrace();}

        Thread b = new Thread(()->{
            LockSupport.unpark(a);
            System.out.println(Thread.currentThread().getName()+"--------------通知了");
        },"b");
        b.start();
    }
}

如果b线程先发通知,a线程后被阻塞运行结果:正常
并且无锁块的要求
原因是先执行了unpark(a)导致上面的park方法形同虚设无效。

package com.atguigu.springcloud.util;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.LockSupport;
import java.util.concurrent.locks.ReentrantLock;

public class LockSupportDemo {
    static Lock lock = new ReentrantLock();
    public static void main(String[] args) {

        Thread a = new Thread(()->{
            try {TimeUnit.SECONDS.sleep(3L);} catch (InterruptedException e) { e.printStackTrace();}
            System.out.println(Thread.currentThread().getName()+"--------------come in");
            LockSupport.park();//被阻塞....等待通知放行,它要通过时需要许可证
            System.out.println(Thread.currentThread().getName()+"--------------被唤醒");
        },"a");
        a.start();
        Thread b = new Thread(()->{
            LockSupport.unpark(a);
            System.out.println(Thread.currentThread().getName()+"--------------通知了");
        },"b");
        b.start();
    }
}

2.1.3.1 问题多个park和unpark会阻塞么:会

因为许可证不会累计,不要出现多对多

package com.atguigu.springcloud.util;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.LockSupport;
import java.util.concurrent.locks.ReentrantLock;

public class LockSupportDemo {
    static Lock lock = new ReentrantLock();
    public static void main(String[] args) {

        Thread a = new Thread(()->{
            try {TimeUnit.SECONDS.sleep(3L);} catch (InterruptedException e) { e.printStackTrace();}
            System.out.println(Thread.currentThread().getName()+"--------------come in");
            LockSupport.park();//被阻塞....等待通知放行,它要通过时需要许可证
            LockSupport.park();//被阻塞....等待通知放行,它要通过时需要许可证
            System.out.println(Thread.currentThread().getName()+"--------------被唤醒");
        },"a");
        a.start();
        Thread b = new Thread(()->{
            LockSupport.unpark(a);
            LockSupport.unpark(a);
            System.out.println(Thread.currentThread().getName()+"--------------通知了");
        },"b");
        b.start();
    }
}

2.1.3.2 总结

在这里插入图片描述
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/953647.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

智慧工地源码带开发手册文档 app 数据大屏、硬件对接、萤石云

智慧工地解决方案依托计算机技术、物联网、云计算、大数据、人工智能、VR、AR等技术相结合&#xff0c;为工程项目管理提供先进技术手段&#xff0c;构建工地现场智能监控和控制体系&#xff0c;弥补传统方法在监管中的缺陷&#xff0c;最终实现项目对人、机、料、法、环的全方…

Verilog基础:延时模型

相关阅读 Verilog基础专栏https://blog.csdn.net/weixin_45791458/category_12263729.html?spm1001.2014.3001.5482 目录 1、连续赋值延时 1.1、赋值内嵌延时 1.2、线网声明延时 1.3、门延迟 2、过程赋值延时 2.1、过程语句前置时序控制 2.2、过程赋值语句内嵌时序控制…

记录--解决前端内存泄漏:问题概览与实用解决方案

这里给大家分享我在网上总结出来的一些知识&#xff0c;希望对大家有所帮助 内存泄漏是前端开发中的一个常见问题&#xff0c;可能导致项目变得缓慢、不稳定甚至崩溃。在本文中&#xff0c;我们将深入探讨在JavaScript、Vue和React项目中可能导致内存泄漏的情况&#xff0c;并提…

现代C++中的从头开始深度学习:【6/8】成本函数

现代C中的从头开始深度学习&#xff1a;成本函数 一、说明 在机器学习中&#xff0c;我们通常将问题建模为函数。因此&#xff0c;我们的大部分工作都包括寻找使用已知模型近似函数的方法。在这种情况下&#xff0c;成本函数起着核心作用。 这个故事是我们之前关于卷积的讨论的…

【python爬虫】7.爬到的数据存到哪里?

文章目录 前言存储数据的方式存储数据的基础知识基础知识&#xff1a;Excel写入与读取基础知识&#xff1a;csv写入与读取项目&#xff1a;存储周杰伦的歌曲信息 复习 前言 上一关我们以QQ音乐为例&#xff0c;主要学习了如何带参数地请求数据&#xff08;get请求&#xff09;…

软件测试/测试开发丨Pytest和Allure报告 学习笔记

点此获取更多相关资料 本文为霍格沃兹测试开发学社学员学习笔记分享 原文链接&#xff1a;https://ceshiren.com/t/topic/26755 Pytest 命名规则 类型规则文件test_开头 或者 _test 结尾类Test 开头方法/函数test_开头注意&#xff1a;测试类中不可以添加__init__构造函数 注…

IP基本原理(上)

文章目录 一、IP的定义二、IP的作用1.标识节点和链路2.寻址和转发3.适应各种数据链路 三、IP头部封装格式四、MTU五、IP地址1.定义2.格式2.1 点分十进制和二进制关系与转换2.2 由网络位主机位组成2.3 网络位长度决定网段 3.分类3.1 A类3.2 B类3.3 C类3.4 D类3.5 E类 4.特殊地址…

Linux虚拟机磁盘扩容

Linux虚拟机磁盘扩容 问题起源 在使用linux系统开发时遇到文件无法创建的问题&#xff0c;根据提示发现是磁盘空间不足。 使用df -h查看具体磁盘使用情况。 针对这个问题&#xff0c;有两种解决方案&#xff1a; 使用du -sh ./*可以查看当前工作目录下各文件的占用空间大小…

【USRP】Ettus USRP X440 (USRP软件无线电设备)

Ettus USRP X440 30 MHz至4 GHz&#xff0c;1.6 GHz 带宽&#xff0c;基于GPS的OCXO&#xff0c;USRP软件无线电设备 - Ettus USRP X440是一款USRP软件无线电(SDR)设备&#xff0c;可帮助您集成硬件和软件&#xff0c;对高性能、多通道、宽带信号生成和分析系统进行原型验证。…

InnoDB的Buffer

一、Buffer内存结构 MySQL 服务器启动的时候就向操作系统申请了一片连续的内存&#xff0c;默认128M&#xff0c;可通过从参数修改。 [server] innodb_buffer_pool_size 268435456 1.1 控制块 控制块包括该页所属的 表空间编号、页号、缓存页在 Buffer Pool 中的地址、链表…

14:00面试,14:06就出来了,问的问题有点变态

从小厂出来&#xff0c;没想到在另一家公司又寄了。 到这家公司开始上班&#xff0c;加班是每天必不可少的&#xff0c;看在钱给的比较多的份上&#xff0c;就不太计较了。没想到8月一纸通知&#xff0c;所有人不准加班&#xff0c;加班费不仅没有了&#xff0c;薪资还要降40%,…

vue three.js基本案例解析

1.安装依赖 // 比如安装148版本 npm install three0.148.0 --save2.使用页面引用 import * as THREE from three; // 引入扩展库OrbitControls.js import { OrbitControls } from three/addons/controls/OrbitControls.js; // 引入扩展库GLTFLoader.js import { GLTFLoader }…

盘点那些国际知名黑客(上篇)

电影中的黑客仅靠一部电脑就可以窃取别人的信息&#xff0c;利用自己高超的技术让公司甚至国家都胆战心惊。“黑客”原指热心于计算机技术、水平高超的电脑高手&#xff0c;但逐渐区分为黑帽、白帽、灰帽。这些术语源自美国流行文化的老式西部电影&#xff0c;其中主角戴白色或…

企业怎么优化固定资产管理

在优化固定资产管理的过程中&#xff0c;不仅要关注硬件设备和设施的维护&#xff0c;还要重视软件系统和数据管理。一些可能的方法&#xff1a;  需要建立一套完整的资产管理系统。这个系统应该包括资产的采购、登记、使用、维修、报废等各个环节的管理流程。通过这个系统&a…

带你吃透Reactor并发模型

目录 1.概述2.项目介绍2.1 有那些并发模型2.2 能锻炼那些技能2.3目录结构 3.编码实践3.1 前期准备3.1.1 Echo协议3.1.2公共代码抽象3.1.3基准性能压测工具 3.2 并发示例3.2.1 EpollReactorSingleProcess3.2.2 EpollReactorProcessPool3.2.3 EpollReactorThreadPool3.2.4 EpollR…

MongoDb-01——Mac上安装MongoDb以及相关的简单命令

MongoDb-01——Mac上安装MongoDb以及相关的简单命令 1. 下载、安装1.1 官网下载1.2 关于安装MongoDB1.2.1 官方安装文档1.2.2 Mac安装详细步骤&#xff08;使用brew&#xff09; 2. 启动MongoDB2.1 官方说明2.2 作为macOS服务运行的相关命令2.3 访问 3. 链接并使用mongodb3.1 链…

人工智能与软件开发的未来

人工智能正在从各个方面改变软件开发。尽管许多公司竞相推出人工智能功能&#xff0c;但人工智能的潜力已超出了功能层面&#xff0c;成为大多数SaaS解决方案的基础。当机器学习和人工智能模型应用在SaaS技术后&#xff0c;便能提高各种业务流程的效率。人工智能应被视为新的开…

解决报错“No module named ‘pandas.core.indexes‘”

解决办法&#xff1a; 首先使用看一下你的pandas是不是版本太新了&#xff0c;如果使用2.0.0以上的版本&#xff0c;则会出现这个报错。 可以安装1.x.x的版本。 pip install pandas1.5.3

在Bigemap中怎么添加高清地图呢?

会使用到的工具 bigemap gis office&#xff0c;下载链接&#xff1a;BIGEMAP GIS Office-全能版 打开软件&#xff0c;要提示需要授权和添加地图&#xff0c;然后去点击选择地图这个按钮&#xff0c;列表中有个添加按钮点进去选择添加地图的方式。 第一种方式&#xff1a;通…

多轮面试中的策略和技巧:如何稳步晋级

&#x1f337;&#x1f341; 博主猫头虎 带您 Go to New World.✨&#x1f341; &#x1f984; 博客首页——猫头虎的博客&#x1f390; &#x1f433;《面试题大全专栏》 文章图文并茂&#x1f995;生动形象&#x1f996;简单易学&#xff01;欢迎大家来踩踩~&#x1f33a; &a…