打印零与奇偶数
欢迎大家访问handsomecui的博客,转载请注明地址https://www.cnblogs.com/handsomecui,欢迎加入技术群讨论:778757421
一、题目描述:https://leetcode-cn.com/problems/print-zero-even-odd
相同的一个 ZeroEvenOdd 类实例将会传递给三个不同的线程:
线程 A 将调用 zero(),它只输出 0 。
线程 B 将调用 even(),它只输出偶数。
线程 C 将调用 odd(),它只输出奇数。
每个线程都有一个 printNumber 方法来输出一个整数。
请修改给出的代码以输出整数序列 010203040506... ,
其中序列的长度必须为 2n。
输入:n = 2
输出:"0102"
说明:三条线程异步执行,其中一个调用 zero(),另一个线程调用 even(),
最后一个线程调用odd()。正确的输出为 "0102"。
题解:3个线程,打印0的分别与奇偶线程互斥,奇偶线程互斥,多种解法。
解法一:不使用锁,使用两个全局标记线程输出状态,当不满足线程输出时让出时间片。
import java.util.function.IntConsumer; /** 打印零与奇偶数 相同的一个 ZeroEvenOdd 类实例将会传递给三个不同的线程: 线程 A 将调用 zero(),它只输出 0 。 线程 B 将调用 even(),它只输出偶数。 线程 C 将调用 odd(),它只输出奇数。 每个线程都有一个 printNumber 方法来输出一个整数。 请修改给出的代码以输出整数序列 010203040506... , 其中序列的长度必须为 2n。 输入:n = 2 输出:"0102" 说明:三条线程异步执行,其中一个调用 zero(),另一个线程调用 even(), 最后一个线程调用odd()。正确的输出为 "0102"。 https://leetcode-cn.com/problems/print-zero-even-odd * @author jy.cui * @version 1.0 * @date 2020/10/15 16:27 */ class ZeroEvenOdd { private int n; private volatile boolean flag1 = true; private volatile boolean flag2 = false; public ZeroEvenOdd(int n) { this.n = n; } // printNumber.accept(x) outputs "x", where x is an integer. public void zero(IntConsumer printNumber) throws InterruptedException { for(int i = 1; i <= n; i++){ while (!flag1){ Thread.yield(); } printNumber.accept(0); flag1 = false; } } public void even(IntConsumer printNumber) throws InterruptedException { for(int i = 1; i <= n; i++){ if((i & 1) == 0){ while (!flag2 || flag1){ Thread.yield(); } printNumber.accept(i); flag2 = false; flag1 = true; } } } public void odd(IntConsumer printNumber) throws InterruptedException { for(int i = 1; i <= n; i++){ if((i & 1) == 1){ while (flag2 || flag1){ Thread.yield(); } printNumber.accept(i); flag2 = true; flag1 = true; } } } }
解法二:信号量Semaphore,思路,三个信号量,分别阻塞,等待其他线程的唤醒,奇偶线程输出完毕唤醒zero线程,zero根据输出的次数,判断唤醒奇偶线程。
Semaphore用法:
void acquire():从此信号量获取一个许可,在提供一个许可前一直将线程阻塞,否则线程被中断。
void release():释放一个许可,将其返回给信号量。
int availablePermits():返回此信号量中当前可用的许可数。
boolean hasQueuedThreads():查询是否有线程正在等待获取。
class ZeroEvenOdd { private int n; private Semaphore zero = new Semaphore(0); private Semaphore odd = new Semaphore(0); private Semaphore even = new Semaphore(0); public ZeroEvenOdd(int n) { this.n = n; } // printNumber.accept(x) outputs "x", where x is an integer. public void zero(IntConsumer printNumber) throws InterruptedException { for(int i = 1; i <= n; i++){ if (i != 1){ zero.acquire(); } printNumber.accept(0); if((i & 1) == 0){ even.release(); }else { odd.release(); } } } public void even(IntConsumer printNumber) throws InterruptedException { for(int i = 1; i <= n; i++){ if((i & 1) == 0){ even.acquire(); printNumber.accept(i); zero.release(); } } } public void odd(IntConsumer printNumber) throws InterruptedException { for(int i = 1; i <= n; i++){ if((i & 1) == 1){ odd.acquire(); printNumber.accept(i); zero.release(); } } } }
测试线程:
public static void main(String[] args) throws InterruptedException { ZeroEvenOdd foo = new ZeroEvenOdd(5); new Thread(()->{ try { foo.zero(new A()); } catch (InterruptedException e) { e.printStackTrace(); } }).start(); new Thread(()->{ try { foo.odd(new A()); } catch (InterruptedException e) { e.printStackTrace(); } }).start(); Thread threadC = new Thread(() -> { try { foo.even(new A()); } catch (InterruptedException e) { e.printStackTrace(); } }); threadC.start(); threadC.join(); } static class A implements IntConsumer { @Override public void accept(int value) { System.out.println(value); } }
【推荐】国内首个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 重磅开源!
· 周边上新:园子的第一款马克杯温暖上架
2015-10-20 士兵杀敌(三)(线段树)
2015-10-20 Ping pong(树状数组经典)
2015-10-20 士兵杀敌(五)
2015-10-20 stringstream字符串流