传智播客-多线程(4)-线程间通信

来源:互联网 发布:车辆调度软件 编辑:程序博客网 时间:2024/06/04 23:35

在实际中有很多现实问题业务需求不仅需要多个线程访问同一共享资源,而且线程与线程之间还需要互相牵制,或者说协调合作,这种牵制/协调合作,我们可以理解为线程间的通信。

 

java中的线程间通信主要是靠Thread的三个方法实现:wait,notify,notifyAll。
wait:告诉当前线程放弃监视器并进入睡眠状态直到其他线程进入同一监视器并调用notify为止;
notify:唤醒同一对象监视器中调用wait的第一个线程。类似于饭馆有一个空位后通知所有等候就餐的顾客中的第一位可以入座。
从这两者的解释可以看出来,wait和notify肯定都是成对出现的。
notifyAll:唤醒同一对象监视器中调用wait的所有线程,具有最高优先级的线程首先被唤醒并执行。例如某个不定期的培训班终于招生满额后,通知所有学员都来上课。
该篇重点介绍前面两个方法的应用。

 

需要注意的是,上述三个方法都是指Object的方法,而不是作为Thread的方法。wait和notify都是在线程同步的时候调用以协调两个线程间的通信,所以这两个方法通常要写在同步代码块里,调用这两个方法的Object就是同步代码块里的监视器对象,也叫加锁对象。

 

一个经典的例子可以说明在java中如何实现线程的通信:生产者与消费者问题。

 

现实中的通常情况是,任何一种商品,得先由生产者生产出来,消费者才能够购买;而有了消费者的购买,生产者才会有动力继续生产。抽象到程序中,以一种极端的方式考虑:首先,生产者和消费者需要各自开启一个线程以代表各自的独立行为;生产者生产的商品应当存放在某一仓库中,然后消费者从该仓库中购买商品,这个仓库可以新建一个类表示;假设只有在仓库中没有商品的时候,生产者才会生产并将商品放入仓库,否则停止生产并等待,直到仓库中的产品被消费者全部取走为止;如果仓库中有商品,则消费者可以将商品取走,否则停止消费并等待,直到仓库中再次放入商品为止。仓库是生产者和消费者的共享资源,在程序中仓库对象即为监视器或者加锁对象;仓库中是否有商品需要有一种标识或者通知来告知生产者和消费者,以便他们的进一步行动,这个标识或通知在程序中用一个boolean变量表示;而生产者和消费者的等待和再次生产或购买的行为则需要利用wait和notify;由于生产者和消费者属于不同的线程,但是又必须使用同一个对象(仓库),因此创建关于生产者和消费者线程应当采用实现Runnable接口的方式。

 

下面的代码中,示例一采用的同步代码块实现;示例二采用的同步方法实现,而且更体现面向对象的思想,代码结构也更好。

 

示例一:

 

示例二:

原创粉丝点击