此文首发于我的个人博客:zhang0peter的个人博客


LeetCode题解专栏:LeetCode题解
LeetCode 所有题目总结:LeetCode 所有题目总结


题目地址:Print FooBar Alternately - LeetCode


Suppose you are given the following code:

class FooBar {public void foo() {for (int i = 0; i < n; i++) {print("foo");}}public void bar() {for (int i = 0; i < n; i++) {print("bar");}}
}

The same instance of FooBar will be passed to two different threads. Thread A will call foo() while thread B will call bar(). Modify the given program to output “foobar” n times.

Example 1:

Input: n = 1
Output: "foobar"
Explanation: There are two threads being fired asynchronously. One of them calls foo(), while the other calls bar(). "foobar" is being output 1 time.

Example 2:

Input: n = 2
Output: "foobarfoobar"
Explanation: "foobar" is being output 2 times.

这道题目的意思是多线程情况下如何保证代码执行的顺序,是一道经典的多线程的题目。

最容易想到的是用Java的synchronized加锁,然后flag变量控制执行顺序。

Java解法如下:

class FooBar {volatile private int n;private int flag = 0;public FooBar(int n) {this.n = n;}public void foo(Runnable printFoo) throws InterruptedException {for (int i = 0; i < n; i++) {synchronized (this) {while (flag == 1) {this.wait();}// printFoo.run() outputs "foo". Do not change or remove this line.printFoo.run();flag = 1;this.notifyAll();}}}public void bar(Runnable printBar) throws InterruptedException {for (int i = 0; i < n; i++) {synchronized (this) {while (flag == 0) {this.wait();}// printBar.run() outputs "bar". Do not change or remove this line.printBar.run();flag = 0;this.notifyAll();}}}
}

当然我们可以使用更高级的工具,比如说 CyclicBarrier。
注意:下面的代码有问题,不能确保并发的顺序!!


class FooBar {private int n;private final CyclicBarrier barrier = new CyclicBarrier(2);public FooBar(int n) {this.n = n;}public void foo(Runnable printFoo) throws InterruptedException {for (int i = 0; i < n; i++) {// printFoo.run() outputs "foo". Do not change or remove this line.printFoo.run();try {barrier.await();} catch (BrokenBarrierException e) {e.printStackTrace();}}}public void bar(Runnable printBar) throws InterruptedException {for (int i = 0; i < n; i++) {try {barrier.await();} catch (BrokenBarrierException e) {e.printStackTrace();}// printBar.run() outputs "bar". Do not change or remove this line.printBar.run();}}
}

另一种正确的做法是使用信号量:Semaphore

class FooBar {private int n;private final Semaphore foo = new Semaphore(0);private final Semaphore bar = new Semaphore(1);public FooBar(int n) {this.n = n;}public void foo(Runnable printFoo) throws InterruptedException {for (int i = 0; i < n; i++) {bar.acquire();// printFoo.run() outputs "foo". Do not change or remove this line.printFoo.run();foo.release();}}public void bar(Runnable printBar) throws InterruptedException {for (int i = 0; i < n; i++) {foo.acquire();// printBar.run() outputs "bar". Do not change or remove this line.printBar.run();bar.release();}}
}

LeetCode 1115. Print FooBar Alternately--多线程并发问题--Java解法--CyclicBarrier, synchronized, Semaphore 信号量相关推荐

  1. Java多线程并发编程--Java并发包(JUC)

    Java多线程并发–Java并发包(JUC) 前言 前一篇文章中,笔者已经介绍了Java多线程的一些基础知识,但是想要成为一名中高级Java程序员还必须懂得Java并发包(JUC)的知识点,而且JUC ...

  2. Java 多线程 并发 锁 Java线程面试题

    1) 什么是线程? 线程是操作系统能够进行运算调度的最小单位,它被包含在进程之中,是进程中的实际运作单位.程序员可以通过它进行多处理器编程,你可以使用多线程对运算密集型任务提速.比如,如果一个线程完成 ...

  3. LeetCode 1195. Fizz Buzz Multithreaded--并发系列题目--Java 解法--AtomicInteger/CountDownLatch/CyclicBarrier

