1114. 按序打印

我们提供了一个类:

public class Foo {public void first() { print("first"); }public void second() { print("second"); }public void third() { print("third"); }
}

三个不同的线程将会共用一个 Foo 实例。

线程 A 将会调用 first() 方法
线程 B 将会调用 second() 方法
线程 C 将会调用 third() 方法

请设计修改程序,以确保 second() 方法在 first() 方法之后被执行,third() 方法在 second() 方法之后被执行。

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/print-in-order

示例 1:
输入: [1,2,3]
输出: “firstsecondthird”
解释:
有三个线程会被异步启动。
输入 [1,2,3] 表示线程 A 将会调用 first() 方法,线程 B 将会调用 second() 方法,线程 C 将会调用 third() 方法。
正确的输出是 “firstsecondthird”。
示例 2:
输入: [1,3,2]
输出: “firstsecondthird”
解释:
输入 [1,3,2] 表示线程 A 将会调用 first() 方法,线程 B 将会调用 third() 方法,线程 C 将会调用 second() 方法。
正确的输出是 “firstsecondthird”。

提示:

尽管输入中的数字似乎暗示了顺序,但是我们并不保证线程在操作系统中的调度顺序。
你看到的输入格式主要是为了确保测试的全面性。

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/print-in-order

官方题解

