🌕 🌗 1114. 按序打印
2022年6月20日
- algorithm
🌕 🌗 1114. 按序打印
难度: 🌕 🌗
问题描述
解法 1 - ReentrantLock + Condition
class Foo {
private int flag; // 设置标志值,只有 == 对应标志值时,才能运行该线程
ReentrantLock lock;
Condition condition1;
Condition condition2;
Condition condition3;
public Foo() {
this.flag = 1;
this.lock = new ReentrantLock();
this.condition1 = lock.newCondition();
this.condition2 = lock.newCondition();
this.condition3 = lock.newCondition();
}
public void first(Runnable printFirst) throws InterruptedException {
// printFirst.run() outputs "first". Do not change or remove this line.
lock.lock();
try {
while(flag != 1) { // while 防虚假唤醒
condition1.await(); // 等待 & 释放锁
}
printFirst.run();
flag = 2;
// 如果 condition2 有节点,说明之前有线程先执行了 second 方法,并被送入了等待队列,需要唤醒
condition2.signal();
} finally {
lock.unlock(); // 释放锁
}
}
public void second(Runnable printSecond) throws InterruptedException {
// printSecond.run() outputs "second". Do not change or remove this line.
lock.lock();
try {
while(flag != 2) {
condition2.await();
}
printSecond.run();
flag = 3;
condition3.signal();
} finally {
lock.unlock();
}
}
public void third(Runnable printThird) throws InterruptedException {
// printThird.run() outputs "third". Do not change or remove this line.
lock.lock();
try {
while(flag != 3) {
condition3.await();
}
printThird.run();
flag = 0;
} finally {
lock.unlock();
}
}
}
输出 1
解法 2 - CountDownLatch
class Foo {
// method 2 - CountDownLatch
CountDownLatch c12; // 计数器,设置初始容量,当减到 0 时可以启动
CountDownLatch c23;
public Foo() {
c12 = new CountDownLatch(1);
c23 = new CountDownLatch(1);
}
public void first(Runnable printFirst) throws InterruptedException {
printFirst.run();
c12.countDown();
}
public void second(Runnable printSecond) throws InterruptedException {
c12.await(); // 阻塞直到 c12 == 0
printSecond.run();
c23.countDown();
}
public void third(Runnable printThird) throws InterruptedException {
c23.await();
printThird.run();
}
}
输出 2
解法 3 - Semaphore
class Foo {
// method 3 - Semaphore - 获取值,获取成功则执行
Semaphore s12;
Semaphore s23;
public Foo() {
s12 = new Semaphore(0);
s23 = new Semaphore(0);
}
public void first(Runnable printFirst) throws InterruptedException {
printFirst.run();
s12.release(); // 发放一个许可
}
public void second(Runnable printSecond) throws InterruptedException {
s12.acquire(); // 尝试获取一个许可,获取不到则阻塞等待
printSecond.run();
s23.release();
}
public void third(Runnable printThird) throws InterruptedException {
s23.acquire();
printThird.run();
}
}
输出 3
解法 4 - SynchronousQueue
class Foo {
// method 4 - SynchronousQueue 当里面有元素时,阻塞放入,只有里面的元素被 take() 时才能继续放入
BlockingQueue<Integer> queue12;
BlockingQueue<Integer> queue23;
public Foo() {
queue12 = new SynchronousQueue<>();
queue23 = new SynchronousQueue<>();
}
public void first(Runnable printFirst) throws InterruptedException {
printFirst.run();
queue12.put(1); // 随便放入一个元素
}
public void second(Runnable printSecond) throws InterruptedException {
queue12.take(); // 获取不到,则阻塞
printSecond.run();
queue23.put(1);
}
public void third(Runnable printThird) throws InterruptedException {
queue23.take();
printThird.run();
}
}