为了看一些synchronized相关的内容,查了网上的一些例子,然后糊涂了一个下午,最终搞懂了,作者可能是好心,但是感觉分析的不彻底,给看的人也容易造成困惑,把我的分析过程贴出来,本来代码比较乱,但分析的过程中收获了一些东西
网址如下:http://blog.csdn.net/hello_chillax/article/details/44992771
我的代码 稍微修改了下
package com.testSync; import java.text.SimpleDateFormat; import java.util.Date; /** * Created by CHENYUAN797 on 2017-06-13. */ public class JavaThread implements Runnable { // wait annotation-------------- // Causes the current thread to wait until another thread invokes the java.lang.Object.notify() method // or the java.lang.Object.notifyAll() method for this object. // In other words, this method behaves exactly as if it simply performs the call wait(0). // The current thread must own this object's monitor. // The thread releases ownership of this monitor and waits until // another thread notifies threads waiting on this object's monitor to wake up either // through a call to the notify method or the notifyAll method. // synchronized (obj) { // while (<condition does not hold>) // obj.wait(); // ... // Perform action appropriate to condition // } // This method should only be called by a thread that is the owner of this object's monitor. // See the notify method for a description of the ways in which a thread can become the owner of a monitor. // notify annotation------------ // Wakes up a single thread that is waiting on this object's monitor. // If any threads are waiting on this object, one of them is chosen to be awakened. // A thread waits on an object's monitor by calling one of the wait methods. // Only one thread at a time can own an object's monitor. private String name; private Object prev; private Object self; private JavaThread(String name, Object prev, Object self) { this.name = name; this.prev = prev; this.self = self; } @Override public void run() { int count = 3; while (count > 0) { synchronized (prev) { synchronized (self) { System.out.println(name); count--; self.notify(); Thread t=Thread.currentThread(); System.out.println(self+"notify-"+getStringDate()+"-"+t.getName()); } try { Thread t=Thread.currentThread(); System.out.println(prev+"wait-"+getStringDate()+"-"+t.getName()); prev.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } } } public String getStringDate() { Date currentTime = new Date(); SimpleDateFormat formatter = new SimpleDateFormat("HH:mm:ss"); String dateString = formatter.format(currentTime); return dateString; } public static void main(String[] args) throws Exception { Object a = "aaaa"; Object b = "bbbb"; Object c = "cccc"; JavaThread pa = new JavaThread("A", c, a); JavaThread pb = new JavaThread("B", a, b); JavaThread pc = new JavaThread("C", b, c); new Thread(pa).start(); Thread.sleep(2000); new Thread(pb).start(); Thread.sleep(2000); new Thread(pc).start(); } }
执行结果及分析如下:
A
aaaanotify-16:18:07-Thread-0
ccccwait-16:18:07-Thread-0
B
bbbbnotify-16:18:09-Thread-1
aaaawait-16:18:09-Thread-1
C
ccccnotify-16:18:11-Thread-2 激活ccccwait-16:18:07-Thread-0同时进入线程1
A 打印A
bbbbwait-16:18:11-Thread-2 同上面的ccccnotify-16:18:11-Thread-2在同一代码块内执行
aaaanotify-16:18:11-Thread-0 打印A 在同一代码块同时激活aaaawait-16:18:09-Thread-1
因为这段在线程0内执行,所以ccccwait-16:18:11-Thread-0
这一段理所当然要执行,又因为激活了a所以B要执行
B
ccccwait-16:18:11-Thread-0
bbbbnotify-16:18:11-Thread-1 这一段又激活了bbbbwait-16:18:11-Thread-2,然后继续执行Thread2里面的代码所以有下面的三段,如此往下推…
C
aaaawait-16:18:11-Thread-1
ccccnotify-16:18:11-Thread-2
A
bbbbwait-16:18:11-Thread-2
aaaanotify-16:18:11-Thread-0
B
ccccwait-16:18:11-Thread-0
bbbbnotify-16:18:11-Thread-1 这一段为什么看起来顺序有点不同,其实上面的notify 每个下面的三行都是并列运行的,毕竟是不同线程,
而且线程里也没有涉及耗时操作,所以乱序正常
C
ccccnotify-16:18:11-Thread-2
aaaawait-16:18:11-Thread-1
bbbbwait-16:18:11-Thread-2 这个程序的缺点,虽然调来调去,结果留下了一个永远关不上的线程在wait,程序其实没有结束
总结一下 这个示例就是把lock嵌套,希望通过连续冻结解冻来示意线程锁的机制,但其实最终线程有一个wait方法一直没有收到notify信号,程序没有关掉,举个例子,有个
客栈,有n间房,作者希望的是这n间房子里的人不停的与第n-1个人替换房间,但是第一个房子永远空着,第n个人永远没有房子,程序永远不能结束,永远敞开着。。。
作者的简化版如下:
package com.testSync; import javax.swing.*; import java.text.SimpleDateFormat; import java.util.Date; /** * Created by CHENYUAN797 on 2017-06-13. */ public class TestTwoLock implements Runnable { private String LOCK; private String LOCK1; public TestTwoLock(String LOCK, String LOCK1) { this.LOCK = LOCK; this.LOCK1 = LOCK1; } public static void main(String[] args) { Thread t = new Thread(new TestTwoLock("AAA","BBB")); t.start(); try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } Thread t1 = new Thread(new TestTwoLock("BBB","AAA")); t1.start(); try { Thread.sleep(10000); } catch (InterruptedException e) { e.printStackTrace(); } } @Override public void run() { synchronized (LOCK) { synchronized (LOCK1) { LOCK1.notify(); System.out.println(LOCK1+" notify--"+getStringDate()); } try { LOCK.wait(); System.out.println(LOCK+" wait--"+getStringDate()); } catch (InterruptedException e) { e.printStackTrace(); } } } public static String getStringDate() { Date currentTime = new Date(); SimpleDateFormat formatter = new SimpleDateFormat("HH:mm:ss"); String dateString = formatter.format(currentTime); return dateString; } }
结果如下:
BBB notify--16:40:42 AAA notify--16:40:44 AAA wait--16:40:44
这个容易懂一点 ,但是我有个疑问,这种synchronized代码块嵌套synchronized代码块在什么情况下用?都是一个线程,多级同步?互解锁?
tips:java 在debug机制下是单线程的,所以涉及到多线程的东西,最好打好log,走debug的话,你不知道进的是哪个线程。。。。