JAVA面试之消费者-生产者问题

最近遇到一个面试题,说是模拟生产者消费者问题并且不能使用concurrent包,思路是使用信号量Semaphore和PV操作,代码如下

/**
 * Created by violetMoon on 2016/5/12.
 */
public class ConsumerTest {

    static class Semaphore {
        private Object lock = new Object();
        private int value;

        public Semaphore(int value) {
            this.value = value;
        }

        public void p() {
            synchronized (lock) {
                value--;
                if (value < 0)
                    try {
                        System.out.println(Thread.currentThread().getName() + " go to sleep");
                        lock.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
            }
        }

        public void v() {
            synchronized (lock) {
                value++;
                if (value <= 0) {
                    System.out.println(Thread.currentThread().getName() + " waitup a thread");
                    lock.notify();
                }
            }
        }
    }

    static int in;
    static int out;

    public void test() {
        final int BUFFER_SIZE = 5;
        Integer[] breads = new Integer[BUFFER_SIZE];
        in = 0;
        out = 0;
        Semaphore putSema = new Semaphore(BUFFER_SIZE); //一开始缓冲区为空,所以可以填充的数量为缓冲区大小
        Semaphore getSema = new Semaphore(0); //一开始没有面包
        Semaphore putMutex = new Semaphore(1);
        Semaphore getMutex = new Semaphore(1);

        Runnable consumer = new Runnable() {
            @Override
            public void run() {
                while (true) {
                    Integer myBread = null;
                    getSema.p();
                    getMutex.p();
                    myBread = breads[out];
                    out = (out + 1) % BUFFER_SIZE;
                    System.out.println(Thread.currentThread().getName() + " eat bread:" + myBread);
                    getMutex.v();
                    putSema.v();
                }
            }
        };

        Runnable worker = new Runnable() {
            @Override
            public void run() {
                while (true) {
                    Integer newBread = null;
                    putSema.p();
                    putMutex.p();
                    newBread = new Integer(in);
                    breads[in] = newBread;
                    System.out.println(Thread.currentThread().getName() + " produce bread:" + newBread);
                    in = (in + 1) % BUFFER_SIZE;
                    putMutex.v();
                    getSema.v();
                }
            }
        };

        int consumerNum = 4;
        for (int i=0; i<consumerNum; ++i)
            new Thread(consumer, "consumer" + (i + 1)).start();

        int workerNum = 4;
        for (int i=0; i<workerNum; ++i)
            new Thread(worker, "worker" + (i + 1)).start();
    }

    public static void main(String[] args) {
        new ConsumerTest().test();
    }
}

Semaphore的p操作相当于获取可用资源,使用lock锁来实现value操作的原子性,以及在没有可用资源时调用lock.wait()释放当前锁并进入等待,v操作相当于释放资源,value<0表明有线程在lock上等待资源,所以调用notify释放其中一个线程

为了方便说明把putSema的资源称作写许可,把getSema的资源称作读许可。

生产者先调用putSema.p()来获取一个写许可,如果没有陷入等待,之后使用putMutex来实现生产者写互斥,进入临界区后将面包放到缓冲区里,使用putMutex.v()释放互斥锁,之后调用getSema.v()释放一个读许可。

消费者先调用getSema.p()来获取一个读许可,如果没有陷入等待,之后使用getMutex来实现消费者读互斥,进入临界区后吃掉一个面包,使用getMutex.v()释放互斥锁,之后调用putSema.p()释放一个写许可

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值