问题:如何实现三个线程交替循环打印?
示例:线程1打印A,线程2打印B,线程3打印C,要求交替打印,并且可以循环打印。
输出结果类似:ABCABCABC
这道题的难度是五颗星,在面试中也会经常遇到,如果是第一次见到这道题,很难在短时间内想出合理的解决方案。
如果只要求交替打印一次的话,实现比较简单,可以用Thread.join()方法,一个线程等待另一个线程执行完成。
现在要求循环打印,就涉及线程间通信,必须要用到锁,一把锁肯定不够。例如线程1释放锁之后,线程2和线程3都可能获取到锁,是随机的,现在要求必须是线程2获取到锁,所以需要三把锁。
执行过程:
线程1获取A锁,打印A,释放B锁;
线程2获取B锁,打印B,释放C锁;
线程3获取C锁,打印C,释放A锁;
循环执行;
可以用Synchronized或者ReentrantLock实现,不过它们不能控制线程启动后的执行顺序。因为三个线程启动后,都等待CPU调度执行,而CPU调度的顺序又是随机的,所以不能保证线程1先执行。
有个可以控制线程启动后执行顺序,又简单的实现方式,就是用Semaphore(信号量),它可以控制共享资源的访问个数。
使用方式:
初始化的时候,指定共享资源的个数
// 初始化一个资源 Semaphore semaphore = new Semaphore(1);
- 获取资源,获取资源后,semaphore资源个数减1,变成0,其他线程再获取资源的时候就会阻塞等待
semaphore.acquire();
- 释放资源,semaphore资源个数加1,其他阻塞的线程就可以获取到资源了
semaphore.release();
代码实现:
/**
* @author yideng
* @apiNote 三个线程循环打印
*/
public class CirclePrint {
static class ThreadDemo extends Thread {
private Semaphore current;
private Semaphore next;
private String name;
/**
* 构造方法
* @param current 要获取的当前锁
* @param next 要释放的下一把锁
* @param name 打印内容
*/
public ThreadDemo(Semaphore current, Semaphore next, String name) {
this.current = current;
this.next = next;
this.name = name;
}
@Override
public void run() {
for (int i = 0; i < 5; i++) {
try {
// 获取当前锁,然后打印
current.acquire();
System.out.print(name);
} catch (InterruptedException e) {
e.printStackTrace();
}
// 释放下一把锁
next.release();
}
}
}
public static void main(String[] args) {
// 初始化三把锁,只有A锁是可用的
Semaphore A = new Semaphore(1);
Semaphore B = new Semaphore(0);
Semaphore C = new Semaphore(0);
// 创建并启动三个线程,线程1获取A锁,释放B锁
new ThreadDemo(A, B, "A").start();
// 线程2获取B锁,释放C锁
new ThreadDemo(B, C, "B").start();
// 线程3获取C锁,释放A锁
new ThreadDemo(C, A, "C").start();
}
}
输出结果:
ABCABCABCABCABC
你觉得怎么样?有更简单的解决方案吗?
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。