# 1、使用三个线程按顺序打印ABC,循环打印10次
# 基础实现
使用三个线程按顺序打印ABC,并循环打印10次,可以通过以下方法实现:
# 实现逻辑
利用线程间通信机制,例如 synchronized
和 wait
/notify
,确保三个线程按照固定顺序执行。每个线程打印一个特定的字符后,通知下一个线程继续,形成循环。
# 完整代码
public class PrintABC {
private static final int MAX_PRINT_COUNT = 10; // 循环打印次数
private static int state = 0; // 线程状态,0表示打印A,1表示打印B,2表示打印C
public static void main(String[] args) {
Object lock = new Object();
Thread threadA = new Thread(() -> {
for (int i = 0; i < MAX_PRINT_COUNT; i++) {
synchronized (lock) {
while (state % 3 != 0) { // 轮到A打印
try {
lock.wait();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
System.out.print("A");
state++;
lock.notifyAll();
}
}
});
Thread threadB = new Thread(() -> {
for (int i = 0; i < MAX_PRINT_COUNT; i++) {
synchronized (lock) {
while (state % 3 != 1) { // 轮到B打印
try {
lock.wait();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
System.out.print("B");
state++;
lock.notifyAll();
}
}
});
Thread threadC = new Thread(() -> {
for (int i = 0; i < MAX_PRINT_COUNT; i++) {
synchronized (lock) {
while (state % 3 != 2) { // 轮到C打印
try {
lock.wait();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
System.out.print("C");
state++;
lock.notifyAll();
}
}
});
// 启动三个线程
threadA.start();
threadB.start();
threadC.start();
}
}
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
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
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
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
# 代码说明
- 状态控制:
- 使用
state
变量来控制打印的顺序:0 对应线程A打印,1 对应线程B打印,2 对应线程C打印。 - 每次打印完成后,状态加1,确保轮流打印。
- 使用
- 锁与线程通信:
- 使用
synchronized
关键字和wait
/notifyAll
方法实现线程通信。 - 当前线程执行时,其他线程阻塞,直到调用
notifyAll
唤醒。
- 使用
- 循环次数:
- 每个线程循环打印
MAX_PRINT_COUNT
次,保证打印完成10个“ABC”。
- 每个线程循环打印
# 输出结果
ABCABCABCABCABCABCABCABCABCABC
1
# 高级扩展
如果需要更灵活的实现,可以使用 ReentrantLock
和 Condition
,或者基于更高级的工具类如 Semaphore
或 CyclicBarrier
来实现类似功能。
以下是使用 ReentrantLock
和 Condition
实现的扩展版本,具有更高的灵活性和控制能力:
# 扩展-ReentrantLock
和 Condition
# 代码实现
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class PrintABCWithLock {
private static final int MAX_PRINT_COUNT = 10; // 循环打印次数
private static int state = 0; // 线程状态,0表示打印A,1表示打印B,2表示打印C
public static void main(String[] args) {
Lock lock = new ReentrantLock();
Condition conditionA = lock.newCondition();
Condition conditionB = lock.newCondition();
Condition conditionC = lock.newCondition();
Thread threadA = new Thread(() -> {
for (int i = 0; i < MAX_PRINT_COUNT; i++) {
lock.lock();
try {
while (state % 3 != 0) {
conditionA.await(); // 等待轮到A打印
}
System.out.print("A");
state++;
conditionB.signal(); // 通知线程B
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
} finally {
lock.unlock();
}
}
});
Thread threadB = new Thread(() -> {
for (int i = 0; i < MAX_PRINT_COUNT; i++) {
lock.lock();
try {
while (state % 3 != 1) {
conditionB.await(); // 等待轮到B打印
}
System.out.print("B");
state++;
conditionC.signal(); // 通知线程C
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
} finally {
lock.unlock();
}
}
});
Thread threadC = new Thread(() -> {
for (int i = 0; i < MAX_PRINT_COUNT; i++) {
lock.lock();
try {
while (state % 3 != 2) {
conditionC.await(); // 等待轮到C打印
}
System.out.print("C");
state++;
conditionA.signal(); // 通知线程A
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
} finally {
lock.unlock();
}
}
});
// 启动三个线程
threadA.start();
threadB.start();
threadC.start();
}
}
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
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
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
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
# 代码说明
ReentrantLock
和Condition
:- 使用
ReentrantLock
来控制线程同步,避免竞争条件。 - 每个线程有自己的
Condition
(如conditionA
、conditionB
和conditionC
),用于线程间的精确通信。
- 使用
- 状态控制:
- 通过
state % 3
判断当前轮到哪个线程执行,类似于之前的synchronized
版本。
- 通过
- 通知机制:
await()
:当前线程进入等待状态,直到被其他线程通过signal()
唤醒。signal()
:唤醒下一个线程,确保按顺序执行。
# 输出结果
ABCABCABCABCABCABCABCABCABCABC
1
# 扩展实现:使用 Semaphore
Semaphore
是一种信号量机制,也可以用来控制线程的执行顺序:
# 代码实现
import java.util.concurrent.Semaphore;
public class PrintABCWithSemaphore {
private static final int MAX_PRINT_COUNT = 10; // 循环打印次数
public static void main(String[] args) {
Semaphore semaphoreA = new Semaphore(1); // A线程初始可以运行
Semaphore semaphoreB = new Semaphore(0); // B线程初始阻塞
Semaphore semaphoreC = new Semaphore(0); // C线程初始阻塞
Thread threadA = new Thread(() -> {
for (int i = 0; i < MAX_PRINT_COUNT; i++) {
try {
semaphoreA.acquire(); // 获取许可
System.out.print("A");
semaphoreB.release(); // 通知线程B
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
});
Thread threadB = new Thread(() -> {
for (int i = 0; i < MAX_PRINT_COUNT; i++) {
try {
semaphoreB.acquire(); // 获取许可
System.out.print("B");
semaphoreC.release(); // 通知线程C
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
});
Thread threadC = new Thread(() -> {
for (int i = 0; i < MAX_PRINT_COUNT; i++) {
try {
semaphoreC.acquire(); // 获取许可
System.out.print("C");
semaphoreA.release(); // 通知线程A
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
});
// 启动三个线程
threadA.start();
threadB.start();
threadC.start();
}
}
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
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
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
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
# 扩展分析
ReentrantLock
vsSemaphore
:ReentrantLock
更灵活,可管理多个条件变量,适用于复杂线程间的精准通信。Semaphore
更简单,适合用于控制有限资源的访问和固定顺序的线程调度。
- 选择建议:
- 如果场景较复杂,推荐使用
ReentrantLock
和Condition
。 - 如果只需要简单的线程顺序控制,可以用
Semaphore
提高代码可读性。
- 如果场景较复杂,推荐使用