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

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()释放一个写许可

你可能感兴趣的:(java)