做ppt的网站叫什么名字/松松软文平台
一、保护性暂停
1.1 定义
即Guarded Suspension,用在一个线程等待另一 个线程的执行结果
要点
● 有一个结果需要从一个线程传递到另一 个线程,让他们关联同一一个GuardedObject
● 如果有结果不断从一个线程到另一个线程那么可以使用消息队列(生产者/消费者)
● JDK中,join的实现、Future的实现,采用的就是此模式
● 因为要等待另一方的结果, 因此归类到同步模式
1.2 实现
GuardedObject(保护对象),其response属性用来保存最终的结果(t1使用结果,t2产生结果),初始值为null(wait-notify在GuardedObject上等待结果)
模拟应用场景:线程1需要等待线程2产生的结果,线程2进行一个下载任务
import cn.itcast.pattern.Downloader;
import lombok.extern.slf4j.Slf4j;
import java.io.IOException;
import java.util.List;@Slf4j(topic = "c.Test")
public class Test {public static void main(String[] args) throws InterruptedException {GuardedObject guardedObject = new GuardedObject();new Thread(() -> {// 等待结果log.debug("等待结果");List<String> list = guardedObject.get();log.debug("结果的大小:{}", list.size());}, "t1").start();new Thread(() -> {log.debug("执行下载");try {List<String> list = Downloader.download();// 将下载结果传给线程1guardedObject.complete(list);} catch (IOException e) {e.printStackTrace();}});}
}class uardedObject {// 结果private Object response;// 获取结果的方法public Object get() {synchronized (this) {// 还没有结果while (response == null) {// 调用wait等待try {this.wait();} catch (InterruptedException e) {e.printStackTrace();}}return response;}}// 产生结果public void complete(Object response) {synchronized (this) {// 给结果成员变量赋值this.response = response;// 通知等待线程this.notifyAll();}}
}
运行结果:
1.3 保护性暂停扩展—增加超时
二、 两阶段终止-interrupt
Two Phase Termination
在一个线程T1中如何“优雅”终止线程T2?这里的【优雅】指的是给T2一个料理后事的机会。
错误思路
● 使用线程对象的stop()方法停止线程(强制杀死)
—— stop()方法会真正杀死线程,如果这时线程锁住了共享资源,那么当它被杀死后就再也没有机会释放锁,其它线程将永远无法获取锁
● 使用System.exit(int)方法停止线程
—— 目的仅是停止一个线程,但这种做法会让整个程序都停止
2.1 两阶段终止-interrupt分析
有如下场景,做一个系统的健康状态监控(记录电脑CPU的使用率、内存的使用率)实现定时监控。实现这样一个场景,可用一个后台的监控线程不断记录。
代码实现:
import lombok.extern.slf4j.Slf4j;@Slf4j(topic = "c.Test")
public class Test {public static void main(String[] args) throws InterruptedException {TwoPhaseTermination tpt=new TwoPhaseTermination();// 启动监控线程(每隔1秒执行监控记录)tpt.start();// 模拟非正常打断,主线程经过3.5后,被interrupt()===>优雅打断Thread.sleep(3500);tpt.stop();}
}
// 监控类代码
@Slf4j(topic = "c.TwoPhaseTermination")
class TwoPhaseTermination{// 创建监控线程private Thread monitor;// 启动监控线程public void start(){// 创建线程对象monitor=new Thread(()->{// 不断被执行监控while (true){// 获取当前线程对象,判断是否被打断Thread current = Thread.currentThread();if(current.isInterrupted()){// 若被打断log.debug("料理后事");break;}// 若未被打断(每隔2s执行睡眠,进行监控操作)try {Thread.sleep(1000); // 情况1===>非正常打断(睡眠过程中)log.debug("执行监控记录"); // 情况2===>正常打断} catch (InterruptedException e) {e.printStackTrace();// 重新设置打断标记(sleep()被打断后会清除打断标记)current.interrupt();}}});monitor.start();}// 停止监控线程public void stop(){// "优雅"打断monitor.interrupt();}
}
运行结果:
分析:监控线程每隔1s监控系统,主线程处于休眠状态,3.5秒后休眠状态被打断
*****interrupted()与isInterrupted()均为判断当前线程是否被打断,表面上看起来类似。但却有着很大的区别,调用isInterrupted()不会清除打断标记,而调用interrupted()判断完后会将打断标记清除
三、固定运行顺序
同步模式之顺序控制
比如,先打印2后打印1(如果不加控制两个线程被CPU调度的时间不受控制)
3.1 wait notify版
import lombok.extern.slf4j.Slf4j;@Slf4j(topic = "c.Test25")
public class Test25 {// 锁对象static final Object lock = new Object();// 表示 t2 是否运行过static boolean t2runned = false;public static void main(String[] args) {// 打印1的线程(线程1期待线程2打印过后将标记置为真后再打印)Thread t1 = new Thread(() -> {synchronized (lock) {while (!t2runned) {try {lock.wait();} catch (InterruptedException e) {e.printStackTrace();}}log.debug("1");}}, "t1");// 打印2的线程Thread t2 = new Thread(() -> {synchronized (lock) {log.debug("2");t2runned = true;lock.notify();}}, "t2");t1.start();t2.start();}
}
运行结果:
3.2 park unpack版
import lombok.extern.slf4j.Slf4j;
import java.util.concurrent.locks.LockSupport;@Slf4j(topic = "c.Test26")
public class Test26 {public static void main(String[] args) {Thread t1 = new Thread(() -> {LockSupport.park();log.debug("1");}, "t1");t1.start();new Thread(() -> {log.debug("2");LockSupport.unpark(t1);},"t2").start();}
}
运行结果:
3.3 ReentrantLock——await&signal
import lombok.extern.slf4j.Slf4j;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;@Slf4j(topic = "c.Test24")
public class Test24 {static final Object room = new Object();static boolean flag = false;static ReentrantLock ROOM = new ReentrantLock();// 创建一个新的条件变量(休息室)static Condition waitSet = ROOM.newCondition();public static void main(String[] args) throws InterruptedException {// 打印“1”的线程Thread t1 = new Thread(() -> {ROOM.lock();try {log.debug("2是否打印完毕[{}]", flag);while (!flag) {log.debug("未打印2,先歇会!");try {waitSet.await();} catch (InterruptedException e) {e.printStackTrace();}}log.debug("1");} finally {// 解锁ROOM.unlock();}});// 打印“2”的线程Thread t2=new Thread(()->{ROOM.lock();try {log.debug("2");flag=true;// 唤醒线程waitSet.signal();}finally {ROOM.unlock();}});t1.start();t2.start();}
}
四、交替输出
线程1输出a 5次,线程2输出b 5次,线程3输出c 5次。现在要求输出abcabcabcabcabc怎么实现
4.1 wait notify版
import lombok.extern.slf4j.Slf4j;@Slf4j(topic = "c.Test")
public class Test {public static void main(String[] args) {Wait_notify wait_notify = new Wait_notify(1,5);// 线程t1打印anew Thread(() -> {wait_notify.print("a",1,2);}, "t1").start();// 线程t1打印bnew Thread(() -> {wait_notify.print("b",2,3);}, "t2").start();// 线程t3打印cnew Thread(() -> {wait_notify.print("c",3,1);}, "t3").start();}
}/*输出内容 等待标记 下一个标记a 1 2b 2 3c 3 1*/
class Wait_notify {// 等待标记【存在3个线程,因此用blooen变量不太合适(blooen变量的状态只有两个)】private int flag; // 1: t1 2: t2 3: t3// 循环次数private int loopnumber;public Wait_notify(int flag, int loopnumber) {this.flag = flag;this.loopnumber = loopnumber;}// 打印方法(打印内容,打印标记)public void print(String s, int wait, int nextFlag) {for (int i = 0; i < loopnumber; i++) {synchronized (this) {while (flag != wait) {// 进入等待try {this.wait();} catch (InterruptedException e) {e.printStackTrace();}}System.out.print(s);flag = nextFlag;// 唤醒其他等待的线程this.notifyAll();}}}
}
运行结果:
4.2 ReentrantLock——await&signal
import lombok.extern.slf4j.Slf4j;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;@Slf4j(topic = "c.Test")
public class Test {public static void main(String[] args) throws InterruptedException {Awaitsynch awaitsynch = new Awaitsynch(5);// 线程1的休息室Condition a = awaitsynch.newCondition();// 线程2的休息室Condition b = awaitsynch.newCondition();// 线程3的休息室Condition c = awaitsynch.newCondition();new Thread(() -> {awaitsynch.print("a", a, b);}).start();new Thread(() -> {awaitsynch.print("b", b, c);}).start();new Thread(() -> {awaitsynch.print("c", c, a);}).start();// 三个线程刚开始都会进入各自休息室进行休息(利用主线程先将a休息室中的线程唤醒)Thread.sleep(1000);awaitsynch.lock();try {System.out.println("开始......");// 唤醒a休息室中的线程a.signal();} finally {awaitsynch.unlock();}}
}
class Awaitsynch extends ReentrantLock {// 循环次数private int loopnumber;public Awaitsynch(int loopnumber) {this.loopnumber = loopnumber;}// (打印内容,进入的休息室,下一个休息室)public void print(String s, Condition con, Condition next) {for (int i = 0; i < loopnumber; i++) {// 给当前线程加锁lock();try {con.await();System.out.print(s);// 唤醒下一个休息室中的线程next.signal();} catch (InterruptedException e) {e.printStackTrace();} finally {unlock();}}}
}
运行结果:
4.3 park unpack版
import lombok.extern.slf4j.Slf4j;
import java.util.concurrent.locks.LockSupport;@Slf4j(topic = "c.Test24")
public class Test24 {static Thread a;static Thread b;static Thread c;public static void main(String[] args) throws InterruptedException {ParkUnpark parkUnpark = new ParkUnpark(5);a=new Thread(() -> {parkUnpark.print("a", b);});b=new Thread(() -> {parkUnpark.print("b", c);});c=new Thread(() -> {parkUnpark.print("c", a);});a.start();b.start();c.start();// 主线程唤醒当前暂停的线程LockSupport.unpark(a);}
}
class parkUpark {// 循坏次数private int loopNumber;public parkUpark(int loopNumber) {this.loopNumber = loopNumber;}// print(打印的内容,要唤醒的线程)public void print(String s, Thread next) {for (int i = 0; i < loopNumber; i++) {// 暂停当前线程(阻塞)LockSupport.park();System.out.println(s);// 唤醒下一个线程LockSupport.unpark(next);}}
}
相关文章:

JUC并发编程设计模式
一、保护性暂停 1.1 定义 即Guarded Suspension,用在一个线程等待另一 个线程的执行结果 要点 ● 有一个结果需要从一个线程传递到另一 个线程,让他们关联同一一个GuardedObject ● 如果有结果不断从一个线程到另一个线程那么可以使用消息队列(生产者…...

HTTPS加密解析
日升时奋斗,日落时自省 目录 1、加密解释 2、对称加密 3、非对称加密 4、证书 HTTPS(HyperText Transfer Protocol over Secure Socket Layer)也是一个应用层协议,是在HTTP协议的基础上引入了一个加密层 HTTP协议内容都是按…...

Python每日一练(20230309)
目录 1. 删除有序数组中的重复项 ★ 2. 二叉树的最小深度 ★★ 3. 只出现一次的数字 II ★★ 🌟 每日一练刷题专栏 C/C 每日一练 专栏 Python 每日一练 专栏 1. 删除有序数组中的重复项 给你一个有序数组 nums ,请你原地删除重复出现的元素…...

哈希表题目:数组的度
文章目录题目标题和出处难度题目描述要求示例数据范围解法思路和算法代码复杂度分析题目 标题和出处 标题:数组的度 出处:697. 数组的度 难度 4 级 题目描述 要求 给定一个非空且只包含非负数的整数数组 nums\texttt{nums}nums,数组的…...

初识rollup 打包、配置vue脚手架
rollup javascript 代码打包器,它使用了 es6 新标准代码模块格式。 特点: 面向未来,拥抱 es 新标准,支持标准化模块导入、导出等新语法。tree shaking 静态分析导入的代码。排除未实际引用的内容兼容现有的 commonJS 模块&#…...

软考网络工程师证书有用吗?
当然有用,但是拿到网络工程师证书的前提是对你自己今后的职业发展有帮助,用得到才能对你而言发挥它最大的好处。软考证书的具体用处:1.纳入我国高校人才培养和教学体系目前,软考已经被纳入高校人才培养和教学体系。在很多高校中&a…...

postgresql 自动备份 bat实现
postgres数据据备分,用cmd命令有些烦,写了个bat实现 BAT脚本中常用的注释命令有rem、@rem和:: rem、@rem和::用法都很简单,直接在命令后加上要注释的语句即可。例如下图,语言前加了rem,运行BAT时就会自动忽略这个句子。需要注释多行时,每行前面都要加上rem、@rem和::。…...

gdb:在命令行中会莫名暂停;detach-on-fork
这个没有捕获到断点的原因是,可能是多线程的问题,需要设置: set detach-on-fork off On Linux, if you want to debug both the parent and child processes, use the command: set detach-on-fork on/off on 默认设置,gdb会放弃子线程(或者父线程,受follow-fork-mode的…...

【3.9】RedisAOF日志、字符串、操作系统进程管理
4. 进程管理 进程、线程基础知识 什么是进程 我们编写的代码只是一个存储在硬盘的静态文件,通过编译后就会生成二进制可执行文件,当我们运行这个可执行文件后,它会被装载到内存中,接着 CPU 会执行程序中的每一条指令,…...

安装mayavi的成功步骤
这篇文章是python 3.6版本,windows系统下的安装,其他python版本应该也可以,下载对应的包即可。 一定不要直接pip install mayavi,这个玩意儿对vtk的版本有要求。 下载whl包 搞了很久不行,咱也别费那个劲了࿰…...

vue+echarts.js 实现中国地图——根据数值表示省份的深浅——技能提升
最近在写后台管理系统,遇到一个需求就是 中国地图根据数值 展示深浅颜色。 效果图如下: 直接上代码: 1.html部分 <div id"Map"></div>2.css部分——一定要设置尺寸 #Map {width: 100%;height: 400px; }3.js部分 …...

[oeasy]python0104_指示灯_显示_LED_辉光管_霓虹灯
编码进化 回忆上次内容 x86、arm、riscv等基础架构 都是二进制的包括各种数据、指令 但是我们接触到的东西 都是屏幕显示出来的字符 计算机 显示出来的 一个个具体的字型 计算机中用来展示的字型 究竟是 如何进化的 呢?🤔🤔 模拟电路时…...

Easy Deep Learning——卷积层
为什么需要卷积层,深度学习中的卷积是什么? 在介绍卷积之前,先引入一个场景 假设您在草地上漫步,手里拿着一个尺子,想要测量草地上某些物体的大小,比如一片叶子。但是叶子的形状各异,并且草地非…...

深入分析@Bean源码
文章目录一、源码时序图二、源码解析1. 运行案例程序启动类2. 解析AnnotationConfigApplicationContext类的AnnotationConfigApplicationContext(Class<?>... componentClasses)构造方法3. 解析AbstractApplicationContext类的refresh()方法4. 解析AbstractApplicationC…...

Web Components学习(1)
一、什么是web components 开发项目的时候为什么不手写原生 JS,而是要用现如今非常流行的前端框架,原因有很多,例如: 良好的生态数据驱动试图模块化组件化等 Web Components 就是为了解决“组件化”而诞生的,它是浏…...

Element-UI实现复杂table表格结构
Element-UI组件el-table用于展示多条结构类似的数据,可对数据进行排序、筛选、对比或其他自定义操作。将使用到以下两项,来完成今天demo演示:多级表头:数据结构比较复杂的时候,可使用多级表头来展现数据的层次关系。合…...

Azure AD 与 AWS 单一帐户SSO访问集成,超详细讲解,包括解决可能出现的错误问题
本教程介绍如何将 AWS Single-Account Access 与 Azure Active Directory (Azure AD) 相集成。 将 AWS Single-Account Access 与 Azure AD 集成后,可以: 在 Azure AD 中控制谁有权访问 AWS Single-Account Access。让用户使用其 Azure AD 帐户自动登录…...

lvgl 笔记 按钮部件 (lv_btn) 和 开关部件 (lv_switch)
按钮基础使用方法: lv_btn 和 lb_obj 使用方法一样,只是外表并不相同,基础创建方法只需一行代码。 lv_obj_t* btn lv_btn_create(lv_scr_act()); 添加大小和位置: lv_obj_t* btn lv_btn_create(lv_scr_act()); lv_obj_set_s…...

Python高频面试题——生成器(最通俗的讲解)
生成器定义在 Python 中,使用了 yield 的函数被称为生成器(generator)。跟普通函数不同的是,生成器是一个返回迭代器的函数,只能用于迭代操作,更简单点理解生成器就是一个迭代器。 在调用生成器运行的过程中…...

品牌软文怎么写?教你几招
软文是什么?软文的本质就是广告,当然不是明晃晃的推销,而是自然隐晦地植入产品信息,引导更多用户自愿下单。 品牌软文对于写手的经验、内容的质量要求都相对较高,否则写出来的软文无法达到预期的效果。品牌软文怎么写…...

Kubernetes (k8s) 污点(Taint)介绍、示例
Kubernetes (k8s) 污点(Taint) 是一种机制,用于标记一个节点(Node)不可被调度的状态。它可以将一个污点标记添加到节点上,以防止 Pod 被调度到该节点上。污点可以用于实现各种策略,例如分离故障…...

Docker学习(二十一)构建 java 项目基础镜像
目录1.下载 JDK 包2.编写 Dockerfile3.构建镜像4.创建容器测试1.下载 JDK 包 JDK各版本官网下载地址: https://www.oracle.com/java/technologies/downloads/archive/#JavaSE 这里我们以 JDK 8u351 为例,点击 Java SE (8U211 and later)。 点击下载 jd…...

python中的上下文原理
目录with语句上下文管理器原理自定义上下文管理器contextmanager 装饰器with语句 在我们日常使用场景中,经常会操作一些资源,比如文件对象、数据库连接、Socket连接等,资源操作完了之后,不管操作的成功与否,最重要的事…...

可复用测试用例描述要素
测试用例的输入、操作、预期结果和评估标准、前提条件是测试用例不可少的要素,但对于可复用测试用例而言,这是不够的。本文在文献规定的测试用例要素基础上,增加了新的内容。从而从多个角度完整地对可复用测试用例进行了描述,为可…...

lnmp中遇到open_basedir配置无效问题
在使用LNMP包安装PHP时,发现直接修改php.ini的配置是无法生效的,其原因竟然是因为nginx的配置文件,覆盖了php.ini的配置。 解决: 1、找到nginx的open_basedir配置文件:(下面是我的文件地址) …...

SpringBoot【知识加油站】---- REST开发
SpringBoot【知识加油站】---- REST开发1. REST 简介2. REST 风格3. RESTful 入门案例1. REST 简介 REST:Representaional State Transfer,表现形式状态转换 传统风格资源描述形式 http://localhost/user/getById?id1 http://localhost/user/saveUser…...

三 Go的语言容器
1. 数组 数组是一个由固定长度的特定类型元素组成的序列,一个数组可以由零个或多个元素组成。因为数组的长度是固定的,所以在Go语言中很少直接使用数组 声明语法: var 数组变量名 [元素数量]Typepackage main import ("fmt" ) fu…...

2023年全国最新会计专业技术资格精选真题及答案16
百分百题库提供会计专业技术资格考试试题、会计考试预测题、会计专业技术资格考试真题、会计证考试题库等,提供在线做题刷题,在线模拟考试,助你考试轻松过关。 一、单选题 1.下列各项关于会计监督职能的表述中,正确的是ÿ…...

模板进阶(仿函数,特化等介绍)
非类型模板参数 模板参数有类型形参和非类型形参; 类型形参:使用typename或者class修饰的参数类型名称 非类型形参:一个普通常量作为模板参数形参,不能为浮点数,字符类型以及类对象; #include<iostrea…...

Beats:在 Docker 中同时部署 Metricbeat 和 Elasticsearch
在本教程中,我们将部署一个 metricbeat 来监控正在运行的容器的健康状况和系统指标。 为什么需要监控,为什么需要 Metricbeat? 一个常见的问题,但很少有人回答。 首先,无论我们部署的是 docker 容器还是老式的金属箱&…...