说明
Java中,线程之间的通信主要是由java.lang.Object类提供的wait、notify和notifyAll这3个方法来完成:
①对象的wait方法被调用后,线程进入对象的等待队列中,并释放对象锁,其它线程可以竞争使用此对象锁;sleep方法使得一个线程进入睡眠状态,但是线程所占有的资源并没有释放。
②当对象的notify方法被调用,该方法会从对象的等待队列中随机取出一个线程来唤醒;notifyAll是唤醒等待队列中所有线程,这些线程会与其它正在执行的线程共同竞争对象锁。
③wait、notify和notifyAll这3个方法只能出现在synchronized作用的范围内。当多个线程等待同一对象,而它们等待等待的条件不同时,应该使用notifyAll方法。notifyAll会导致性能下降,因为不必要的线程也会被唤醒。而notify唤醒的线程有可能不是所期望的线程。
生产者与消费者问题
这里,将使用某类资源(用类Goods表示)的线程称为消费者Consumer,产生同类资源的线程称为Producer。要想使得Consumer和Producer能够协同工作,则它们应该遵循如下规则:
(1)只要缓冲区buffer有空间,生产者Producer就可向其中存放资源;当缓冲区buffer已满时,则让生产者Producer等待,放弃自己已获取的对象锁,进入等待队列;
(2)只要缓冲区中有资源可用,消费者Consumer就可以从buffer中取出资源;当buffer为空时,则让Consumer等待,放弃自己已获取的对象锁,进入等待队列;
(3)Producer和Consumer不能同时读、写buffer。所以对buffer进行操作的方法increase(生产资源)和decrease(消费资源)均需要使用synchronized进行同步。
/** * Goods类,表示共享资源 */ package com.hh.Producer.Consumer; public class Goods { private final int SIZE = 5; private int buffer = 0; /** * 共享资源增加 */ public synchronized int increase() { if (buffer < SIZE) { ++buffer; notify(); // 通知消费者可以消费 } else { try { wait(); // 生成者线程等待,直到消费者线程发出notify通知 } catch (InterruptedException e) { e.printStackTrace(); } } return buffer; } /** * 共享资源减少 */ public synchronized int decrease() { if (buffer > 0) { --buffer; notify(); // 通知生产者可以生产 } else { try { wait(); // 消费者线程等待,直到生产者线程发出notify通知 } catch (InterruptedException e) { e.printStackTrace(); } } return buffer; } public int getGoodsSize() { return SIZE; } }
/** * Producer类,模拟生产者线程 */ package com.hh.Producer.Consumer; public class Producer implements Runnable { private Goods goods; public Producer(Goods goods) { this.goods = goods; } @Override public void run() { while (true) { int goodsCount = goods.increase(); if (goodsCount != goods.getGoodsSize()) { System.out.println("生产者生产了一件商品,目前商品数:" + goodsCount); } else { System.out.println("商品已满,生产者等待"); } try { Thread.sleep((int) (Math.random() * 1000)); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } }
/** * Consumer类,模拟消费者 */ package com.hh.Producer.Consumer; public class Consumer implements Runnable { private Goods goods; public Consumer(Goods goods) { this.goods = goods; } @Override public void run() { while (true) { int goodsCount = goods.decrease(); if (goodsCount != 0) { System.out.println("消费者消费了一件商品,目前商品数:" + goodsCount); } else { System.out.println("商品已空,消费者等待"); } try { Thread.sleep((int) (Math.random() * 1000)); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } }
/** * 测试生产者Producer与消费者Consumer线程之间的通信 */ package com.hh.Producer.Consumer; public class TestMain { public static void main(String[] args) { Goods goods = new Goods(); Producer producer = new Producer(goods); Consumer consumer = new Consumer(goods); new Thread(producer).start(); new Thread(consumer).start(); } }
注意:是在共享资源Goods类中进行wait和notify操作,并不是在Producer或者Consumer类中。
对于这样的问题,一定要自己动手写示例代码,这样才能较好的理解线程之间的通信问题。
Java多线程--生产者与消费者问题,布布扣,bubuko.com
原文地址:http://blog.csdn.net/huhui_cs/article/details/38534313