class Foo {private AtomicInteger firstJobDone=new AtomicInteger(0);private AtomicInteger secondJobDone=new AtomicInteger(0);public Foo() {}public void first(Runnable printFirst) throws InterruptedException {// printFirst.run() outputs "first". Do not change or remove this line.printFirst.run();//mark the first job as done,by increasing its countfirstJobDone.incrementAndGet();}public void second(Runnable printSecond) throws InterruptedException {while(firstJobDone.get()!=1){// waiting for the first job to be done}// printSecond.run() outputs "second". Do not change or remove this line.printSecond.run();//mark the second as done,by increasing its countsecondJobDone.incrementAndGet();}public void third(Runnable printThird) throws InterruptedException {while(secondJobDone.get()!=1){//waiting for the second job to be done}// printThird.run() outputs "third". Do not change or remove this line.printThird.run();}
}


构造执行屏障实现

我们使用一个 Ojbect 对象 lock 实现所有执行屏障的锁对象,两个布尔型对象 firstFinished,secondFinished 保存屏障消除的条件。

作者:pulsaryu
链接:https://leetcode-cn.com/problems/print-in-order/solution/gou-zao-zhi-xing-ping-zhang-shi-xian-

class Foo {private boolean firstFinished;private boolean secondFinished;private Object lock=new Object();public Foo() {}public void first(Runnable printFirst) throws InterruptedException {synchronized(lock){// printFirst.run() outputs "first". Do not change or remove this line.printFirst.run();firstFinished=true;lock.notifyAll();}                   }public void second(Runnable printSecond) throws InterruptedException {    synchronized(lock){while(firstFinished==false){lock.wait();//当他拿到锁时,如果第一个线程没执行,他就释放这个锁(这样第一个线程就有机会拿到锁了)}// printSecond.run() outputs "second". Do not change or remove this line.printSecond.run();secondFinished=true;lock.notifyAll();}                }public void third(Runnable printThird) throws InterruptedException {synchronized(lock){while(!secondFinished){lock.wait();}// printThird.run() outputs "third". Do not change or remove this line.printThird.run();//lock.notifyAll();//不用通知其他线程,因为它肯定是最后执行的}}
}

1115. 交替打印FooBar

我们提供一个类:

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

本地运行完整代码

package LeetCode.MultiThread;public class jiaotiFooBar implements Runnable {FooBar foobar=new FooBar(100);public static void main(String[] args) {jiaotiFooBar jiaotiFooBar = new jiaotiFooBar();new Thread(jiaotiFooBar,"1").start();new Thread(jiaotiFooBar,"2").start();}@Overridepublic void run() {if(Thread.currentThread().getName()=="1"){try {foobar.foo();} catch (InterruptedException e) {e.printStackTrace();}}if(Thread.currentThread().getName()=="2"){try {foobar.bar();} catch (InterruptedException e) {e.printStackTrace();}}}
}class FooBar{private int n;boolean fooFlag=false;boolean barFlag=false;volatile  boolean fooFirstRun=false;public FooBar(int n) {this.n = n;}public synchronized void foo() throws InterruptedException {for (int i = 0; i < n; i++) {if(fooFirstRun)//如果已经打印过foo,打印foo的线程先等待{wait();}System.out.print("foo");fooFirstRun=true;notify();}}public synchronized void bar() throws InterruptedException {for (int i = 0; i < n; i++) {if (!fooFirstRun) {wait();//如果还没打印foo,打印bar的线程先等待}System.out.print("bar");fooFirstRun=false;notify();}}
}


解法2

记套路模板:
1、AtomicInteger 标记量
2、锁资源
3、wait、notify/notifyAll 的使用(变种就是本文中的 await 和 singal)
4、条件阻塞
5、循环条件(一般都是最外层)

class FooBar {private int n;private AtomicInteger flag = new AtomicInteger(0);private ReentrantLock lock = new ReentrantLock();private Condition condition1 = lock.newCondition();private Condition condition2 = lock.newCondition();public FooBar(int n) {this.n = n;}public void foo(Runnable printFoo) throws InterruptedException {for (int i = 0; i < n; i++) {lock.lock();try {while (flag.get() != 0) {condition1.await();}printFoo.run();flag.set(1);condition2.signal();} finally {lock.unlock();}}}public void bar(Runnable printBar) throws InterruptedException {for (int i = 0; i < n; i++) {lock.lock();try {while (flag.get() != 1) {condition2.await();}printBar.run();flag.set(0);condition1.signal();} finally {lock.unlock();}}}
}作者:leetcoder-youzg
链接:https://leetcode-cn.com/problems/print-foobar-alternately/solution/java-yi-fa-tong-tong-mo-fa-by-leetcoder-fhqql/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

1116. 打印零与奇偶数

假设有这么一个类:

class ZeroEvenOdd {public ZeroEvenOdd(int n) { ... }      // 构造函数public void zero(printNumber) { ... }  // 仅打印出 0public void even(printNumber) { ... }  // 仅打印出 偶数public void odd(printNumber) { ... }   // 仅打印出 奇数
}

相同的一个 ZeroEvenOdd 类实例将会传递给三个不同的线程:

线程 A 将调用 zero(),它只输出 0 。
线程 B 将调用 even(),它只输出偶数。
线程 C 将调用 odd(),它只输出奇数。

每个线程都有一个 printNumber 方法来输出一个整数。请修改给出的代码以输出整数序列 010203040506… ,其中序列的长度必须为 2n。

示例 1:
输入:n = 2
输出:“0102”
说明:三条线程异步执行,其中一个调用 zero(),另一个线程调用 even(),最后一个线程调用odd()。正确的输出为 “0102”。
示例 2:
输入:n = 5
输出:“0102030405”

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/print-zero-even-odd

我的解法
自己写了两个小时,不管力扣过不过,先贴在这,至少自己本地测试是没有问题的

package LeetCode.MultiThread;public class printZero implements Runnable{ZeroEvenOdd zeroEvenOdd=new ZeroEvenOdd(10);public static void main(String[] args) {printZero printZero=new printZero();new Thread(printZero,"1").start();new Thread(printZero,"2").start();new Thread(printZero,"3").start();}@Overridepublic void run() {if(Thread.currentThread().getName()=="1"){try {zeroEvenOdd.zero();} catch (InterruptedException e) {e.printStackTrace();}}if(Thread.currentThread().getName()=="2") //线程2调用even(){try {zeroEvenOdd.even();} catch (InterruptedException e) {e.printStackTrace();}}if(Thread.currentThread().getName()=="3"){try {zeroEvenOdd.Odd();} catch (InterruptedException e) {e.printStackTrace();}}}
}class ZeroEvenOdd{private int n;boolean firstFinished=false;boolean secondFinished=false;boolean thirdFinished=true;//为了满足第一个线程的执行条件,设置为trueboolean hasOddtran=false;//bug:会出现偶数线程比单数线程先执行,这样程序无法正常结束,所以设一个标志位,最开始让奇数线程(Odd)先执行public ZeroEvenOdd(int n) {this.n = n;}public synchronized void zero() throws InterruptedException {for (int i =1; i <= n; i++) {if(!((thirdFinished||secondFinished)&&!firstFinished))//如果不是(第2或第3个线程执行完毕且第一个线程未执行)就释放锁{wait();}System.out.print(0);firstFinished=true;secondFinished=false;thirdFinished=false;notifyAll();//因为剩余两个线程,所以要用notifyAll()}}public synchronized void even() throws InterruptedException {for (int i = 1; i <= n; i++) {if(!(firstFinished&&!secondFinished)||hasOddtran==false)//如果不是(第一个线程执行完毕,且第二个线程未执行)就释放锁{wait();}if(i%2==0)//打印偶数{System.out.print(i);secondFinished=true;firstFinished=false;thirdFinished=false;notifyAll();}}}public synchronized void Odd() throws InterruptedException {for (int i = 1; i <= n; i++) {if( !(firstFinished&&!thirdFinished))//如果不是(第一个线程执行完毕,第三个线程未执行)就释放锁{wait();}if(i%2==1)//打印奇数{System.out.print(i);thirdFinished=true;secondFinished=false;firstFinished=false;hasOddtran=true;notifyAll();}}}
}


测试结果
力扣测试的话是奇数先打印完,才打印的偶数,而且当测试用例是奇数时,会超时,搞不懂


可以通过的题解
解题思路

下标从1开始数:
0占奇数下标(即i%2 == 1);
偶数占4的倍数的下标(即i/2%2 == 0);
奇数占其它下标(即i/2%2 == 1);

作者:WeitongBai
链接:https://leetcode-cn.com/problems/print-zero-even-odd/solution/100shi-jian-jie-fa-xia-biao-biao-ji-ling-qi-ou-by-/

class ZeroEvenOdd2 {private int n;private int i = 1;public ZeroEvenOdd2(int n) {this.n = n;}// printNumber.accept(x) outputs "x", where x is an integer.public void zero() throws InterruptedException {synchronized(this){while(true){while (i <= 2 *n && i%2 == 0) wait();if (i > 2*n) break;//printNumber.accept(0);System.out.print(0);i++;notifyAll();}}}public void even() throws InterruptedException {synchronized(this){while(true){while (i <= 2*n && (i%2 == 1 || (i%2 == 0 && i/2%2 == 1))) wait();if(i > 2*n) break;//  printNumber.accept(i/2);System.out.print(i/2);i++;notifyAll();}}}public void odd() throws InterruptedException {synchronized(this){while(true){while (i <= 2*n &&(i%2 == 1 || (i%2 == 0 && i/2%2 == 0))) wait();if(i > 2*n) break;//printNumber.accept(i/2);System.out.print(i/2);i++;notifyAll();}}}
}

解题思路2

可以通过Thread.yeild()释放CPU资源,
其实本题想表达的意思就是A、B、C三个线程共同的协作,保证:

1.B执行前要A先执行,C执行前要A先执行
2.C要在B执行之前
3.保证输出 n * 2个数(其中有n个0)

说白了就是不管先输出奇数,还是先输出偶数,先输出0。且奇数优先输出于偶数。

那么咱就开始控制这个流程就好了

1.首先执行的是A线程,然后由A线程控制下一个阶段,核心控制
2.由控制器来控制放行的是B还是C。默认

private volatile boolean control = true;

保证C先执行。
3.当C先执行完,将控制器“翻面”,然后回退到A线程去处理。

作者:zong-you-yi-tian
链接:https://leetcode-cn.com/problems/print-zero-even-odd/solution/qi-shi-tong-xian-qian-liang-dao-ti-yi-yang-wo-men-/
来源:力扣(LeetCode)

class ZeroEvenOdd {private int n;private volatile int state;public ZeroEvenOdd(int n) {this.n = n;}public void zero(IntConsumer printNumber) throws InterruptedException {for (int i = 0; i < n; i++) {while (state != 0) {Thread.yield();}printNumber.accept(0);if (i % 2 == 0) {state = 1;} else {state = 2;}}}public void even(IntConsumer printNumber) throws InterruptedException {for (int i = 2; i <= n; i += 2) {while (state != 2) {Thread.yield();}printNumber.accept(i);state = 0;}}public void odd(IntConsumer printNumber) throws InterruptedException {for (int i = 1; i <= n; i += 2) {while (state != 1) {Thread.yield();}printNumber.accept(i);state = 0;}}}

解题思路3

通过三个信号量来控制
zero方法中的for表示要输出的0个次数,同时用来控制要唤醒偶数还是奇数方法
even方法用来输出偶数同时唤醒zero方法
odd方法用来输出奇数同时唤醒zero方法

作者:dan-xie-6
链接:https://leetcode-cn.com/problems/print-zero-even-odd/solution/xin-hao-liang-jie-jue-by-dan-xie-6/

import java.util.concurrent.Semaphore;
import java.util.function.IntConsumer;class ZeroEvenOdd {private int n;private Semaphore zero = new Semaphore(1);private Semaphore even = new Semaphore(0);private Semaphore odd = 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++){zero.acquire();printNumber.accept(0);if(i%2==1){odd.release();}else{even.release();}}}public void even(IntConsumer printNumber) throws InterruptedException {for (int i=2;i<=n;i+=2){even.acquire();printNumber.accept(i);zero.release();}}public void odd(IntConsumer printNumber) throws InterruptedException {for (int i=1;i<=n;i+=2){odd.acquire();printNumber.accept(i);zero.release();}}public static void main(String[] args) {ZeroEvenOdd zeroEvenOdd = new ZeroEvenOdd(6);new Thread(() -> {try {zeroEvenOdd.zero(System.out::print);} catch (InterruptedException e) {e.printStackTrace();}}).start();new Thread(() -> {try {zeroEvenOdd.even(System.out::print);} catch (InterruptedException e) {e.printStackTrace();}}).start();new Thread(() -> {try {zeroEvenOdd.odd(System.out::print);} catch (InterruptedException e) {e.printStackTrace();}}).start();}
}

力扣-多线程专项(一)(按序打印、交替打印、打印零与奇偶数)相关推荐

  1. 《LeetCode力扣练习》剑指 Offer 29. 顺时针打印矩阵 Java

    <LeetCode力扣练习>剑指 Offer 29. 顺时针打印矩阵 Java 一.资源 题目: 输入一个矩阵,按照从外向里以顺时针的顺序依次打印出每一个数字. 示例 1: 输入:matr ...

  2. 打印零与奇偶数 思路分析

    1116. 打印零与奇偶数 假设有这么一个类: class ZeroEvenOdd {public ZeroEvenOdd(int n) { ... } // 构造函数public void zero ...

  3. JUC练习代码-力扣多线程1126题目:哲学家进餐,解题详解

    想起来上学的时候好像就挺经典的一道算法题,一直没有自己试过去解决.刚好力扣上有这道题,于是试试看. 题目描述就简单说了.5个哲学家5只筷子,要保证每个哲学家都能吃上饭.. 哲学家从 0 到 4 按 顺 ...

  4. 力扣 6009. 使两字符串互为字母异位词的最少步骤数

    题目 给你两个字符串 s 和 t .在一步操作中,你可以给 s 或者 t 追加 任一字符 . 返回使 s 和 t 互为 字母异位词 所需的最少步骤数. 字母异位词 指字母相同但是顺序不同(或者相同)的 ...

  5. 力扣 第314场周赛 Q3 使用机器人打印字典序最小的字符串【难度:中等,rating: 1953】(栈+贪心)

    题目链接 https://leetcode.cn/problems/using-a-robot-to-print-the-lexicographically-smallest-string/ 题目来源 ...

  6. 打印零与奇偶数(多线程)

    假设有这么一个类: class ZeroEvenOdd {public ZeroEvenOdd(int n) { ... } // 构造函数public void zero(printNumber) ...

  7. 20200502:力扣185周周赛下

    力扣185周周赛下 题目 思路与算法 代码实现 题目 数青蛙 生成数组 思路与算法 数青蛙:本题考查一个模拟过程,把青蛙的叫声设计出croak五个过程,必须同时出现这5个,才是一个青蛙的叫声,否则返回 ...

  8. 《LeetCode力扣练习》剑指 Offer 06. 从尾到头打印链表 Java

    <LeetCode力扣练习>剑指 Offer 06. 从尾到头打印链表 Java 一.资源 题目: 输入一个链表的头节点,从尾到头反过来返回每个节点的值(用数组返回). 示例 1: 输入: ...

  9. 力扣693.交替位二进制数

    题目描述 给定一个正整数,检查它的二进制表示是否总是 0.1 交替出现:换句话说,就是二进制表示中相邻两位的数字永不相同. 示例 1: 输入:n = 5 输出:true 解释:5 的二进制表示是:10 ...

  10. 剑指Offer Ⅱ 003.二进制加法(力扣剑指Offer专项突击版——整数_3)

    题目 给定一个非负整数 n ,请计算 0 到 n 之间的每个数字的二进制表示中 1 的个数,并输出一个数组. 示例 1: 输入: n = 2 输出: [0,1,1] 解释: 0 --> 0 1 ...

最新文章

  1. 计算机英语考试试题一附答案,计算机英语考试试题一附答案
  2. python中的引用_Python中的引用
  3. python中索引是从什么开始_python索引从0开始,那负数索引算什么?三秋道果说python...
  4. 《刺客信条:英灵殿》全面分析:浅谈公式化开放世界
  5. 17款开源论坛系统/Forum Software(转载)
  6. 01.HTML基础命令笔记
  7. time series 时间序列 | fractional factorial design 部分要因试验设计
  8. android recycleview长按多选_UI设计中Android和IOS设计差异总结
  9. 块状元素的居中,首先设置宽度,再设 margin: 0 auto
  10. ubuntu14.04下修改python默认版本
  11. 65. 布置行内脚本
  12. vb.net 如何连接Access数据库
  13. python 车辆识别_PythonAI应用(1)车辆识别
  14. MFC windows程序设计(第三版)课后习题第二章
  15. 几种反函数和差角公式的推导
  16. BZOJ2001 HNOI2010 城市建设
  17. Win7常见问题和技巧整
  18. sqlserver数据库账户登录18456错误怎么解决?
  19. 用vue2写一个新闻列表页,和新闻详情页,该怎么做?
  20. ssl证书购买后多久生效?ssl证书有效期多长时间

热门文章

  1. xls文件格式与扩展名不匹配php,excel表格的文件格式和扩展名不匹配怎么办
  2. VIOS查看网卡对应的插槽
  3. ubuntu16.04设置自启动wifi热点
  4. 第4节:alphapose项目运行和参数
  5. 网站广告的盈利模式详解
  6. Omni研究系列【USDT raw transaction】
  7. 称重管理系统方案之车牌识别摄像机的应用
  8. Frequency domain enhancement
  9. 清华姚班和100个“张小龙”| 中国AI天才养成计划
  10. 谈谈This对象的理解