今天做了一个Leetcode题很有意思,有别于其他算法题,这是一个跟多线程相关的题,首先看一下题目:
我们提供了一个类:
public class Foo {
public void one() { print("one"); }
public void two() { print("two"); }
public void three() { print("three"); }
}
三个不同的线程将会共用一个 Foo 实例。
线程 A 将会调用 one() 方法
线程 B 将会调用 two() 方法
线程 C 将会调用 three() 方法
请设计修改程序,以确保 two() 方法在 one() 方法之后被执行,three() 方法在 two() 方法之后被执行。
这个题目的关键一目了然,就是如何保证三个线程按照指定的顺序去依次执行,即先执行A,然后B,最后C。
方法一
类似于cas自旋:
class Foo {
private volatile int a = 1;
public Foo() {
}
public void first(Runnable printFirst) throws InterruptedException {
// printFirst.run() outputs "first". Do not change or remove this line.
for(;;)
{
if(a==1)
{
printFirst.run();
a = 2;
break;
}
}
}
public void second(Runnable printSecond) throws InterruptedException {
// printSecond.run() outputs "second". Do not change or remove this line.
for(;;)
{
if(a==2)
{
printSecond.run();
a = 3;
break;
}
}
}
public void third(Runnable printThird) throws InterruptedException {
// printThird.run() outputs "third". Do not change or remove this line.
for(;;)
{
if(a==3)
{
printThird.run();
a = 1;
break;
}
}
}
}
方法二
使用关键字synchronized以及方法wait()和notify(),相当于设置了两道屏障:
class Foo {
boolean first_finished = false;
boolean second_finished = false;
Object lock = new Object();
public Foo() {
}
public void first(Runnable printFirst) throws InterruptedException {
// printFirst.run() outputs "first". Do not change or remove this line.
synchronized(lock)
{
printFirst.run();
first_finished = true;
lock.notifyAll();
}
}
public void second(Runnable printSecond) throws InterruptedException {
// printSecond.run() outputs "second". Do not change or remove this line.
synchronized(lock)
{
while(!first_finished)
{
lock.wait();
}
printSecond.run();
second_finished = true;
lock.notifyAll();
}
}
public void third(Runnable printThird) throws InterruptedException {
// printThird.run() outputs "third". Do not change or remove this line.
synchronized(lock)
{
while(!second_finished)
{
lock.wait();
}
printThird.run();
lock.notifyAll();
}
}
}
方法三
使用CountDownLatch这个类,用来计数需要等待线程的数量。
class Foo {
private CountDownLatch cnt_A = new CountDownLatch(1);
private CountDownLatch cnt_B = new CountDownLatch(1);
public Foo() {
}
public void first(Runnable printFirst) throws InterruptedException {
// printFirst.run() outputs "first". Do not change or remove this line.
printFirst.run();
cnt_A.countDown();
}
public void second(Runnable printSecond) throws InterruptedException {
// printSecond.run() outputs "second". Do not change or remove this line.
cnt_A.await();
printSecond.run();
cnt_B.countDown();
}
public void third(Runnable printThird) throws InterruptedException {
// printThird.run() outputs "third". Do not change or remove this line.
cnt_B.await();
printThird.run();
}
}