LeetCode-1195.交替打印字符串(多线程)

2024-06-03 13:32

本文主要是介绍LeetCode-1195.交替打印字符串(多线程),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

LeetCode 题目描述

编写一个可以从 1 到 n 输出代表这个数字的字符串的程序,但是:

  • 如果这个数字可以被 3 整除,输出 “fizz”。
  • 如果这个数字可以被 5 整除,输出 “buzz”。
  • 如果这个数字可以同时被 3 和 5 整除,输出 “fizzbuzz”。

例如,当 n = 15,输出: 1, 2, fizz, 4, buzz, fizz, 7, 8, fizz, buzz, 11, fizz, 13, 14, fizzbuzz。

假设有这么一个类:

class FizzBuzz {public FizzBuzz(int n) { ... }               // constructorpublic void fizz(printFizz) { ... }          // only output "fizz"public void buzz(printBuzz) { ... }          // only output "buzz"public void fizzbuzz(printFizzBuzz) { ... }  // only output "fizzbuzz"public void number(printNumber) { ... }      // only output the numbers
}

请你实现一个有四个线程的多线程版  FizzBuzz, 同一个 FizzBuzz 实例会被如下四个线程使用:

  • 线程 A 将调用 fizz() 来判断是否能被 3 整除,如果可以,则输出 fizz。
  • 线程 B 将调用 buzz() 来判断是否能被 5 整除,如果可以,则输出 buzz。
  • 线程 C 将调用 fizzbuzz() 来判断是否同时能被 3 和 5 整除,如果可以,则输出 fizzbuzz。
  • 线程 D 将调用 number() 来实现输出既不能被 3 整除也不能被 5 整除的数字。

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/fizz-buzz-multithreaded
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

题解

整体思考思路为:
4 个线程并发执行

①.打印数字的线程控制着其他 3 个线程的执行,每次打印数字线程 number 方法执行后判断数字整除情况唤醒对应线程。但是该处我们考虑是否有这种情况,number 方法唤醒 fizz 方法,fizz 方法执行后其实直接可以执行 buzz 方法了,如果我们通过 number 方法过渡会出现多余的操作。(参考 Solution1)
②.每个线程判断整除情况唤醒对应的线程。(最终考虑停止程序时释放所有许可时判断较为复杂)
③.使用单个信号量+for 循环轮询判断,满足条件执行,不满足条件则释放许可后让其他方法进行判断。(参考 Solution2,该实现考虑-如果某方法耗时较长时性能问题)

Solution1.Semaphore + 整型变量

class FizzBuzz {private int n;Semaphore fizzSem = new Semaphore(0);Semaphore buzzSem = new Semaphore(0);Semaphore fizzBuzzSem = new Semaphore(0);Semaphore numSem = new Semaphore(1);private int i;public FizzBuzz(int n) {//从 1 开始this.i = 1;this.n = n;}// printFizz.run() outputs "fizz".public void fizz(Runnable printFizz) throws InterruptedException {while (true) {fizzSem.acquire();if (i > n) {break;}printFizz.run();i++;numSem.release();}}// printBuzz.run() outputs "buzz".public void buzz(Runnable printBuzz) throws InterruptedException {while (true) {buzzSem.acquire();if (i > n) {break;}printBuzz.run();i++;numSem.release();}}// printFizzBuzz.run() outputs "fizzbuzz".public void fizzbuzz(Runnable printFizzBuzz) throws InterruptedException {while (true) {fizzBuzzSem.acquire();if (i > n) {break;}printFizzBuzz.run();i++;numSem.release();}}// printNumber.accept(x) outputs "x", where x is an integer.public void number(IntConsumer printNumber) throws InterruptedException {///主要是这儿执行完后其他的还在等,所以会超时,这个时候释放掉所有的就行了。while (i <= n) {numSem.acquire();if (i % 3 == 0 && i % 5 == 0) {fizzBuzzSem.release();} else if (i % 3 == 0) {fizzSem.release();} else if (i % 5 == 0) {buzzSem.release();} else {if (i <= n) {printNumber.accept(i);}i++;numSem.release();}}release(); // 最终释放许可}private void release() {fizzBuzzSem.release();buzzSem.release();fizzSem.release();}
}

Solution2.Semaphore + for 循环轮询判断

class FizzBuzz {private Semaphore semaphore = new Semaphore(1);private int curNum = 1;private int n;public FizzBuzz(int n) {this.n = n;}// printFizz.run() outputs "fizz".public void fizz(Runnable printFizz) throws InterruptedException {for (; ; ) {this.semaphore.acquire(1);try {if (this.curNum > n) {return;}if ((this.curNum % 3 == 0) && (this.curNum % 5 != 0)) {printFizz.run();this.curNum++;}} finally {// Release the permit anyway.this.semaphore.release(1);}}}// printBuzz.run() outputs "buzz".public void buzz(Runnable printBuzz) throws InterruptedException {for (; ; ) {this.semaphore.acquire(1);try {if (this.curNum > n) {return;}if ((this.curNum % 3 != 0) && (this.curNum % 5 == 0)) {printBuzz.run();this.curNum++;}} finally {this.semaphore.release(1);}}}// printFizzBuzz.run() outputs "fizzbuzz".public void fizzbuzz(Runnable printFizzBuzz) throws InterruptedException {for (; ; ) {this.semaphore.acquire(1);try {if (this.curNum > n) {return;}if ((this.curNum % 3 == 0) && (this.curNum % 5 == 0)) {printFizzBuzz.run();this.curNum++;}} finally {this.semaphore.release(1);}}}// printNumber.accept(x) outputs "x", where x is an integer.public void number(IntConsumer printNumber) throws InterruptedException {for (; ; ) {this.semaphore.acquire(1);try {if (this.curNum > n) {return;}if ((this.curNum % 3 != 0) && (this.curNum % 5 != 0)) {printNumber.accept(this.curNum);this.curNum++;}} finally {this.semaphore.release(1);}}}
}

参考

