线程通信——wait(),notify(),notifyAll()
wait():执行此方法,当前线程就会进入阻塞状态,并释放同步监视器(也可以理解成所持有的锁)
notify():执行此方法,会唤醒wait的一个线程,如果有多个线程被wait,就会唤醒优先级高的,如果优先级一致就随机唤醒一个
notifyAll():执行该方法,就会唤醒所有被wait的线程
注意:
1、wait()、notify()、notifyAll()三个方法必须使用在同步代码块或同步方法中
2、wait()、notify()、notifyAll()三个方法的调用者必须是同步代码块或同步方法中的同步监视器,否则会出现IllegalMonitorStateException异常
3、wait()、notify()、notifyAll()三个方法是定义在java.lang.Object类中。
原因:同步监视器可以使用任意类的对象充当,为了保证任何对象都能调用这三个方法,就必须将其放在Object中(Object是所有类的父类)
notify()
方法会唤醒对象条件队列中等待的某个线程,但是这个唤醒是无序的(和VM调度,OS调度有关,甚至底层是随机选取一个,更
甚至就是队列中的第一个)。 而如果,条件队列不断有新的线程进入,或者在唤醒的那一刻,刚好有其他线程抢入,那都可能导致某个运气不好的线程
迟迟不能被唤醒。 对这个线程来说,就是进入一种“饥饿”的状态,甚至还会有“饿死”的风险。
进程通信可能出现的问题——饥饿问题
在Java中,通常有以下几种情况导致饥饿:
- CPU被高优先级的线程完全占用(打满),而导致低优先级的线程一直没有机会获得CPU 解决方法:可以为每个线程单独设置一个优先级。 高优先级的线程可以获得更多CPU时间。 在Java中可以设置1~10个等级的优先级。 实际上,这个优先级等级依赖于具体的操作系统。 对于一般应用来说,保持默认的优先级,就可以了。
synchronized
同步块导致某个线程频繁重入(偏向锁,以及OS调度策略,导致已经获得monitor锁的线程有更多的机会再次获得锁),而导致其他线程只能阻塞等待- 某个线程在某个对象的条件队列上等待(
wait()
),而其他线程不断的抢入。