前言
昨天看了一个三线程循环打印ABC的经典例子,看了很多博客感觉都没有讲清楚具体的执行流程,而且对于方法的解释也是没有完全没有解释好,和朋友讨论解决了这个问题,写下这篇博客,来解释三线程同步打印的问题,所以不能完全相信博客的解释,最好还是看官方的注释和源码。
先上实例以及输出
public class HjsjyThread implements Runnable {
private String name;
private Object prev;
private Object self;
private HjsjyThread(String name, Object prev, Object self) {
this.name = name;
this.prev = prev;
this.self = self;
}
@Override
public void run() {
int count = 10;
while (count > 0) {
synchronized (prev) {
synchronized (self) {
System.out.print(name);
count--;
try{
Thread.sleep(1);
}
catch (InterruptedException e){
e.printStackTrace();
}
self.notify();
}
try {
prev.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public static void main(String[] args) throws Exception {
Object a = new Object();
Object b = new Object();
Object c = new Object();
HjsjyThread pa = new HjsjyThread("A", c, a);
HjsjyThread pb = new HjsjyThread("B", a, b);
HjsjyThread pc = new HjsjyThread("C", b, c);
new Thread(pa).start();
Thread.sleep(100);
new Thread(pb).start();
Thread.sleep(100);
new Thread(pc).start();
Thread.sleep(100);
}
}
//输出:ABCABCABCABCABCABCABCABCABCABC
主要问题
- notify()的解释 (重要)
我先搬出源码上的注释
Wakes up a single thread that is waiting on this object’s monitor. if any thread are waiting on this object ,one of them is chosen to be awakened.
这段英文还是挺简单的 唤醒任意一个 正在等待当前对象的waiting线程,重点就是在这个正在等待当前对象这句话,这是第一个作用,另外notify()并不是立刻释放对象锁,而是要等出临界区 也就是在这个例子里面的内synchronized。出去之后线程才会释放对象锁
- wait()
wait也是有两个作用,一个是使当前线程进入等待状态,二是使当前对象锁立刻释放。
执行流程
主线程开启,执行A线程,获得 c, a锁, 输出A count为9,这时self.notify()也就是a.notify(),当前没有正在等待a对象锁的wait 线程所以只有释放锁的作用,接着执行 c.wait() ,释放c锁,并且让当前线程也就是A线程等待,接着执行B线程 B线程等待A锁的释放(因为notify()不是立刻释放锁的,具体可以看上面notify 方法的解释),得到a ,b锁之后输出B count=9,执行b.notify(),也没有当前wait 等待b锁的wait线程 所以也有释放锁的功能,接着a.wait,b线程d等待 立刻释放锁a,接着执行C线程,需要等待B线程释放b锁,得到b c锁执行,输出C然后count=9,然后c.notify() 当前有正在等待c的wait线程 也就是A线程,C线程执行b.wait 让C线程d等待并且立刻释放b锁,A需要等待C线程释放c锁 如此循环打印。