交替打印 ABC
如题。本文给出交替打印的代码示例,并解释了条件变量在代码实现中所起的作用。
使用三个线程,一个只负责打印A,另一个只负责打印B,最后一个只负责打印C
按顺序交替。即打印A后,才能打印B,打印B后,才能打印C
由于按序交替,最好采用条件队列来实现。初始时,只有打印A的条件满足 打印B、C的条件都不满足。A打印后,使得打印B的条件满足,同时打印A的条件由原来的满足变成不满足;B打印后,使得打印C的条件满足,同时打印B的条件由原来的满足变成不满足;C打印后,使得打印A的条件满足,同时打印C的条件由原来的满足变成不满足。
采用锁+条件队列实现的优势:
锁+条件队列是基于"通知-唤醒"机制实现的,比sleep+轮询的方式要高效。
完整代码如下:
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
/**
* @author psj
* @date 20-3-7
*/
public class PrintABC {
private ReentrantLock lock = new ReentrantLock();
//与锁关联的条件队列,当打印条件不满足时,挂起线程(通知唤醒机制,而不是sleep或者轮询)
private Condition printA = lock.newCondition();
private Condition printB = lock.newCondition();
private Condition printC = lock.newCondition();
//初始化 打印A的条件成立,打印B不成立,打印C不成立
private volatile boolean isA = true;
private volatile boolean isB = false;
private volatile boolean isC = false;
public static void main(String[] args) {
PrintABC pabc = new PrintABC();
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
while (true) {
try {
pabc.printA();
} catch (InterruptedException e) {
System.out.println(Thread.currentThread().getName() + " 退出打印");
break;
}
}
}
}, "t1");
Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
while (true) {
try {
pabc.printB();
} catch (InterruptedException e) {
//响应中断退出打印
System.out.println(Thread.currentThread().getName() + " 退出打印");
break;
}
}
}
}, "t2");
Thread t3 = new Thread(new Runnable() {
@Override
public void run() {
while (true) {
try {
pabc.printC();
} catch (InterruptedException e) {
System.out.println(Thread.currentThread().getName() + " 退出打印");
break;
}
}
}
}, "t3");
t2.start();
t3.start();
t1.start();
// sleepMills(10 * 1000);
// t1.interrupt();
}
public void printA() throws InterruptedException{
try {
lock.lock();
while (!isA) {
printA.await();
}
System.out.println(Thread.currentThread().getName() + " print A");
sleepMills(2000);
//A 已打印,将打印A的条件由原来的满足变成不满足
isA = false;
//将打印B的条件变成满足
isB = true;
//通知线程打印B
printB.signal();
}finally {
lock.unlock();
}
}
public void printB()throws InterruptedException {
try {
lock.lock();
while (!isB) {
printB.await();
}
System.out.println(Thread.currentThread().getName() + " print B");
//模拟方法执行耗时
sleepMills(2000);
//打印B的条件由满足变成不满足
isB = false;
//使得打印C的条件变成满足
isC = true;
printC.signal();
}finally {
lock.unlock();
}
}
public void printC()throws InterruptedException {
try {
lock.lock();
while (!isC) {
printC.await();
}
System.out.println(Thread.currentThread().getName() + " print C");
sleepMills(2000);
//C已打印,将打印C的条件由原来的满足变成不满足
isC = false;
//将打印A的条件变成满足
isA = true;
printA.signal();
}finally {
lock.unlock();
}
}
private static void sleepMills(long mills) {
try {
TimeUnit.MILLISECONDS.sleep(mills);
} catch (InterruptedException e) {
System.out.println(e);
}
}
}