漫画:并发系列 之 H2O的生成
今天为大家分享一道看起来“高大上”的题目。
话不多说,直接看题。
01
水分子的产生
水分子的产生:现在有两种线程,氢 oxygen 和氧 hydrogen,你的目标是组织这两种线程来产生水分子。
存在一个屏障(barrier)使得每个线程必须等候直到一个完整水分子能够被产生出来。
氢和氧线程会被分别给予 releaseHydrogen 和 releaseOxygen 方法来允许它们突破屏障。
这些线程应该三三成组突破屏障并能立即组合产生一个水分子。
你必须保证产生一个水分子所需线程的结合必须发生在下一个水分子产生之前。
换句话说:
如果一个氧线程到达屏障时没有氢线程到达,它必须等候直到两个氢线程到达。
如果一个氢线程到达屏障时没有其它线程到达,它必须等候直到一个氧线程和另一个氢线程到达。
书写满足这些限制条件的氢、氧线程同步代码。
示例 1:
输入: "HOH"
输出: "HHO"
解释: "HOH" 和 "OHH" 依然都是有效解。
示例 2:
输入: "OOHHHH"
输出: "HHOHHO"
解释: "HOHHHO", "OHHHHO", "HHOHOH", "HOHHOH", "OHHHOH", "HHOOHH", "HOHOHH" 和 "OHHOHH" 依然都是有效解。
限制条件:
输入字符串的总长将会是 3n, 1 ≤ n ≤ 50;
输入字符串中的 “H” 总数将会是 2n;
输入字符串中的 “O” 总数将会是 n。
代码模板:
1class H2O {2 public H2O() {34 }5 public void hydrogen(Runnable releaseHydrogen) throws InterruptedException {6 // releaseHydrogen.run() outputs "H". Do not change or remove this line.7 releaseHydrogen.run();8 }9 public void oxygen(Runnable releaseOxygen) throws InterruptedException {
10 // releaseOxygen.run() outputs "O". Do not change or remove this line.
11 releaseOxygen.run();
12 }
13}
(水分子的产生)
02
JAVA分析
乍看之下,题目貌似很高大上,不少同学一听多线程直接就慌了神。我们一起分析一下。一个氧消耗两个氢,两个氢供给一个氧。我们只要可以模拟氢和氧的供给关系,就可以顺利进行求解。
这里先介绍一下Java中的Semaphore:Semaphore是 synchronized 的加强版,作用是控制线程的并发数量。可以通过 acquire 和 release 来进行类似 lock 和 unlock 的操作。
1//请求一个信号量,这时候信号量个数-1,当减少到0的时候,下一次acquire不会再执行,只有当执行一个release()的时候,信号量不为0的时候才可以继续执行acquire
2void acquire()
3//释放一个信号量,这时候信号量个数+1,
4void release();
什么?听不懂!大白话就是叫做 Semaphore 的这个东东,可以控制同时有多少线程可以进去,比一般的锁要稍微高级那么一点点。
由于题目中给的限制条件,已经明确说明了H是2n,O是n,所以我们不需要考虑无法构成水分子的情况。
我们分别定义H和O的信号量,都初始化为2个信号量。
在每一次产生O的过程中,都需要等待产生了两个H。
1import java.util.concurrent.Semaphore;23class H2O {45 public H2O() {67 }89 private Semaphore h = new Semaphore(2);
10 private Semaphore o = new Semaphore(2);
11
12 public void hydrogen(Runnable releaseHydrogen) throws InterruptedException {
13 h.acquire(1);
14 releaseHydrogen.run();
15 o.release(1);
16 }
17
18 public void oxygen(Runnable releaseOxygen) throws InterruptedException {
19 o.acquire(2);
20 releaseOxygen.run();
21 h.release(2);
22 }
23}
03
C++代码分析
如果没有原生的信号量支持怎么办?其实也是一样的。我们可以通过锁来模拟信号量。这里加一个C++版本的实现。
1class H2O {2private:3 int countOxygen;4 pthread_mutex_t lockHy;5 pthread_mutex_t lockOx;6public:7 H2O() {8 pthread_mutex_init(&lockOx,NULL);9 pthread_mutex_init(&lockHy,NULL);
10 pthread_mutex_lock(&lockOx);
11 countOxygen = 2;
12 }
13 void hydrogen(function<void()> releaseHydrogen) {
14 pthread_mutex_lock(&lockHy);
15 releaseHydrogen();
16 countOxygen--;
17 if(countOxygen > 0){
18 pthread_mutex_unlock(&lockHy);
19 }else{
20 pthread_mutex_unlock(&lockOx);
21 }
22 }
23 void oxygen(function<void()> releaseOxygen) {
24 pthread_mutex_lock(&lockOx);
25 releaseOxygen();
26 countOxygen = 2;
27 pthread_mutex_unlock(&lockHy);
28 }
29};
03
PYTHON怎么办
好吧,其他语言都有并发。但是我PY竟然连并发都没有(杠精勿扰,我知道有 threading 库可以用。并且里边也已经提供了现成的信号量可以用)这种情况下怎么办?
还是可以解决,我们可以用队列模拟进行实现。
1class H2O:2 def __init__(self):3 self.h, self.o = [], []45 def hydrogen(self, releaseHydrogen: 'Callable[[], None]') -> None:6 self.h.append(releaseHydrogen)7 self.res()89 def oxygen(self, releaseOxygen: 'Callable[[], None]') -> None:
10 self.o.append(releaseOxygen)
11 self.res()
12
13 def res(self):
14 if len(self.h) > 1 and len(self.o) > 0:
15 self.h.pop(0)()
16 self.h.pop(0)()
17 self.o.pop(0)()
04
为啥没有GO语言的版本
已经提供了PY,JAVA,C++的版本。对于GO而言,不管你是通过channel来模拟信号量的方式,还是参照PY的方式进行实现,我觉得应该都可以完成。所以就偷个懒....
注:本系列所有教程中都不会用到复杂的语言特性,大家不需要担心没有学过相关语法。算法思想最重要,使用各语言纯属本人爱好。同时,所有代码均在leetcode上进行过测试运行,保证其严谨性!
今天的题目和并发有关,大家有什么感触呢?
评论区留下你的想法吧!
每天一道图解算法,如需进群 ↓↓↓
欢迎加微信:llhaohao
转发是对我最大的支持!
温馨提示
小浩算法~
每天一起学习图解漫画算法。
一起刷题,一起成长!
~长按下方二维码进行关注吧~
漫画:并发系列 之 H2O的生成相关推荐
- asp按时间自动递增编号_Java秒杀系统实战系列-分布式唯一ID生成订单编号
本文是"Java秒杀系统实战系列文章"的第七篇,在本文中我们将重点介绍 "在高并发,如秒杀的业务场景下如何生成全局唯一.趋势递增的订单编号",我们将介绍两种方法 ...
- 5W字高质量java并发系列详解教程(上)-附PDF下载
文章目录 第一章 java.util.concurrent简介 主要的组件 Executor ExecutorService ScheduledExecutorService Future Count ...
- Java秒杀系统实战系列~分布式唯一ID生成订单编号
摘要: 本篇博文是"Java秒杀系统实战系列文章"的第七篇,在本博文中我们将重点介绍 "在高并发,如秒杀的业务场景下如何生成全局唯一.趋势递增的订单编号",我们 ...
- java 唯一编号_Java秒杀系统实战系列~分布式唯一ID生成订单编号
摘要: 本篇博文是"Java秒杀系统实战系列文章"的第七篇,在本博文中我们将重点介绍 "在高并发,如秒杀的业务场景下如何生成全局唯一.趋势递增的订单编号",我们 ...
- php 8位md5重复概率,高并发 php uniqid 用md5生成不重复唯一标识符方案
高并发 php uniqid 用md5生成不重复唯一标识符方案 uniqid() 函数基于以微秒计的当前时间,生成一个唯一的 ID. uniqid(prefix,more_entropy) prefi ...
- httpd开启status模块_Nginx高并发系列之二——Nginx开启ssl模块
在上一期中我们安装配置了nginx1.13.7版本并且成功启动,那么这一期就针对安装的Nginx支持ssl模块--即开启https功能.如果还有不知道如何安装与配置的请移至: 水番丘山:Nginx高并 ...
- 并发系列1:并发基础知识
本文是Java并发系列的开篇,主要讲一些并发的计算机基础知识.本系列所讲的知识框架也是基于<Java并发编程的艺术>一书,所讲的内容也多围绕于并发concurrent包下的类. 正文 并发 ...
- shell 获取命令执行结果_java高并发系列 第31天:获取线程执行结果,这6种方法你都知道?...
这是java高并发系列第31篇. 环境:jdk1.8. java高并发系列已经学了不少东西了,本篇文章,我们用前面学的知识来实现一个需求: 在一个线程中需要获取其他线程的执行结果,能想到几种方式?各有 ...
- 【SQL Server 学习系列】-- sql 随机生成中文名字
[SQL Server 学习系列]-- sql 随机生成中文名字 原文:[SQL Server 学习系列]-- sql 随机生成中文名字 1 DECLARE @fName TABLE(Id INT I ...
最新文章
- java如何读取word的占位符_java利用xml导出word(占位符替换)
- rabbitMQ(二):Fanout Exchange
- 11. Android框架和工具之 Logger(调试代码)
- gps卫星位置计算程序matlab_科研项目 | BD/ GPS卫星导航仿真测试系统研究
- c++ stl 获取最小值_如何在C ++ STL中找到向量的最小/最小元素?
- mysql 格式化_mysql中格式化数字详解
- Python机器学习方向企业面试题(三)
- 集成学习—GBDT原理理解
- 【车间调度】基于matlab遗传算法求解置换流水车间调度问题【含Matalb源码 176期】
- c语言出100道计算题,C语言例题100道
- c语言程序设计二维数组ppt,C语言程序设计教程二维数组的应用优秀讲义.ppt
- 联想ThinkPad E431禁用触摸板功能
- 个人百科怎么做,如何申请个人百度百科
- 2022浙江大学计算机考研超强攻略
- 知识图谱及其关键技术
- 在Mac M1芯片下使用Android Studio模拟器
- 43.自动获取汉子笔画
- Parellel TSP
- 浅谈数字证书的今生前世
- 力扣 1833. 雪糕的最大数量
热门文章
- 地理信息系统:利用ArcGIS制作校园地图
- 【重新定义matlab强大系列一】利用MATLAB进行清洗缺失数据
- ubuntu14.04 刚安装完成后汉语拼音输入法出错问题的解决办法
- js打开飞行模式_什么是飞行模式? 它有什么作用?什么时候应该打开它?
- (附源码)springboot音乐播放器小程序 毕业设计 170900
- php 3d animation,CSS_纯CSS实现菜单、导航栏的3D翻转动画效果,我曾经向大家展示过闪光的logo - phpStudy...
- 【JDK8 新特性 6】收集Stream流中的结果
- 杨百万:中国股市是政策市 炒股要听党和政府的话
- 【JAVA】MyEclipse 各菜单项:功能、说明(转自CSDN - lgx06)
- 计算机专业博士出国,申请经典案例:欧洲计算机科学专业博士全奖