借用用sleep方法影响cpu的执行,详细分析死锁、wait、notify
一个模拟stack类,用两个线程分别调用get和push方法【代码自己加】,此时(1)和(2)代码不能同时存在,如果都存在就会互相等待,无论后面有没有notify,程序卡住不动。
1,如果打开(1)的注释,同上,一定保证cup先调用get线程,因为有o1.wait(),程序会先执行push,再执行get,并且在push后要o1.notify();【即(4)代码不能注释】否则程序卡住。可以试试把(4)注释起来
2,如果没有保证cup先调用get线程,可以试着打开(7)的注释,此时尽管get线程先start,但实际上cpu并没有进入get代码块,是push线程先执行,也就是说此时o1.notify先于o1.wait执行,程序就只执行push,然后卡死,如果此时再打开(6),就又会执行push再执行get正常结束。
3,如果打开(5),程序会抛出java.lang.IllegalMonitorStateException异常,此时get线程的o1锁虽然已经wait,但push线程并没有持有o1锁,所以抛出异常,必须让代码执行到内层同步块,才能调用o1.notify,正常唤醒o1锁。
4,如果是push线程先start,就正好反过来,要注释掉(1)和(4),打开(2)和(3),此时程序因为在push代码块的第一层让o2.wait,所以程序会先执行get,哪怕在get中sleep,因为是在同步块中,cpu是不会跳出的,执行完之后再o2.notify,唤醒o2执行完push中剩下的内层代码块。
总之,多线程时程序一定是多个流程同时执行,当进入同步代码块的时候,就不会再跳出了,为了有可能出现的死锁(可能是W分之一),就要搞的这么复杂,实在是太不值了,还是尽量避免这样嵌套的情况发生吧
public class MyStack {
Object o1 = new Object();
Object o2 = new Object();
public void get() throws Exception {
//Thread.sleep(100);//(7)
synchronized (o1) {
o1.wait();//(1)
synchronized (o2) {
for (int i = 0; i < 10; i++) {
Thread.sleep(100);
System.out.println("这是get--" + i);
}
//o2.notify();//(3)
} } }
public void push() throws Exception {
synchronized (o2) {
//o1.notify();//(5)
//Thread.sleep(100);//(6)
//o2.wait();//(2)
synchronized (o1) {
for (int i = 0; i < 10; i++) {
System.out.println("这是push--" + i);
}
o1.notify();//(4)
} }
}
} |
|