今天来看一个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循环去掉。
动手写一下试一试吧。