生产者、消费者

并发编程中的一个经典问题就是生产者与消费者问题。它描述是有一块缓冲区作为仓库,生产者可以将产品放入仓库,消费者则可以从仓库中取走产品。
由于仓库是一个共享的数据结构,我们必须采用同步机制,比如synchronized关键字来控制对它的访问。但是我们有更多的限制因素,如果仓库是满的,生产者不能存放产品,如果仓库是空的,消费者不能取出产品。
对于这些类型的情况,Java在Object对象中提供wait(),notify(),和notifyAll() 方法的实现。这样,我们就可以为任何对象实现同步机制。

  • wait():当仓库已满/空时,生产者/消费者线程停止自己的执行,放弃锁,使自己处于等待状态,让其他线程执行。
  • notify():当生产者/消费者向仓库放入/取出一个产品时,向其他等待的线程发出可执行的通知,同时放弃锁,使自己处于等待状态。
  • notifyAll():同notify(),通知所有等待的线程。

一个线程必须在synchronized代码块中调用wait()方法。如果在synchronized代码块外部调用wait()方法,JVM会抛出IllegalMonitorStateException异常。下面看看示例代码:

/**
 * 仓库类
 */
public class Storage {

    private int maxSize;
    private List<Date> list;

    public Storage() {
        maxSize = 10;
        list = new LinkedList<>();
    }

    public synchronized void set() {
        while (list.size() == maxSize) {
            System.out.println("仓库已满,请等待...");

            try {
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

        list.add(new Date());
        System.out.printf("存放产品: %d\n", list.size());
        notify();
    }

    public synchronized void get() {
        while (list.size() == 0) {
            System.out.println("仓库为空,暂时没有产品提供,请等待...");

            try {
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

        System.out.printf("取出产品:%d: %s\n", list.size(), ((LinkedList<?>) list).poll());
        notify();
    }

}
/**
 * 生产者
 */
public class Producer implements Runnable {

    private Storage storage;

    public Producer(Storage storage) {
        this.storage = storage;
    }

    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            storage.set();
        }
    }
}
/**
 * 消费者  
 */
public class Consumer implements Runnable {

    private Storage storage;

    public Consumer(Storage storage) {
        this.storage = storage;
    }

    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            storage.get();
        }
    }

}

测试main()方法:

public static void main(String[] args) {
    Storage storage=new Storage();      
    Producer producer=new Producer(storage);
    Thread thread1=new Thread(producer);

    Consumer consumer=new Consumer(storage);
    Thread thread2=new Thread(consumer);

    thread2.start();
    thread1.start();
    }

猜你喜欢

转载自blog.csdn.net/maodou95838/article/details/52163364