LeetCode1114.按序打印 Java实现及测试方法

原题:

我们提供了一个类:

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变量其实是完全相同的。

原文地址:https://www.cnblogs.com/pauljoyce/p/13646181.html