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

来源:互联网 发布:仟游软件科技有限公司 编辑:程序博客网 时间:2024/05/18 00:22

最近遇到一个面试题,说是模拟生产者消费者问题并且不能使用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()释放一个写许可

0 0