LeetCode:交替打印【1115】

题目描述

我们提供一个类:

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" 将被输出两次。

题目分析

  在解决1114问题按序打印时,我们曾引入了一个Java多线程工具类倒计时器(CountDownLatch),这里要介绍另外一个工具类信号量(Semaphore)。了解更多

  信号量(Semaphore)由一个值和一个指针组成,指针指向等待该信号量的进程。信号量的值表示相应资源的使用情况。信号量S≥0时,S表示可用资源的数量。

  信号量可以被两个操作修改:

  • 执行一次P操作意味着请求分配一个资源,因此S的值减1;当S<0时,表示已经没有可用资源,S的绝对值表示当前等待该资源的进程数。请求者必须等待其他进程释放该类资源,才能继续运行。
  • 执行一次V操作意味着释放一个资源,因此S的值加1;若S<0,表示有某些进程正在等待该资源,因此要唤醒一个等待状态的进程,使之运行下去。


注意:
信号量的值只能由PV操作来改变。

  我们可利用信号量来描述程序或语句之间的前趋关系

  设有两个并发执行的进程 P1 和 P2。 P1 中有语句 S1;P2 中有语句 S2。我们希望在 S1 执行后再执行 S2。为实现这种前趋关系, 我们只须使进程 P1 和 P2 共享一个公用信号量 S,并赋予其初值为 0,将 signal(S)操作放在 语句 S1 后面;而在 S2 语句前面插入 wait(S)操作,即

  • 在进程 P1 中,用 S1;signal(S);
  • 在进程 P2 中,用 wait(S);S2;

  由于 S 被初始化为 0,这样,若 P2 先执行必定阻塞,只有在进程 P1 执行完 S1;signal(S);操作后使 S 增为 1 时,
P2 进程方能执行语句 S2 成功

  回到题中,先Foo后Bar,添加信号量S2(值为1),先申请资源后再输出Foo,此时S2为0,循环暂停,暂停前需要让Bar有机会输出,所以添加信号量S1(值为0),每当Foo输出后,都释放资源,这样Bar就可以输出了。

Java题解

import java.util.concurrent.Semaphore;

class FooBar {
private Semaphore s1 = new Semaphore(0);
private Semaphore s2 = new Semaphore(1);
private int n; public FooBar(int n) {
this.n = n;
} public void foo(Runnable printFoo) throws InterruptedException { for (int i = 0; i < n; i++) {
// printFoo.run() outputs "foo". Do not change or remove this line.
s2.acquire();
printFoo.run();
s1.release();
}
} public void bar(Runnable printBar) throws InterruptedException { for (int i = 0; i < n; i++) {
// printBar.run() outputs "bar". Do not change or remove this line.
s1.acquire();
printBar.run();
s2.release();
}
}
}

  

最新文章

  1. Windows Azure Service Bus (6) 中继(Relay On) 使用VS2013开发Service Bus Relay On
  2. XAF应用开发教程(五)验证模块
  3. iOS10和Xcode8适配
  4. php 链接access数据库
  5. HTML5画布(圆形)
  6. jQuery源码笔记——准备
  7. Jquery的text()和html()方法在li与div取值结果解析
  8. Mysql笔记5之查询
  9. 【FPGA】高斯白噪声的Verilog实现
  10. 解决api、WebService跨域问题
  11. 庄博园的Mp4
  12. JVM Optimization
  13. hexo自动部署到git、ftp(虚拟主机等)、云服务器的方式
  14. LayoutParams继承于Android.View.ViewGroup.LayoutParams(转)
  15. e800. 监听JSlider的数值变化
  16. BZOJ 4197 NOI 2015 寿司晚宴 状压DP
  17. struts1和struts2比较
  18. RabbitMq初探——消息分发
  19. javascript 事件委托 event delegation
  20. discuz数据库迁移,改密码后,相关配置文件修改

热门文章

  1. idea-git同步服务器代码后撤销操作
  2. 018_Python3 模块
  3. A tow-day exam
  4. Vim颜色配置
  5. [SDOI2009][BZOJ 1876]SuperGCD
  6. CTYZ的树论赛(P5557 旅行/P5558 心上秋/P5559 失昼城的守星使)
  7. 记一次vue+vuex+vue-router+axios+elementUI开发(二)
  8. [提权]mysql中的UDF提权
  9. 三大框架 之 Struts2
  10. T-MAX--冲刺合集