一:问题描述
生活中很多事情都是有顺序的交互进行着,比如100个人去做地铁,安检的只负责安;只有安检通过了,才能排队刷卡进站;进站了,在对应线路站下排队才能进站。这就是一个典型的多任务有顺序的进行。对于每一个人来说都有顺序要经过这几步。
我们可以通过程序简单的抽象成,使用三个线程,每个线程分别只打印A、B、C. 依次打印出十组ABC.
二:实现思路:
这是一个典型的同步多条件的线程问题。同步肯定要用到Lock锁, 多条件就要用到Condition。
a)我们先抽象一个打印类,负责具体的A,B,C的打印.里边有个对象锁,同事有三个分支条件Condition,里边有一个变量代表当前打印的类型是A,B,C。打印具体的一个字母时候,判断下当前变量是不是这个字母的,不是就把当前条件挂起,是的话就执行打印,打印完唤起下一个条件。
public class PrintLog {
/**三种打印类型*/
public static final int TYPE_A = 0;
public static final int TYPE_B = 1;
public static final int TYPE_C = 2;
/**当前类型*/
private int curType = TYPE_A;
/**对象锁*/
private Lock lock = new ReentrantLock();
/**三个分支条件*/
private Condition condition1 = lock.newCondition();
private Condition condition2 = lock.newCondition();
private Condition condition3 = lock.newCondition();
/**
* 原理:执行方法前加上锁对象,执行完释放锁。 当前类型一致的话,直接执行,把类型重置为下一个条件,唤醒下一个锁条件;
* 类型不一样就让条件锁等待。
*/
public void printA() {
lock.lock();
try {
if (curType != TYPE_A) {
// 如果目前是非A的线程打印,A的线程要等待
condition1.await();
}else{
System.out.print("A");
curType = TYPE_B ;
//唤醒信号2
condition2.signal();
}
} catch (Exception e) {
}
lock.unlock();
}
public void printB() {
lock.lock();
try {
if (curType!= TYPE_B) {
condition2.await();
}else{
System.out.print("B");
curType = TYPE_C ;
condition3.signal();
}
} catch (Exception e) {
}
lock.unlock();
}
public void printC() {
lock.lock();
try {
if (curType != TYPE_C) {
condition3.await();
}else{
System.out.print("C");
curType = TYPE_A;
condition1.signal();
}
} catch (Exception e) {
}
lock.unlock();
}
}
b)创建一个线程对象,负责循环打印特定字母
public class ThreadPrint extends Thread {
public static final int PRINT_COUNT=5;
/**打印对象*/
private PrintLog printLog ;
/**打印类型*/
private int type = 0;
public ThreadPrint(PrintLog printLog , int type) {
super();
this.type = type ;
this.printLog = printLog;
}
@Override
public void run() {
for (int i = 0; i <10; i++) {
if (type ==PrintLog.TYPE_A) {
printLog.printA();
}else if(type==PrintLog.TYPE_B){
printLog.printB();
}else {
printLog.printC();
}
}
}
}
c)测试代码
public class PrintTest {
public static void main(String[] args) {
PrintLog printLog = new PrintLog() ;
Thread threadA = new ThreadPrint(printLog, PrintLog.TYPE_A);
Thread threadB = new ThreadPrint(printLog, PrintLog.TYPE_B);
Thread threadC = new ThreadPrint(printLog, PrintLog.TYPE_C);
threadA.start();
threadB.start();
threadC.start();
}
}