leetcode.1114-按序打印-多线程案例

简介: leetcode.1114-按序打印-多线程案例

题目


1114. 按序打印 - 力扣(Leetcode)

给你一个类:


public class Foo {

 public void first() { print("first"); }

 public void second() { print("second"); }

 public void third() { print("third"); }

}


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

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

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

提示:

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


解法一


先声明两个AtomicInteger变量并初始化为0,使用他来控制first()和second(),second() 和third()之间的顺序关系。

在进入second和third方法时,提前进入循环去检验变量是否被增加为1,如果是,则进入方法,否则空转。


1. class Foo {
2. 
3. private AtomicInteger firstJobDone = new AtomicInteger(0);
4. private AtomicInteger secondJobDone = new AtomicInteger(0);
5. 
6. public Foo() {}
7. 
8. public void first(Runnable printFirst) throws InterruptedException {
9. // printFirst.run() outputs "first".
10.     printFirst.run();
11. // mark the first job as done, by increasing its count.
12.     firstJobDone.incrementAndGet();
13.   }
14. 
15. public void second(Runnable printSecond) throws InterruptedException {
16. while (firstJobDone.get() != 1) {
17. // waiting for the first job to be done.
18.     }
19. // printSecond.run() outputs "second".
20.     printSecond.run();
21. // mark the second as done, by increasing its count.
22.     secondJobDone.incrementAndGet();
23.   }
24. 
25. public void third(Runnable printThird) throws InterruptedException {
26. while (secondJobDone.get() != 1) {
27. // waiting for the second job to be done.
28.     }
29. // printThird.run() outputs "third".
30.     printThird.run();
31.   }
32. }
33.

方法二


CountDownLatch(int count); //构造方法,创建一个值为count 的计数器。


//阻塞当前线程,将当前线程加入阻塞队列

//当计数器的值变为0时,在CountDownLatch上await()的线程就会被唤醒

await();


await(long timeout, TimeUnit unit);//在timeout的时间之内阻塞当前线程,时间一过则当前线程可以执行,


countDown();//对计数器进行递减1操作,当计数器递减至0时,当前线程会去唤醒阻塞队列里的所有线程。

在构造函数中使用 CountDownLatch()来说设置两个值为1的计数器,然后在second和third函数中加入awati()函数进行等待,当计数器为0时被唤醒

代码:


1. class Foo {
2. 
3. private final CountDownLatch firstDone;
4. private final CountDownLatch secondDone;
5. 
6. public Foo() {
7.         firstDone = new CountDownLatch(1);
8.         secondDone = new CountDownLatch(1);
9.     }
10. 
11. public void first(Runnable printFirst) throws InterruptedException {
12. // printFirst.run() outputs "first". Do not change or remove this line.
13.         printFirst.run();
14.         firstDone.countDown();
15.     }
16. 
17. public void second(Runnable printSecond) throws InterruptedException {
18.         firstDone.await();
19. // printSecond.run() outputs "second". Do not change or remove this line.
20.         printSecond.run();
21.         secondDone.countDown();
22.     }
23. 
24. public void third(Runnable printThird) throws InterruptedException {
25.         secondDone.await();
26. // printThird.run() outputs "third". Do not change or remove this line.
27.         printThird.run();
28.     }
29. }

方法三


使用信号量Semaphore ,先初始化信号量,不允许second和third函数运行,在first函数末尾调用release函数使得计数值加一,second函数可以运行;同理,在second函数结束后调用release函数增肌计数值,使得third()函数可以运行。


1. class Foo {
2. 
3. private Semaphore two = new Semaphore(0);
4. private Semaphore three = new Semaphore(0);
5. 
6. public Foo() {
7. 
8.     }
9. 
10. public void first(Runnable printFirst) throws InterruptedException {
11. 
12. // printFirst.run() outputs "first". Do not change or remove this line.
13.         printFirst.run();
14.         two.release();
15.     }
16. 
17. public void second(Runnable printSecond) throws InterruptedException {
18.         two.acquire();
19. // printSecond.run() outputs "second". Do not change or remove this line.
20.         printSecond.run();
21.         three.release();
22.     }
23. 
24. public void third(Runnable printThird) throws InterruptedException {
25.         three.acquire();
26. // printThird.run() outputs "third". Do not change or remove this line.
27.         printThird.run();
28.     }
29. }

方法四


使用object和synchronized进行原子操作