  • 参考博文-Java 线程等待通知机制(wait、notify)
  • 参考博文-Java 控制并发数的信号量-Semaphore
  • 更多并发编程相关博文参考 Java 并发编程-专栏文章目录汇总

这篇关于LeetCode-1195.交替打印字符串(多线程)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1027126

相关文章

Python实现字典转字符串的五种方法

《Python实现字典转字符串的五种方法》本文介绍了在Python中如何将字典数据结构转换为字符串格式的多种方法,首先可以通过内置的str()函数进行简单转换;其次利用ison.dumps()函数能够... 目录1、使用json模块的dumps方法:2、使用str方法:3、使用循环和字符串拼接:4、使用字符

Python 常用数据类型详解之字符串、列表、字典操作方法

《Python常用数据类型详解之字符串、列表、字典操作方法》在Python中,字符串、列表和字典是最常用的数据类型,它们在数据处理、程序设计和算法实现中扮演着重要角色,接下来通过本文给大家介绍这三种... 目录一、字符串(String)(一)创建字符串(二)字符串操作1. 字符串连接2. 字符串重复3. 字

Java 字符串操作之contains 和 substring 方法最佳实践与常见问题

《Java字符串操作之contains和substring方法最佳实践与常见问题》本文给大家详细介绍Java字符串操作之contains和substring方法最佳实践与常见问题,本文结合实例... 目录一、contains 方法详解1. 方法定义与语法2. 底层实现原理3. 使用示例4. 注意事项二、su

SpringBoot分段处理List集合多线程批量插入数据方式

《SpringBoot分段处理List集合多线程批量插入数据方式》文章介绍如何处理大数据量List批量插入数据库的优化方案:通过拆分List并分配独立线程处理,结合Spring线程池与异步方法提升效率... 目录项目场景解决方案1.实体类2.Mapper3.spring容器注入线程池bejsan对象4.创建

Java实现将HTML文件与字符串转换为图片

《Java实现将HTML文件与字符串转换为图片》在Java开发中,我们经常会遇到将HTML内容转换为图片的需求,本文小编就来和大家详细讲讲如何使用FreeSpire.DocforJava库来实现这一功... 目录前言核心实现:html 转图片完整代码场景 1:转换本地 HTML 文件为图片场景 2:转换 H

Java使用正则提取字符串中的内容的详细步骤

《Java使用正则提取字符串中的内容的详细步骤》:本文主要介绍Java中使用正则表达式提取字符串内容的方法,通过Pattern和Matcher类实现,涵盖编译正则、查找匹配、分组捕获、数字与邮箱提... 目录1. 基础流程2. 关键方法说明3. 常见场景示例场景1:提取所有数字场景2:提取邮箱地址4. 高级

Python多线程实现大文件快速下载的代码实现

《Python多线程实现大文件快速下载的代码实现》在互联网时代,文件下载是日常操作之一,尤其是大文件,然而,网络条件不稳定或带宽有限时,下载速度会变得很慢,本文将介绍如何使用Python实现多线程下载... 目录引言一、多线程下载原理二、python实现多线程下载代码说明:三、实战案例四、注意事项五、总结引

Python多线程应用中的卡死问题优化方案指南

《Python多线程应用中的卡死问题优化方案指南》在利用Python语言开发某查询软件时,遇到了点击搜索按钮后软件卡死的问题,本文将简单分析一下出现的原因以及对应的优化方案,希望对大家有所帮助... 目录问题描述优化方案1. 网络请求优化2. 多线程架构优化3. 全局异常处理4. 配置管理优化优化效果1.

Python 字符串裁切与提取全面且实用的解决方案

《Python字符串裁切与提取全面且实用的解决方案》本文梳理了Python字符串处理方法,涵盖基础切片、split/partition分割、正则匹配及结构化数据解析(如BeautifulSoup、j... 目录python 字符串裁切与提取的完整指南 基础切片方法1. 使用切片操作符[start:end]2

MyBatis的xml中字符串类型判空与非字符串类型判空处理方式(最新整理)

《MyBatis的xml中字符串类型判空与非字符串类型判空处理方式(最新整理)》本文给大家介绍MyBatis的xml中字符串类型判空与非字符串类型判空处理方式,本文给大家介绍的非常详细,对大家的学习或... 目录完整 Hutool 写法版本对比优化为什么status变成Long?为什么 price 没事?怎