    题目地址:Fizz Buzz Multithreaded - LeetCode Write a program that outputs the string representation of nu ...

  4. 多线程-并发工具类之CyclicBarrier详解

    文章目录 简介 例子 实现原理 小结 简介 从字面意思理解,CyclicBarrier是回环屏障的意思,它可以让一组线程全部达到一个状态后再全部同时执行.这里之所以叫作回环是因为当所有等待线程执行完毕 ...

  5. JAVA中的并发工具 -- CountDownLatch、CyclicBarrier、Semaphore

    2019独角兽企业重金招聘Python工程师标准>>> CountDownLatch CountDownLatch允许一个或多个线程等待其他线程完成操作. CountDownLatc ...

  6. 将指定的计数添加到信号量中会导致其超过_并发编程用不上?Semaphore信号量了解一下...

    什么是信号量 Java中的同步工具类信号量即计数信号量(Counting Semaphore),是用来控制访问某个特定资源的操作数量,或同时执行某个指定操作的数量.可以简单理解为信号量用来限制对某个资 ...

  7. 【高并发】java JUC中的Semaphore(信号量)

    1.概述 1.1 问题 什么是Semaphore? Semaphore内部原理? Semaphore常用方法有哪些? 如何实现线程同步和互斥的? Semaphore适合用在什么场景? 单独使用Sema ...

  8. LeetCode 77. Combinations--回溯法,-Python,Java解法

    题目地址: Given two integers n and k, return all possible combinations of k numbers out of 1 - n. Exampl ...

  9. Android 数据库综述(二) 程序计算器与信号量来处理多线程并发问题

    Android 数据库综述(二) 程序计算器与信号量来处理多线程并发问题 多线程操作数据库,为处理并发问题,大家第一想到的是加锁操作 ,SQLite是文件级别的锁.SQLite3对于并发的处理机制是允 ...

最新文章

  1. html的input不可编辑状态,HTML中让表单input不可编辑的方法
  2. Hyperledger Besu(2)隐私
  3. CentOS 6.X启动流程
  4. 移动端canvas_web前端开发分享-css,js移动篇
  5. 解决go get下载包失败问题
  6. bzoj 1032: [JSOI2007]祖码Zuma(区间DP)
  7. 春节过后,外贸人如何快速抓住采购旺季,高效跟进客户
  8. C盘压缩,电脑无法正常启动的解决方法?
  9. web3.0是什么意思(web3和元宇宙的关系)
  10. SlideShow Pro(幻灯片制作)v5.0.0.10绿色中文版
  11. J2EE学习推荐书籍
  12. TCP/IP、 IXP/SPX、 NetBEUI、 AppleTalk协议
  13. DPU网络开发SDK——DPDK(九)
  14. IP数据库的定位能力在商业端的具体应用有哪些?(一)
  15. 读懂常见IRP:IRP_MJ_CLEANUP\IRP_MJ_CLOSE\IRP_MJ_CREATE
  16. Java 8 Stream 的终极技巧——Collectors 操作
  17. linux / 根目录爆满
  18. linux最新内核5.80版本移植详细过程
  19. Centos 8 安装 Openbravo 之安装 Openjdk11
  20. Linux学习-47-Linux系统进程管理和启动方式

热门文章

  1. 基于机器学习的临床决策支持-ANN
  2. 提高android 运行效率,如何提高安卓手机运行速度 提高安卓手机运行速度方法
  3. c语言链表交换,求单链表的数据交换解决思路
  4. 去重查询_《前端算法系列》数组去重
  5. 可视化生信分析利器 Galaxy 之 Docker 部署
  6. Coronascape – 为COVID-19研究特制的基因列表比较工具
  7. Gastroenterology:住院期间COVID-19患者肠道菌群的变化
  8. 生物信息通识技术研讨会
  9. 不属于JAVA类中的变量_在Java中,不属于整数类型变量的是( )。_学小易找答案...
  10. R语言使用table1包绘制(生成)三线表、使用单变量分列构建三线表、自定义overall的标签名称