编写一个程序,开启3个线程,这3个线程的ID分别为A、B、C,每个线程将自己的ID在屏幕上打印10遍,要求输出结果必须按ABC的顺序显示;如:ABCABC….依次递推。
我的思路是这样的:每个线程都有一个公用的锁,谁先拿到锁,谁就判断是不是该我输出ID,如果不是我输出,我就释放锁,并继续申请等待锁 (wait),如果是我输出,我就输出,并且释放锁并且唤醒那些正在等待申请锁的线程(notify),那如何控制 A->B->C->A这样的循环输出呢,因为被唤醒的线程是不确定的,如果A线程唤醒了C线程呢,那C线程必须判断是否输出,如果不该 轮到自己,就必须释放锁,而去唤醒别人,直到唤醒的线程就是B为止。
以下是我的实现:
public class ABCOutputThread implements Runnable{
private static String now = "A";
private final static String lock = "lock";
private String name,next;
public ABCOutputThread(String name,String next) {
this.name = name;
this.next = next;
}
@Override
public void run() {
int i=10;
while(i>0){
// System.out.print(this.name+" begin to get lock ");
synchronized (lock) {
// System.out.print(this.name+" get it ");
if(this.name.equals(now)){
// System.out.print(this.name+" my turn ");
System.out.print(this.name);
now = next;
--i;
// System.out.print(this.name+" notify other wait thread ");
try {lock.notifyAll();} catch (IllegalMonitorStateException e) {e.printStackTrace();}
}else{
// System.out.print(this.name+" not my turn and wait the other notify me ");
try {lock.wait();} catch (InterruptedException e) {e.printStackTrace();}
}
}
}
}
public static void main(String[] args) {
Thread t1 = new Thread(new ABCOutputThread("A","B"));
Thread t2 = new Thread(new ABCOutputThread("B","C"));
Thread t3 = new Thread(new ABCOutputThread("C","A"));
t1.start();
t2.start();
t3.start();
}
}
一开始我写的是lock.notify(),而不是lock.notifyAll(),以至于运行的时候只输出ABC,而没有循环10次的效果,但是debug下又能循环10次。这是为什么呢,后来在程序代码中加入了System.out.print调试语句,发现,notify只会唤醒一个线程,考虑这样一种场景:
1、A获得锁,成功输出A后释放了锁,唤醒一个线程
2、恰巧唤醒的是自己,发现不该轮到自己输出,就释放锁等待,但没有唤醒任何线程
3、同时BC在等待A唤醒,A没有唤醒任何人,它调用的是wait,故三个线程全部“睡着了”
notify是唤醒一个线程的意思,仅仅唤醒一个而已,唤醒的是别人还是自己,是不确定的,而如果notifyAll则会唤醒所有的线程,让所有的线程都有机会去争用锁,个人觉得这样做有浪费资源的嫌疑,接下来我会看看有没有办法就唤醒特定对象,做到精确唤醒。
baidu查过了,没有找到精确唤醒方式!!!!!!!!!!!!!!!