1. 按序打印
- 方法1:无锁的方法:使用volatile+自旋
class Foo {
volatile int flag;
public Foo() {
}
public void first(Runnable printFirst) throws InterruptedException {
// printFirst.run() outputs "first". Do not change or remove this line.
printFirst.run();
flag = 1;
}
public void second(Runnable printSecond) throws InterruptedException {
while (flag != 1) {
Thread.yield();
}
// printSecond.run() outputs "second". Do not change or remove this line.
printSecond.run();
flag = 2;
}
public void third(Runnable printThird) throws InterruptedException {
while (flag != 2) {
Thread.yield();
}
// printThird.run() outputs "third". Do not change or remove this line.
printThird.run();
}
}
方法一的volatile变量也可以换成原子自增类AtomicInteger。
这里因为没有多线程同时写,所以flag++也可以。
方法2:使用信号量
private Semaphore two = new Semaphore(0);
private Semaphore three = new Semaphore(0);
public Foo() {
}
public void first(Runnable printFirst) throws InterruptedException {
// printFirst.run() outputs "first". Do not change or remove this line.
printFirst.run();
two.release();
}
public void second(Runnable printSecond) throws InterruptedException {
two.acquire();
// printSecond.run() outputs "second". Do not change or remove this line.
printSecond.run();
three.release();
}
public void third(Runnable printThird) throws InterruptedException {
three.acquire();
// printThird.run() outputs "third". Do not change or remove this line.
printThird.run();
}
方法3 使用条件变量/wait, notifyAll
class Foo {
int flag;
public Foo() {
}
public void first(Runnable printFirst) throws InterruptedException {
// printFirst.run() outputs "first". Do not change or remove this line.
synchronized(this) {
printFirst.run();
flag = 1;
notifyAll();
}
}
public void second(Runnable printSecond) throws InterruptedException {
// printSecond.run() outputs "second". Do not change or remove this line.
synchronized(this) {
while (flag != 1) {
wait();
}
printSecond.run();
flag = 2;
notifyAll();
}
}
public void third(Runnable printThird) throws InterruptedException {
synchronized(this) {
while (flag != 2) {
wait();
}
printThird.run();
}
// printThird.run() outputs "third". Do not change or remove this line.
}
}
方法3可能写出错误的代码,注意点1:必须得加一个flag防止调度时线程1先执行唤醒,线程2然后在wait。这样线程2将永远沉睡。注意点2:flag变量的更新必须在notifyAll()前面。
方法4: 使用CountDownLatch与CyclicBarrier也可以。但是得设置2个,此处不表。
1115
方法1:无锁
class FooBar {
private int n;
int flag = 1;
public FooBar(int n) {
this.n = n;
}
public void foo(Runnable printFoo) throws InterruptedException {
for (int i = 0; i < n; i++) {
while (flag != 1) {
Thread.yield();
}
// printFoo.run() outputs "foo". Do not change or remove this line.
printFoo.run();
flag = 2;
}
}
public void bar(Runnable printBar) throws InterruptedException {
for (int i = 0; i < n; i++) {
while (flag != 2) {
Thread.yield();
}
// printBar.run() outputs "bar". Do not change or remove this line.
printBar.run();
flag = 1;
}
}
}
方法2:使用2个信号量
class FooBar {
private int n;
Semaphore f = new Semaphore(1);
Semaphore b = new Semaphore(0);
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.
f.acquire();
printFoo.run();
b.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.
b.acquire();
printBar.run();
f.release();
}
}
}
其他方法,条件变量,CountDownLatch, CyclicBarrier。不赘述
1116. 打印零与奇偶数
自旋
class ZeroEvenOdd {
private int n;
volatile int zero = 1, flag = -1;
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 = 0; i < n; i++) {
while (zero != 1) {
Thread.yield();
}
printNumber.accept(0);
zero = 0;
flag ++;
}
}
public void even(IntConsumer printNumber) throws InterruptedException {
for (int i = 2; i <= n; i += 2) {
while (flag != 2) {
Thread.yield();
}
printNumber.accept(i);
flag = -1;
zero = 1;
}
}
public void odd(IntConsumer printNumber) throws InterruptedException {
for (int i = 1; i <= n; i += 2) {
while (flag != 0) {
Thread.yield();
}
printNumber.accept(i);
flag = 1;
zero = 1;
}
}
}
条件变量
与无锁几乎没区别。只是把自旋换成了阻塞。
class ZeroEvenOdd {
private int n;
volatile int zero = 1, flag = -1;
public ZeroEvenOdd(int n) {
this.n = n;
}
// printNumber.accept(x) outputs "x", where x is an integer.
public synchronized void zero(IntConsumer printNumber) throws InterruptedException {
for (int i = 0; i < n; i++) {
while (zero != 1) {
wait();
}
printNumber.accept(0);
zero = 0;
flag ++;
notifyAll();
}
}
public synchronized void even(IntConsumer printNumber) throws InterruptedException {
for (int i = 2; i <= n; i += 2) {
while (flag != 2) {
wait();
}
printNumber.accept(i);
flag = -1;
zero = 1;
notifyAll();
}
}
public synchronized void odd(IntConsumer printNumber) throws InterruptedException {
for (int i = 1; i <= n; i += 2) {
while (flag != 0) {
wait();
}
printNumber.accept(i);
flag = 1;
zero = 1;
notifyAll();
}
}
}
1117. H2O 生成
无锁方式没写出来,应该没有办法无锁。
class H2O {
Semaphore h = new Semaphore(2);
Semaphore o = new Semaphore(0);
public H2O() {
}
public void hydrogen(Runnable releaseHydrogen) throws InterruptedException {
h.acquire();
// releaseHydrogen.run() outputs "H". Do not change or remove this line.
releaseHydrogen.run();
if (h.availablePermits() == 0) {
o.release();
}
}
public void oxygen(Runnable releaseOxygen) throws InterruptedException {
o.acquire();
// releaseOxygen.run() outputs "O". Do not change or remove this line.
releaseOxygen.run();
h.release(2);
}
}