class Foo {
// 定义两个 CountDownLatch 对象,分别用于控制两次的顺序
private final CountDownLatch firstDone;
private final CountDownLatch secondDone;
// 构造函数
public Foo() {
firstDone = new CountDownLatch(1); // 用于等待 first 方法完成
secondDone = new CountDownLatch(1); // 用于等待 second 方法完成
}
// 第一个方法
public void first(Runnable printFirst) throws InterruptedException {
printFirst.run(); // 输出 "first"
firstDone.countDown(); // 调用完成后,减少计数器,通知等待的线程
}
// 第二个方法
public void second(Runnable printSecond) throws InterruptedException {
firstDone.await(); // 等待 firstDone 的计数器变为 0,即等待 first 方法完成
printSecond.run(); // 输出 "second"
secondDone.countDown(); // 完成后,减少计数器,通知等待的线程
}
// 第三个方法
public void third(Runnable printThird) throws InterruptedException {
secondDone.await(); // 等待 secondDone 的计数器变为 0,即等待 second 方法完成
printThird.run(); // 输出 "third"
}
}
class FooBar {
private int n; // 要打印的次数
private final Semaphore fooSemaphore = new Semaphore(1); // foo 方法的信号量,初始为 1,表示可以先执行 foo
private final Semaphore barSemaphore = new Semaphore(0); // bar 方法的信号量,初始为 0,表示初始情况下 bar 不可执行
// 构造函数,初始化打印次数
public FooBar(int n) {
this.n = n; // 设置要打印的次数
}
// foo 方法
public void foo(Runnable printFoo) throws InterruptedException {
for (int i = 0; i < n; i++) {
fooSemaphore.acquire(); // 获取 foo 的许可,如果没有许可则阻塞
printFoo.run(); // 调用传入的 Runnable,打印 "foo"
barSemaphore.release(); // 打印完成后,释放 bar 的许可,允许 bar 方法执行
}
}
// bar 方法
public void bar(Runnable printBar) throws InterruptedException {
for (int i = 0; i < n; i++) {
barSemaphore.acquire(); // 获取 bar 的许可,如果没有许可则阻塞
printBar.run(); // 调用传入的 Runnable,打印 "bar"
fooSemaphore.release(); // 打印完成后,释放 foo 的许可,允许 foo 方法执行
}
}
}
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
import java.util.function.IntConsumer;
class ZeroEvenOdd {
private final int n; // 要打印的最大数字
private final CyclicBarrier[] cbs = new CyclicBarrier[3]; // 用于控制线程同步的屏障
// 构造函数,初始化 n 和 CyclicBarrier
public ZeroEvenOdd(int n) {
this.n = n;
// 初始化每个屏障,等待两个线程
for (int i = 0; i < cbs.length; i++) {
cbs[i] = new CyclicBarrier(2);
}
}
// 打印0的方法
public void zero(IntConsumer printNumber) throws InterruptedException {
for (int i = 1; i <= n; i++) {
printNumber.accept(0); // 打印 0
try {
// 根据当前 i 的奇偶性决定等待 odd 还是 even
if (i % 2 == 1) {
cbs[1].await(); // 等待 odd 打印
} else {
cbs[2].await(); // 等待 even 打印
}
cbs[0].await(); // 等待下一轮的 0
} catch (BrokenBarrierException e) {
e.printStackTrace(); // 捕获并打印异常堆栈
}
}
}
// 打印偶数的方法
public void even(IntConsumer printNumber) throws InterruptedException {
for (int i = 2; i <= n; i += 2) {
try {
cbs[2].await(); // 等待 zero 打印 0
printNumber.accept(i); // 打印当前偶数
cbs[0].await(); // 等待下一轮的 0
} catch (BrokenBarrierException e) {
e.printStackTrace(); // 捕获并打印异常堆栈
}
}
}
// 打印奇数的方法
public void odd(IntConsumer printNumber) throws InterruptedException {
for (int i = 1; i <= n; i += 2) {
try {
cbs[1].await(); // 等待 zero 打印 0
printNumber.accept(i); // 打印当前奇数
cbs[0].await(); // 等待下一轮的 0
} catch (BrokenBarrierException e) {
e.printStackTrace(); // 捕获并打印异常堆栈
}
}
}
}
class H2O {
// 表示当前状态,0 代表可以产生氧气,1 和 2 代表产生了一个和两个氢原子的状态
private volatile int state = 0;
// 用于线程同步的对象
private Object obj = new Object();
public H2O() {
}
// 产生氢原子的方法
public void hydrogen(Runnable releaseHydrogen) throws InterruptedException {
// 对同步对象加锁
synchronized (obj) {
// 当状态为 2 时,说明已经有两个氢原子,需要等待氧气产生后才能继续产生氢原子
while (state == 2) {
obj.wait();
}
// 状态加一,表示产生了一个氢原子
state++;
// 执行产生氢原子的操作
releaseHydrogen.run();
// 通知其他等待的线程
obj.notifyAll();
}
}
// 产生氧气的方法
public void oxygen(Runnable releaseOxygen) throws InterruptedException {
// 对同步对象加锁
synchronized (obj) {
// 当状态不是 2 时,说明氢原子数量不足,需要等待氢原子产生到两个后才能产生氧气
while (state!= 2) {
obj.wait();
}
// 将状态重置为 0,表示可以继续产生氢原子和氧气的新循环
state = 0;
// 执行产生氧气的操作
releaseOxygen.run();
// 通知其他等待的线程
obj.notifyAll();
}
}
}
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
import java.util.function.IntConsumer;
class FizzBuzz {
private final int n; // 最大数字
private final ReentrantLock lock = new ReentrantLock(); // 用于控制线程间的访问
private int state = 0; // 状态变量,用于控制输出
private final Condition condition = lock.newCondition(); // 条件变量,用于线程之间的通知
// 构造函数,初始化最大数字 n
public FizzBuzz(int n) {
this.n = n;
}
// printFizz.run() 输出 "fizz"
public void fizz(Runnable printFizz) throws InterruptedException {
for (int i = 3; i <= n; i += 3) {
lock.lock(); // 获取锁
try {
// 跳过能被 15 整除的数字,因为它会被 fizzbuzz 方法处理
if (i % 3 == 0 && i % 5 == 0) continue;
// 等待状态变为 3,表示需要打印 "fizz"
while (state != 3) {
condition.await();
}
printFizz.run(); // 打印 "fizz"
state = 0; // 重置状态
condition.signalAll(); // 通知其他等待的线程
} finally {
lock.unlock(); // 解锁
}
}
}
// printBuzz.run() 输出 "buzz"
public void buzz(Runnable printBuzz) throws InterruptedException {
for (int i = 5; i <= n; i += 5) {
lock.lock(); // 获取锁
try {
// 跳过能被 15 整除的数字,因为它会被 fizzbuzz 方法处理
if (i % 3 == 0 && i % 5 == 0) continue;
// 等待状态变为 5,表示需要打印 "buzz"
while (state != 5) {
condition.await();
}
printBuzz.run(); // 打印 "buzz"
state = 0; // 重置状态
condition.signalAll(); // 通知其他等待的线程
} finally {
lock.unlock(); // 解锁
}
}
}
// printFizzBuzz.run() 输出 "fizzbuzz"
public void fizzbuzz(Runnable printFizzBuzz) throws InterruptedException {
for (int i = 15; i <= n; i += 15) {
lock.lock(); // 获取锁
try {
// 等待状态变为 15,表示需要打印 "fizzbuzz"
while (state != 15) {
condition.await();
}
printFizzBuzz.run(); // 打印 "fizzbuzz"
state = 0; // 重置状态
condition.signalAll(); // 通知其他等待的线程
} finally {
lock.unlock(); // 解锁
}
}
}
// printNumber.accept(x) 输出 "x",其中 x 是一个整数
public void number(IntConsumer printNumber) throws InterruptedException {
for (int i = 1; i <= n; i++) {
try {
lock.lock(); // 获取锁
// 等待状态为 0,表示可以打印数字
while (state != 0) {
condition.await();
}
// 检查 i 是否是 FizzBuzz 的情况
if (i % 3 != 0 && i % 5 != 0) {
printNumber.accept(i); // 打印数字
} else {
// 根据数字的特性设置状态
if (i % 3 == 0 && i % 5 == 0) state = 15; // 设置状态为方程的状态
else if (i % 3 == 0) state = 3; // 设置状态为打印 "fizz"
else if (i % 5 == 0) state = 5; // 设置状态为打印 "buzz"
condition.signalAll(); // 通知其他等待的线程
}
} finally {
lock.unlock(); // 解锁
}
}
}
}