本文主要是介绍LeetCode-1115.交替打印FooBar(多线程),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
LeetCode 题目描述
我们提供一个类:
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");}}
}
两个不同的线程将会共用一个 FooBar 实例。其中一个线程将会调用 foo() 方法,另一个线程将会调用 bar() 方法。
请设计修改程序,以确保 “foobar” 被输出 n 次。
示例 1:
输入: n = 1
输出: "foobar"
解释: 这里有两个线程被异步启动。其中一个调用 foo() 方法, 另一个调用 bar() 方法,"foobar" 将被输出一次。
示例 2:
输入: n = 2
输出: "foobarfoobar"
解释: "foobar" 将被输出两次。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/print-foobar-alternately
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
题解
解题思路为:
- 多线程并发访问同一个对象的成员方法
- 成员方法的执行顺序是固定的(突破点)
对于多线程固定顺序的执行,我们可以采用 Thread.join 方法。但此处不适用,此处我们只可以修改方法内部实现机制,并不能控制线程执行的方式,所以应该是线程等待唤醒机制。
顺序执行实现方案:
- 方法内部使用布尔变量控制当前方法是否可以执行,即 if(boolean)` 范式,某个方法执行后修改布尔值达到顺序控制
- 使用并发工具类 Semaphore 实现(初始许可为 0,执行前置条件后释放一个许可)(感兴趣可尝试实现)
此处如果使用
CyclicBarrier
工具类不能保证 bar 在 foo 前执行,需要额外控制。
方法内部使用布尔变量控制实现
对于 synchronized 关键字,该实现添加在方法签名上而不是 for 循环内部,减少锁的操作,而是在获取锁后使用等待通知机制唤醒后继续执行。可参考博文-Java 线程等待通知机制(wait、notify)
class FooBar {private volatile boolean tmp = false;private int n;public FooBar(int n) {this.n = n;}public synchronized void foo(Runnable printFoo) throws InterruptedException {for (int i = 0; i < n; i++) {if (tmp) {wait();}// printFoo.run() outputs "foo". Do not change or remove this line.printFoo.run();tmp = true;notify();}}public synchronized void bar(Runnable printBar) throws InterruptedException {for (int i = 0; i < n; i++) {if (!tmp) {wait();}// printBar.run() outputs "bar". Do not change or remove this line.printBar.run();tmp = false;notify();}}
}
参考
有关并发编程相关知识参考本博客专栏对应文章。
- 本题在 LeetCode-1114. 按序打印(多线程) 顺序执行基础上增加了 for 循环内部等待通知操作。
这篇关于LeetCode-1115.交替打印FooBar(多线程)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!