前言
昨天看了一个三线程循环打印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锁 如此循环打印。