多线程交替打印问题
例如:建立三个线程A、B、C,A线程打印10次字母A,B线程打印10次字母B,C线程打印10次字母C,但是要求三个线程同时运行,并且实现交替打印,即按照ABCABCABC的顺序打印。
Lock锁方法实现
- 思路分析
通过ReentrantLock我们可以很方便的进行显式的锁操作,即获取锁和释放锁,对于同一个对象锁而言,统一时刻只可能有一个线程拿到了这个锁,此时其他线程通过lock.lock()来获取对象锁时都会被阻塞,直到这个线程通过lock.unlock()操作释放这个锁后,其他线程才能拿到这个锁。
public class PrintABC {
private int times;//控制打印的次数
private int state; //控制当前的状态保证之间交替打印
private Lock lock = new ReentrantLock();//保证每次只能一个线程能够拿到资源
public PrintABC(int times) {
this.times = times;
}
public void printA() {
print("A", 0);
}
public void printB() {
print("B", 1);
}
public void printC() {
print("C", 2);
}
private void print(String name, int targetState) {
for (int i = 0; i < times; ) {
lock.lock();
if (state % 3 == targetState) {
state++;
i++;
System.out.println("线程:" + name + ",第 " + i + " 打印");
}
lock.unlock();
}
}
public static void main(String[] args) {
PrintABC printABC = new PrintABC(10);
new Thread(printABC::printA).start();
new Thread(printABC::printB).start();
new Thread(printABC::printC).start();
}
}
使用Semaphore信号量实现
- 思路分析
直接使用 semaphore 中的 state 是否为1,为1时代表可执行。
public class PrintABC {
private int times;
private Semaphore semaphoreA = new Semaphore(1);
private Semaphore semaphoreB = new Semaphore(0);
private Semaphore semaphoreC = new Semaphore(0);
public PrintABC(int times) {
this.times = times;
}
public void printA() {
try {
print("A", semaphoreA, semaphoreB);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public void printB() {
try {
print("A", semaphoreB, semaphoreC);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public void printC() {
try {
print("A", semaphoreC, semaphoreA);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
private void print(String name, Semaphore current, Semaphore next) throws InterruptedException {
for (int i = 0; i < times; i++) {
current.acquire();
System.out.println("线程:" + name + ",第 " + i + " 打印");
next.release();
}
}
public static void main(String[] args) {
PrintABC printABC = new PrintABC(10);
new Thread(printABC::printA).start();
new Thread(printABC::printB).start();
new Thread(printABC::printC).start();
}
}
wait / notify 实现
- 思路分析
需要使用 synchronized 保证线程安全。
public class PrintABCUsingWaitNotify {
private int times;
private int state;
private Object objectA = new Object();
private Object objectB = new Object();
private Object objectC = new Object();
public PrintABCUsingWaitNotify(int times){
this.times = times;
}
public void printA(){
try {
print("A", 0, objectA, objectB);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public void printB(){
try {
print("B", 1, objectB, objectC);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public void printC(){
try {
print("C", 2, objectC, objectA);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public void print(String name, int targetState, Object current, Object next) throws InterruptedException {
for(int i = 0; i < times;){
// 锁定当前线程
synchronized(current){
while(state % 3 != targetState){
current.wait();
}
state++;
i++;
System.out.println("线程:" + name + ",第 " + i + " 打印");
synchronized(next){
// 通知下一个线程
next.notify();
}
}
}
}
public static void main(String[] args) {
PrintABCUsingWaitNotify printABC = new PrintABCUsingWaitNotify(10);
new Thread(printABC::printA).start();
new Thread(printABC::printB).start();
new Thread(printABC::printC).start();
}
}