1. public class Foo {
2. private  int flag = 1;
3. private final Object object = new Object();
4. 
5. public Foo() {
6. 
7.     }
8. 
9. public void first(Runnable printFirst) throws InterruptedException {
10. synchronized (object) {
11. while (flag != 1) object.wait();
12.             printFirst.run();
13.             flag = 2;
14.             object.notifyAll();
15.         }
16.     }
17. 
18. public void second(Runnable printSecond) throws InterruptedException {
19. synchronized (object) {
20. while (flag != 2) object.wait();
21.             printSecond.run();
22.             flag = 3;
23.             object.notifyAll();
24.         }
25.     }
26. 
27. public void third(Runnable printThird) throws InterruptedException {
28. synchronized (object) {
29. while (flag != 3) object.wait();
30.             printThird.run();
31.         }
32. 
33.     }
34. }
目录
相关文章
|
16天前
|
安全 Java
Java多线程通信新解:本文通过生产者-消费者模型案例,深入解析wait()、notify()、notifyAll()方法的实用技巧
【10月更文挑战第20天】Java多线程通信新解:本文通过生产者-消费者模型案例,深入解析wait()、notify()、notifyAll()方法的实用技巧,包括避免在循环外调用wait()、优先使用notifyAll()、确保线程安全及处理InterruptedException等,帮助读者更好地掌握这些方法的应用。
13 1
|
2月前
|
数据采集 负载均衡 安全
LeetCode刷题 多线程编程九则 | 1188. 设计有限阻塞队列 1242. 多线程网页爬虫 1279. 红绿灯路口
本文提供了多个多线程编程问题的解决方案,包括设计有限阻塞队列、多线程网页爬虫、红绿灯路口等,每个问题都给出了至少一种实现方法,涵盖了互斥锁、条件变量、信号量等线程同步机制的使用。
LeetCode刷题 多线程编程九则 | 1188. 设计有限阻塞队列 1242. 多线程网页爬虫 1279. 红绿灯路口
|
6月前
|
设计模式 监控 Java
Java多线程基础-11:工厂模式及代码案例之线程池(一)
本文介绍了Java并发框架中的线程池工具,特别是`java.util.concurrent`包中的`Executors`和`ThreadPoolExecutor`类。线程池通过预先创建并管理一组线程,可以提高多线程任务的效率和响应速度,减少线程创建和销毁的开销。
188 2
|
6月前
|
安全 Java
Java多线程基础-10:代码案例之定时器(一)
`Timer` 是 Java 中的一个定时器类,用于在指定延迟后执行指定的任务。它常用于实现定时任务,例如在网络通信中设置超时或定期清理数据。`Timer` 的核心方法是 `schedule()`,它可以安排任务在延迟一段时间后执行。`
131 1
|
6月前
|
Java Python 开发者
Python 学习之路 01基础入门---【Python安装,Python程序基本组成】
线程池详解与异步任务编排使用案例-xian-cheng-chi-xiang-jie-yu-yi-bu-ren-wu-bian-pai-shi-yong-an-li
507 3
Python 学习之路 01基础入门---【Python安装,Python程序基本组成】
|
6月前
|
SQL Dubbo Java
案例分析|线程池相关故障梳理&总结
本文作者梳理和分享了线程池类的故障,分别从故障视角和技术视角两个角度来分析总结,故障视角可以看到现象和教训,而技术视角可以透过现象看到本质更进一步可以看看如何避免。
84760 136
案例分析|线程池相关故障梳理&总结
|
2月前
|
安全 Java 调度
python3多线程实战(python3经典编程案例)
该文章提供了Python3中多线程的应用实例,展示了如何利用Python的threading模块来创建和管理线程,以实现并发执行任务。
36 0
|
6月前
|
Python
Python学习之路 02 之分支结构
Python学习之路 02 之分支结构
488 0
Python学习之路 02 之分支结构
|
3月前
|
消息中间件 安全 Kafka
"深入实践Kafka多线程Consumer:案例分析、实现方式、优缺点及高效数据处理策略"
【8月更文挑战第10天】Apache Kafka是一款高性能的分布式流处理平台,以高吞吐量和可扩展性著称。为提升数据处理效率,常采用多线程消费Kafka数据。本文通过电商订单系统的案例,探讨了多线程Consumer的实现方法及其利弊,并提供示例代码。案例展示了如何通过并行处理加快订单数据的处理速度,确保数据正确性和顺序性的同时最大化资源利用。多线程Consumer有两种主要模式:每线程一个实例和单实例多worker线程。前者简单易行但资源消耗较大;后者虽能解耦消息获取与处理,却增加了系统复杂度。通过合理设计,多线程Consumer能够有效支持高并发数据处理需求。
157 4
|
6月前
|
Java
线程池详解与异步任务编排使用案例-xian-cheng-chi-xiang-jie-yu-yi-bu-ren-wu-bian-pai-shi-yong-an-li
线程池详解与异步任务编排使用案例-xian-cheng-chi-xiang-jie-yu-yi-bu-ren-wu-bian-pai-shi-yong-an-li
84 0