算法学习 leetcode1114题 线程按序打印

今天来看一个leetcode线程顺序同步题。

demo类:

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() 方法之后被执行。

示例 1:

输入: [1,2,3]
输出: “onetwothree”
解释:
有三个线程会被异步启动。
输入 [1,2,3] 表示线程 A 将会调用 one() 方法,线程 B 将会调用 two() 方法,线程 C 将会调用 three() 方法。
正确的输出是 “onetwothree”。

我的截图思路是,用两个volatile变量来实现线程间的顺序控制,因为volatile有两个作用,一个是禁用指令重排,一个是当某个使用了volatile声明的变量的值发生改变,会在引用的线程间进行通知,让所有线程能感知到这个值的变化,所以volatile可以用在线程间的状态同步(注意:但是不能用在多线程共享变量计算,比如int i=0,int++,volatile依然保证不了线程安全)

Java代码如下:

package com.example.demo;

public class Solution1114{

    volatile boolean firstFlag = false;
    volatile boolean secondFlag = false;

    public Solution1114() {

    }

    public void first(Runnable printFirst) throws InterruptedException {
        // printFirst.run() outputs "first". Do not change or remove this line.
        printFirst.run();
        firstFlag = true;
    }

    public void second(Runnable printSecond) throws InterruptedException {
        while(!firstFlag) {

        }
        // printSecond.run() outputs "second". Do not change or remove this line.
        printSecond.run();
    }

    public void third(Runnable printThird) throws InterruptedException {
        while(!secondFlag) {

        }
        // printThird.run() outputs "third". Do not change or remove this line.
        printThird.run();

    }
}

这里用到了这两个volatile变量,来控制第二和第三个线程的执行顺序

    volatile boolean firstFlag = false;
    volatile boolean secondFlag = false;

其实Java中还有多种解法,比如还有CountDownLatch,这个的解法也非常优雅。CountDownLatch正如名字一样,倒数栓,也就是初始CountDownLatch时,指定要倒数几个线程,每个线程执行完就执行countDown(),CountDownLatch就会从倒数的线程数中减掉一个,直到减为0,那么同步通知就结束了。

声明两个

private CountDownLatch s2;
private CountDownLatch t3;

在方法first()和second()的末尾,把“firstFlag = true;”替换为“c2.countDown();”和“c3.countDown();”,最后把second和third方法中的while循环去掉。

动手写一下试一试吧。