生产者消费者问题

首先用一个普通的stack来实现消费者和生产者。

package concurrent;

import java.util.Stack;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;


public class StackPC {
    class MyStack{
        private Stack stack = new Stack();
        private int size = 0;
        public synchronized void push(int i ){
            stack.push(i);
            size = size +1;
        }
        public synchronized int pop(){
            int i = (int) stack.pop();
            size = size -1;
            return i;
        }
        public boolean isEmpty(){
            return stack.isEmpty();
        }
        public int size(){
            return size;
        }
    }
    class Producer{
        private MyStack mystack ;
        public Producer(MyStack mystack){
            this.mystack = mystack;
        }
        public void producer(){
                try {
                    synchronized (mystack){
                        if(mystack.size()>10)
                            mystack.wait();
                        int i = (int) Math.round((Math.random()*100));
                        mystack.push(i);
                        System.out.println("生产了"+i+"此时size为"+mystack.size());
                        mystack.notify();
                    }
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
        }
    }
    class Customer{
        private MyStack mystack ;
        public Customer(MyStack mystack){
            this.mystack = mystack;
        }
        public void customer(){
                try {
                    synchronized(mystack){
                        if(mystack.isEmpty())
                            mystack.wait();
                        int i = mystack.pop();
                        System.out.println("消费了"+i+"此时size为"+mystack.size);
                        mystack.notify();
                    }
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
        }
    }
    
    public static void main(String[] args) {
        StackPC test  = new StackPC();
        StackPC.MyStack stack = test.new MyStack();
        final StackPC.Producer p = test.new Producer(stack);
        final StackPC.Customer c = test.new Customer(stack);
        Runnable pRunner = new Runnable() {
            @Override
            public void run() {
                while(true){
                    p.producer();
                }
            }
        };
        Runnable cRunner = new Runnable() {
            @Override
            public void run() {
                while(true){
                    c.customer();
                }
            }
        };
        ExecutorService exe = Executors.newCachedThreadPool();
        exe.execute(pRunner);
        exe.execute(cRunner);
    }
}

运行结果如下:

生产者最多生产到size为11的时候就会唤醒消费者进行消费,消费者消费到size为0时会唤醒生产者进行生产。当stack的容量大于0小于11时,生产和消费是并行运行的。这里由于cpu执行较快没有明显的生产消费交替进行,而是一次消费或者生产多个然后才交替执行。

 

上面是我们自己使用stack来对产品进行缓存,其实java中已经有非常完善的类提供给我们使用,使用阻塞队列来模拟生产者消费者问题实现更为简单。

package concurrent;

import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class BlockingQueueTest {
    public static void main(String[] args) throws InterruptedException {
        final BlockingQueue bq = new ArrayBlockingQueue(10);
        Runnable producer = new Runnable() {
            @Override
            public void run() {
                int i = 0;
                while(true){
                    try {
                        i++;
                        bq.put(i);
                        System.out.println("生产了一个"+ i);
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                        break;
                    }
                }
            }
        };
        Runnable customer = new Runnable() {
            @Override
            public void run() {
                while(true){
                    try {
                        System.out.println("消费了一个"+bq.take());
                        Thread.sleep(3000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                        break;
                }
            }
            }
        };
        ExecutorService exe = Executors.newCachedThreadPool();
        exe.execute(producer);
        exe.execute(customer);
//         Thread.sleep(1000);
//        exe.shutdownNow();
    }
}

这里我们不需要再手动写wait和notify,也不用对队列进行手动加锁,这里生产者生产的速度快与消费者,所以在开始的时候虽然是并行执行,但是生产者的速度较快,阻塞队列很快达到容量最大值10,这时候生产者无法继续生产,阻塞等待,当消费者消费后,容量减小,生产者继续生产。

可以看出在容量到达10 以后,消费者消费一个生产者才继续生产一个,使用阻塞队列可有效平衡生产者和消费者。

posted @ 2017-11-01 21:11  封尘寒剑  阅读(280)  评论(0编辑  收藏  举报