[LeetCode] 1114. 按序打印(Easy)Java语言题解

1.题目相关

①题目及示例

Alt text
Alt text

②相关标签

  • 多线程

③题目地址


2.解题方法

①原子变量

  • 使用一个原子变量控制,把并发调用变成按顺序调用。

②volatile 关键字

  • 使用 volatile 关键字保证变量的可见性,把并发调用变成按顺序调用。

③信号量

  • 三个线程第一次执行时,因为 flag1 信号量和 flag2 信号量的计数器初始值都为 0,所以需要等 first 线程中释放了 flag1 信号量,second 线程才能开始执行,需要等 second 线程中释放了 flag2 信号量,third 线程才能开始执行。

④CountDownLatch

  • 两个 CountDownLatch 实例可以控制三个线程执行的先后顺序
  • 具体实现见代码

⑤CyclicBarrier

  • 两个 CyclicBarrier 实例可以控制三个线程执行的先后顺序
  • 具体实现见代码

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
// 1.使用一个原子变量控制,把并发调用变成按顺序调用。
class Foo {
private AtomicInteger n = new AtomicInteger(0);

public Foo() {
}

public void first(Runnable printFirst) throws InterruptedException {
printFirst.run();
n.incrementAndGet();
}

public void second(Runnable printSecond) throws InterruptedException {
// 等待第一个线程执行完毕
while (n.get() != 1) {
}
printSecond.run();
n.incrementAndGet();
}

public void third(Runnable printThird) throws InterruptedException {
// 等待第二个线程执行完毕
while (n.get() != 2) {
}
printThird.run();
}
}

②volatile 关键字

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
// 2.volatile关键字
class Foo {
private volatile int flag = 0;

public Foo() {
}

public void first(Runnable printFirst) throws InterruptedException {
printFirst.run();
flag = 1;
}

public void second(Runnable printSecond) throws InterruptedException {
// 等待第一个线程执行完毕
while (flag != 1) {}
printSecond.run();
flag = 2;
}

public void third(Runnable printThird) throws InterruptedException {
// 等待第二个线程执行完毕
while (flag != 2) {}
printThird.run();
}
}

③信号量

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
// 3.信号量(Semaphore)
class Foo {
private Semaphore flag1 = new Semaphore(0);
private Semaphore flag2 = new Semaphore(0);

public Foo() {
}

public void first(Runnable printFirst) throws InterruptedException {
printFirst.run();
// 释放flag1信号量的一个许可
flag1.release();
}

public void second(Runnable printSecond) throws InterruptedException {
// 获取flag1信号量的一个许可
flag1.acquire();
printSecond.run();
// 释放flag2信号量的一个许可
flag2.release();
}

public void third(Runnable printThird) throws InterruptedException {
// 获取flag2信号量的一个许可
flag2.acquire();
printThird.run();
}
}

④CountDownLatch

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
// 4.CountDownLatch
class Foo {
private CountDownLatch latch1 = new CountDownLatch(1);
private CountDownLatch latch2 = new CountDownLatch(1);

public Foo() {
}

public void first(Runnable printFirst) throws InterruptedException {
printFirst.run();
// 触发second线程执行
latch1.countDown();
}

public void second(Runnable printSecond) throws InterruptedException {
// 等待被触发
latch1.await();
printSecond.run();
// 触发third线程执行
latch2.countDown();
}

public void third(Runnable printThird) throws InterruptedException {
// 等待被触发
latch2.await();
printThird.run();
}
}

⑤CyclicBarrier

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
29
30
31
32
// 5.CyclicBarrier
class Foo {
private CyclicBarrier barrier1 = new CyclicBarrier(2);
private CyclicBarrier barrier2 = new CyclicBarrier(2);

public Foo() {
}

public void first(Runnable printFirst) throws InterruptedException {
try {
printFirst.run();
barrier1.await();
} catch (BrokenBarrierException e) {}
}

public void second(Runnable printSecond) throws InterruptedException {
try {
// 等待fisrt线程执行完printFirst.run();
barrier1.await();
printSecond.run();
barrier2.await();
} catch (BrokenBarrierException e) {}
}

public void third(Runnable printThird) throws InterruptedException {
try {
// 等待second线程执行完printSecond.run();
barrier2.await();
printThird.run();
} catch (BrokenBarrierException e) {}
}
}

附录

0%