线程通信:生产者/消费者模式

---恢复内容开始---

线程是操作系统中独立的个体,但这些个体之间如果没有特殊的处理就不能成为一个整体。而线程间的通信机制就是成为整体的必用方案。线程间的通信会使系统的交互性更强,在提高CPU利用率的同时还会使程序员对各线程任务在处理的过程中进行有效的把控和监督。

等待/通知机制

线程之间不是独立的个体,而是通过等待和通知机制进行相互通信和协作。

等待/通知机制可以与生活中就餐时的场景类似。厨师和服务员之间的交互在“菜品传递台”上,过程如下:

  1. 厨师在做完一道菜的时间不定,所以厨师将完成的菜放到“菜品传递台”的时间也不定。
  2. 服务员在厨师将完成的菜放到“菜品传递台”之前处于“等待(wait)”状态。
  3. 服务员怎样取到菜?当厨师将完成的菜放到“菜品传递台”上,这相当于一种“通知(notify)”,这时服务员拿到菜交给就餐者。
  4. 在这个过程中,出现的就是“等待/通知”机制。

等待/通知的实现

wait,notify,notifyAll都是Object中的方法。

方法wait的作用:

  1. 使当前线程进行等待,wait方法将当前线程置于“预执行队列”中,并在wait所在代码行处停止执行,直到接到通知或被中断为止。
  2. 在调用wait之前,线程必须获取该对象的对象级别锁,即只能在同步方法或同步语句块中调用wait方法。如果调用wait方法时,没有持有适当的锁,则抛出IllegalMonitorStateException,它是RuntimeException的一个子类,不需try/catch捕获。
  3. 执行wait方法后,释放对象级别锁,不同于sleep,sleep不释放锁。
  4. 在wait方法返回前,线程与其他线程竞争得到锁。

方法notify的作用:

  1. 在调用notify之前,线程必须获取该对象的对象级别锁,即只能在同步方法或同步语句块中调用notify方法。如果调用notify方法时,没有持有适当的锁,则抛出IllegalMonitorStateException,它是RuntimeException的一个子类,不需try/catch捕获。同wait方法
  2. 该方法用来通知那些可能等待的该对象的对象锁的其他线程。如果有多个线程等待,则由线程规划器随机挑选一个成wait状态的线程,对其通知唤醒。类比ReentrantLock,可以用condition对象通知唤醒制定线程。
  3. notify在通知后,不会立即释放对象锁,外套也不能马上获取对象锁,要等待notify所在的同步方法或同步代码块执行完毕,(退出synchronized代码块后)释放锁。由于notify唤醒了处于wait状态的线程,使其进入就绪状态。被重新唤醒的线程会试图重新获取临界区的权限,也就是锁,并继续执行临界区内wait之后的代码,执行完毕后,释放锁。此时如果“预执行队列”中还有其他wait线程,则需要再次使用notify语句,否则wait状态的线程由于没有得到该对象的通知,仍旧阻塞在wait状态,知道该对象发出notify或notifyAll通知。

简而言之,wait方法可以使调用该方法的线程释放共享资源的锁,然后从运行状态退出,进入等待序列,直到被唤醒。wait(long)等待一段时间内是否有线程对锁进行唤醒,如果超过这个时间自动唤醒。notify方法可以随机唤醒等待序列中等待同一共享资源的“一个”线程,使该线程退出等待序列,进入可运行状态,仅通知一个线程。notifyAll方法可以随机唤醒等待序列中等待同一共享资源的“全部”线退出等待序列,进入可运行状态,优先级高的最先执行或随机选择执行由JVM决定。

每个锁对象有两个队列,一个是就绪队列,一个是阻塞队列。一个线程被唤醒后进入绪队列,等待CPU调度。一个线程被wait后,进入阻塞队列,等待下一次唤醒。

等待/通知机制实现案例:生产者/消费者模式

 等待/通知机制最经典的案例就是“生产者/消费者”模式。但有一生产一消费,多生产多消费,一生产多消费,多生产一消费四种变形。将在下一篇中持续更新。

 

 

 

        

 

 

 

        

        

 

---恢复内容结束---

posted @ 2017-05-09 14:34  傑0327  阅读(199)  评论(0编辑  收藏  举报