按序打印(来源力扣):

题目描述:

给你一个类:

1
2
3
4
5
public class Foo {
public void first() { print("first"); }
public void second() { print("second"); }
public void third() { print("third"); }
}

三个不同的线程 A、B、C 将会共用一个 Foo 实例。

线程 A 将会调用 first() 方法
线程 B 将会调用 second() 方法
线程 C 将会调用 third() 方法
请设计修改程序,以确保 second() 方法在 first() 方法之后被执行,third() 方法在 second() 方法之后被执行。

提示:

尽管输入中的数字似乎暗示了顺序,但是我们并不保证线程在操作系统中的调度顺序。
你看到的输入格式主要是为了确保测试的全面性。

示例 1:

输入:nums = [1,2,3]
输出:"firstsecondthird"
解释:
有三个线程会被异步启动。输入 [1,2,3] 表示线程 A 将会调用 first() 方法,线程 B 将会调用 second() 方法,线程 C 将会调用 third() 方法。正确的输出是 "firstsecondthird"
示例 2:

输入:nums = [1,3,2]
输出:"firstsecondthird"
解释:
输入 [1,3,2] 表示线程 A 将会调用 first() 方法,线程 B 将会调用 third() 方法,线程 C 将会调用 second() 方法。正确的输出是 "firstsecondthird“。

提示:
nums 是 [1, 2, 3] 的一组排列。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
class Foo {
private CountDownLatch c2;
private CountDownLatch c3;
public Foo() {
c2 = new CountDownLatch(1);
c3 = new CountDownLatch(1);
}

public void first(Runnable printFirst) throws InterruptedException {

// printFirst.run() outputs "first". Do not change or remove this line.
printFirst.run();
c2.countDown();
}

public void second(Runnable printSecond) throws InterruptedException {
c2.await();
// printSecond.run() outputs "second". Do not change or remove this line.
printSecond.run();
c3.countDown();
}

public void third(Runnable printThird) throws InterruptedException {
c3.await();
// printThird.run() outputs "third". Do not change or remove this line.
printThird.run();
}
}
  • 解题思路:

    • countDownLatch计数器解决问题。

    • countDownLatch这个类使得一个线程一个线程等待其他线程执行完毕后再执行。

    • 通过一个计数器实现的。计数器的初始值是当前线程的数量,每当一个线程执行完毕后,计数器值减一,当计数器值为零时,表示所有线程执行完毕。

  • 具体实施:

    • 首先考虑使用一个线程安全的线程标记,选择了countDownLatch计数器。

    • 由题意得在线程1,2,3,不论谁先执行,都要使执行结果为first,second,third。

    • countDownLatch计数器的作用是初始化一个计数器数值指定,只有在该计数器值为0时才继续执行,所以先创建两个计数器c2是second的,c3是third的,初始化都为1.

    • 使用countDown(使当前计数器减一),方法在first执行后将c2的计数器置于0,在c2执行后将c3的计数器置于0.

    • 如果second,third先执行,在他们之中.await自己的计数器(如果当前计数器不为零,挂起,等待计数器为零后继续执行,否则会在此阻塞。调用await方法()会被挂起)。

    解题过程参考:力扣博主MOMENTUMxx