交替打印FooBar
欢迎大家访问handsomecui的博客,转载请注明地址https://www.cnblogs.com/handsomecui,欢迎加入技术群讨论:778757421
题目来源:https://leetcode-cn.com/problems/print-foobar-alternately
两个不同的线程将会共用一个 FooBar 实例。其中一个线程将会调用 foo() 方法,另一个线程将会调用 bar() 方法。
设计修改程序,以确保 "foobar" 被输出 n 次。
题解:两个线程,一个输出完唤醒另一个线程,输出时等待上一个线程。有多种写法
写法一:使用java的Condition条件await和signal实现
import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.ReentrantLock; /** * 两个不同的线程将会共用一个 FooBar 实例。其中一个线程将会调用 foo() 方法,另一个线程将会调用 bar() 方法。 * <p> * 请设计修改程序,以确保 "foobar" 被输出 n 次。 * <p> * https://leetcode-cn.com/problems/print-foobar-alternately * * @author jy.cui * @version 1.0 * @date 2020/10/9 16:40 */ class FooBar { private int n; private ReentrantLock lock = new ReentrantLock(); private Condition conditionFoo = lock.newCondition(); private Condition conditionBar = lock.newCondition(); private volatile boolean isSignal = false; public FooBar(int n) { this.n = n; } public void foo(Runnable printFoo) throws InterruptedException { lock.lock(); // 注意Condition需要被lock包围 for (int i = 0; i < n; i++) { // printFoo.run() outputs "foo". Do not change or remove this line. printFoo.run(); conditionFoo.signal(); //释放信号 isSignal = true; //标记已释放信号 conditionBar.await(); } lock.unlock(); } public void bar(Runnable printBar) throws InterruptedException { lock.lock(); for (int i = 0; i < n; i++) { if(!isSignal){ // 没释放信号再锁 conditionFoo.await(); } // printBar.run() outputs "bar". Do not change or remove this line. printBar.run(); isSignal = false; //输出完回退标记 conditionBar.signal(); } lock.unlock(); } }
写法二:利用syncronized的对象wait和notify,交替等待另一个线程的输出,标记为判断此线程的输出状态进行阻塞。
/** * 交替打印FooBar * 两个不同的线程将会共用一个 FooBar 实例。其中一个线程将会调用 foo() 方法,另一个线程将会调用 bar() 方法。 * <p> * 请设计修改程序,以确保 "foobar" 被输出 n 次。 * <p> * https://leetcode-cn.com/problems/print-foobar-alternately * * @author jy.cui * @version 1.0 * @date 2020/10/9 16:40 */ class FooBar { private int n; private Object lock = new Object(); private volatile boolean barHandle = false; //bar输出控制 public FooBar(int n) { this.n = n; } public void foo(Runnable printFoo) throws InterruptedException { for (int i = 0; i < n; i++) { synchronized (lock){ if(barHandle){ // bar输出时等待 lock.wait(); } // printFoo.run() outputs "foo". Do not change or remove this line. printFoo.run(); lock.notify(); //唤醒bar线程 barHandle = true; // 标记唤醒bar输出 } } } public void bar(Runnable printBar) throws InterruptedException { for (int i = 0; i < n; i++) { synchronized (lock){ if(!barHandle){ //初始等待foo输出 lock.wait(); } // printBar.run() outputs "bar". Do not change or remove this line. printBar.run(); lock.notify(); //唤醒foo线程 barHandle = false; //恢复标记,控制foo输出 } } } }
写法三:无锁,标记互斥,根据全局标记让出时间片
class FooBar { private int n; private volatile boolean flag = false; public FooBar(int n) { this.n = n; } public void foo(Runnable printFoo) throws InterruptedException { for (int i = 0; i < n; i++) { while (flag){ Thread.yield(); } // printFoo.run() outputs "foo". Do not change or remove this line. printFoo.run(); flag = true; } } public void bar(Runnable printBar) throws InterruptedException { for (int i = 0; i < n; i++) { while (!flag){ Thread.yield(); } // printBar.run() outputs "bar". Do not change or remove this line. printBar.run(); flag = false; } } }
写法四:Semaphore信号量,分别等待其他线程唤醒
class FooBar { private int n; private Semaphore foo = new Semaphore(0); private Semaphore bar = new Semaphore(0); public FooBar(int n) { this.n = n; } public void foo(Runnable printFoo) throws InterruptedException { for (int i = 0; i < n; i++) { if(i != 0){ foo.acquire(); } // printFoo.run() outputs "foo". Do not change or remove this line. printFoo.run(); bar.release(); } } public void bar(Runnable printBar) throws InterruptedException { for (int i = 0; i < n; i++) { bar.acquire(); // printBar.run() outputs "bar". Do not change or remove this line. printBar.run(); foo.release(); } } }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 提示词工程——AI应用必不可少的技术
· Open-Sora 2.0 重磅开源!
· 周边上新:园子的第一款马克杯温暖上架