原题:
我们提供了一个类:
public class Foo {
public void first() { print("first"); }
public void second() { print("second"); }
public void third() { print("third"); }
}
三个不同的线程将会共用一个 Foo 实例。线程 A 将会调用 first() 方法
线程 B 将会调用 second() 方法
线程 C 将会调用 third() 方法
分析:目的是实现三个线程间的运行顺序控制,使用一个共享voaltile变量或者使用AtomicInteger都可以作为一个flag,各个线程通过这个flag来调度。这样各个线程中只有set和get操作,没有getAndOperate操作,个人认为没有必要加锁,用volatile变量在这正合适(volatile不保证原子性,不要用在i++等非原子操作上)。
代码如下,第一次在leetcode做多线程题纠结了好一会测试方法咋写,还是太菜了。。
static class Foo { private volatile int flag = 0; 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){ } // 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){ } // printThird.run() outputs "third". Do not change or remove this line. printThird.run(); } } //使用原子变量实现 // static class Foo { // private AtomicInteger flag = new AtomicInteger(0); // // public Foo() { // // } // // public void first(Runnable printFirst) throws InterruptedException { // // // printFirst.run() outputs "first". Do not change or remove this line. // printFirst.run(); // flag.set(1); // } // // public void second(Runnable printSecond) throws InterruptedException { // while (flag.get() !=1){ // } // // printSecond.run() outputs "second". Do not change or remove this line. // printSecond.run(); // flag.set(2); // } // // public void third(Runnable printThird) throws InterruptedException { // while (flag.get() !=2){ // } // // printThird.run() outputs "third". Do not change or remove this line. // printThird.run(); // } // // } public static void main(String[] args) throws InterruptedException { Foo foo = new Foo(); ExecutorService executorService = Executors.newFixedThreadPool(5); //匿名内部类写法 executorService.submit(new Runnable() { @Override public void run() { try { foo.first(new Runnable() { @Override public void run() { System.out.print("first"); } }); } catch (InterruptedException e) { e.printStackTrace(); } } }); //lambda表达式写法 executorService.submit(() -> { try { foo.second(() -> System.out.print("second")); } catch (InterruptedException e) { e.printStackTrace(); } }); executorService.submit(()->{ try { foo.third(()->System.out.print("third")); }catch (InterruptedException e) { e.printStackTrace(); } }); }
从AtomicInteger和volatile变量运行结果看,时间、消耗都相同,因为这里只用到了AtomicInteger的get和set方法,没有用到需要CAS的操作(当然这就是使用volatile的原因,如果有需要cas的操作那就不能用了),和直接用volatile变量其实是完全相同的。