想要交替输出,两边线程就需要通信,因为只有两个线程分别调用两个方法,所以仅需要使用一个布尔类型的量作为信号即可,用flag的两种状态来分别限制两者,如果为真,foo线程等待 ,bra执行,执行完毕唤醒foo
如果为假,bar线程等待,foo执行,执行完毕唤醒bar
以下分别ReentrantLock和synchronized代码块来实现。
class FooBar {
private int n;
private ReentrantLock lock = new ReentrantLock();
private volatile boolean flag = false;
private Condition wait = lock.newCondition();
public FooBar(int n) {
this.n = n;
}
public void foo(Runnable printFoo) throws InterruptedException {
for (int i = 0; i < n; i++) {
lock.lock();
try{
while(flag){
wait.await();
}
// printFoo.run() outputs "foo". Do not change or remove this line.
printFoo.run();
flag = true;
wait.signal();
}finally{
lock.unlock();
}
}
}
public void bar(Runnable printBar) throws InterruptedException {
for (int i = 0; i < n; i++) {
lock.lock();
try{
while(!flag){
wait.await();
}
// printBar.run() outputs "bar". Do not change or remove this line.
printBar.run();
flag = false;
wait.signal();
}finally{
lock.unlock();
}
}
}
}
class FooBar {
private int n;
volatile boolean flag = false;
public FooBar(int n) {
this.n = n;
}
public void foo(Runnable printFoo) throws InterruptedException {
for (int i = 0; i < n; i++) {
synchronized(FooBar.class){
while(flag){
FooBar.class.wait();
}
// printFoo.run() outputs "foo". Do not change or remove this line.
printFoo.run();
flag = true;
FooBar.class.notify();
}
}
}
public void bar(Runnable printBar) throws InterruptedException {
for (int i = 0; i < n; i++) {
synchronized(FooBar.class){
while(!flag){
FooBar.class.wait();
}
// printBar.run() outputs "bar". Do not change or remove this line.
printBar.run();
flag = false;
FooBar.class.notify();
}
}
}
}
由于仅有两种状态两个线程,仅用一个volatile变量+sleep操作也不是不可以。毕竟这里的赋值操作时本身是原子的。
不过会比等待通知的写法慢,因为这里是存在两个线程来竞争且等待时间比较短用的是轻量级的锁(运气贼好的情况还可能用偏向锁(如果是那基本上阔以去买彩票了2333)),而第二种方法我人为的等待了1ms,所以会相对较慢。
class FooBar {
private int n;
volatile boolean flag = false;
public FooBar(int n) {
this.n = n;
}
public void foo(Runnable printFoo) throws InterruptedException {
for (int i = 0; i < n; i++) {
while(flag)Thread.sleep(1);
printFoo.run();
atomicBoolean = true;
}
}
public void bar(Runnable printBar) throws InterruptedException {
for (int i = 0; i < n; i++) {
while(!flag)Thread.sleep(1);
printBar.run();
atomicBoolean = false;
}
}
}
或者使用信号量(本质上是一个限定获取次数的共享锁(重入次数有限))。
慢于等待通知,快于第二种。
class FooBar {
private int n;
private Semaphore foo = new Semaphore(1);
private Semaphore bar = new Semaphore(0);
public FooBar(int n) {
this.n = n;
}
public void foo(Runnable printFoo) throws InterruptedException {
for (int i = 0; i < n; i++) {
foo.acquire();
printFoo.run();
bar.release();
}
}
public void bar(Runnable printBar) throws InterruptedException {
for (int i = 0; i < n; i++) {
bar.acquire();
printBar.run();
foo.release();
}
}
}