自我总结核心内容:线程之间的通信是通过具体对象来实现信息的交互的。而对象有wait和notafy方法,当一个线程调用了一个对象的wait方法,那么这个线程就处于暂停状态,如果另外一个线程调用了第一个线程对象的notify,那么含义就是说,我这个对象可以用了,那么所以调用我这个对象的线程,你们都可以继续执行你们的功能。但是需要注意,在线程waiti方法结束的时候,他必须要获得这个对象的锁,才可以退出wait方法。
对于wait,Notify,notifyall方法的总结:
共同点:这三个方法都必须在同步块里面执行,之所以这样设计,个人的理解是一个对象的状态不应该同时又多个线程在同时对他进行改变,必定是同一时刻只能有一个现成来处理,因此,如果线程之间的通信,对于对象来说,如果这个对象想让调用它的线程都先暂停一下,那么就把wati方法同步块里面,暂停之后,其他线程该做什么就做什么,该唤醒的唤醒,该做其他处理的就做其他处理。因此,不难可以总结出来,想让一些线程暂时停下,可以通过交互的对象来控制,也就是说,我这个对象调用wati了,那么你们一个个调用的线程,都按着顺序暂停下来。然后等着其他线程来调用我的notify唤醒方法,来唤醒你们,这样你们才可以继续运行,这就是线程之间的通信,当然,线程之间的通信,通过对象来实现,也是可以理解的,因为在面向对象的设计语言中,彼此之间事物的交互,也就是通过对象来完成。
下面对几个方法分别讲解:
第一:wait 我们知道,这几个方法,都在同步块里面执行,一旦一个线程执行到一个对象的wait方法,那么这个线程就会被暂停,也就是wait下面的方法不会执行了。如以下代码:
public class MonitorObject{ } public class MyWaitNotify{ MonitorObject myMonitorObject = new MonitorObject(); public void doWait(){ synchronized(myMonitorObject){ try{ myMonitorObject.wait();
System.out.println("wait is end");
} catch(InterruptedException e){...}
}
}
public void doNotify(){
synchronized(myMonitorObject){
myMonitorObject.notify();
}
}
}
也就是System.out.println("wait is end");这个方法不会执行,因为当前线程已经暂停,但是问题来了,从代码中发现,这个同步块synchronized并没有结束啊,既然同步块没有结束,那么这个对象的锁就没办法释放,而且一个对象也就一个同步锁,但是唤醒方法,也必须在当前对象的同步块里面执行,这样来推算,其他的现成都没法执行dotify方法了。
但是,java虚拟机并不会因此在违前面的所有涉及,规定在调用一个对象调用wait方法时候,第一:他能让当前调用的线程暂停;第二:他能让所有调用这个方法的线程释放了这个对象的锁,也就是说释放了所有持有这个对象的锁,等到他被唤醒,退出wati的时候,再重新获取这个对象锁。
所以这样的一种机制,其他的线程就可以执行唤醒操作了。
第二:notify 上面已经讲过,对象调用这个方法,他会唤醒引用当前对象的线程中的某一个线程,是他从暂停状态变成运行状态,当然是随机的
第三: NOtifyaLL 从字面上不能理解,他就是唤醒所有引用当前对象锁的现成,是他们变成运行状态、
第二部分:信号丢失
由于线程的执行时随机的,假设有四个线程调用对象的wati方法,也就是让这四个线程先休息一下,然后第五个线程可能需要处理一些东西,然后然第五个现成调用这个对象的Notify把你们都唤醒。理想中的设计是这样的,但是有可能第五个线程先执行了,当然此时并没线程执行wait方法,所以他虽然执行了唤醒操作,但是并没有唤醒任何线程,但是,对他来说无所谓,他已经完成了自己的任务了。可是,问题来了,由于缺少了唤醒操作的线程,所以前面四个线程调用wait的时候,都可能永远的处于等待状态,而没有人唤醒。
基于以上一种现象,我们事先方式是,如果第一个唤醒线程先执行了,我们可以设计一个信号量,表示已经线程已经执行过唤醒操作了,如以下代码:
public class MyWaitNotify2{ MonitorObject myMonitorObject = new MonitorObject(); boolean wasSignalled = false; public void doWait(){ synchronized(myMonitorObject){ if(!wasSignalled){ try{ myMonitorObject.wait(); } catch(InterruptedException e){...} } //clear signal and continue running. wasSignalled = false; } } public void doNotify(){ synchronized(myMonitorObject){ wasSignalled = true; myMonitorObject.notify(); } } }当第五个唤醒线程执行了Notify方法,他会把变量设置为true,那么这种情况,第一个wait线程执行的时候,他就不会执行wait里面的If语句,他会继续向下执行,然后把变量设为false,这样,其他的线程再来执行的时候,就全部都执行IF语句,最终暂停下来。如果wait方法线程块后面有很多的代码需要执行,这样就可以保证其他线程暂停,确定是,第一个执行wait的方法,依然会执行后面的重要代码。