使用信号量实现的有界缓冲池BoundedBuffer

来源:互联网 发布:mysql 数据库迁移 编辑:程序博客网 时间:2024/05/21 01:28
/** * author:gaoxingliang@outlook.com * created:2015年9月2日 下午8:19:08   */package datastruct;import java.util.concurrent.Semaphore;/** * 使用信号量实现的有界缓冲池 */public class BoundedBuffer<T>{    private int size;    // 可用的信号量    private Semaphore avialable = null;    // 是否已经有元素的信号量    private Semaphore used = null;    // put的位置 take的位置    private int putPos, takePos;    private T[] objs;    @SuppressWarnings("unchecked")    public BoundedBuffer(int size)    {        this.size = size;        avialable = new Semaphore(size);        used = new Semaphore(0);        objs = (T[]) new Object[size];        putPos = takePos = 0;    }    public boolean isEmpty()    {        return used.availablePermits() == 0;    }    public boolean isFull()    {        return avialable.availablePermits() == 0;    }    /**     * 取一个元素     *      * @return     * @throws InterruptedException     */    public T take() throws InterruptedException    {        // wrong version        T o = null;        used.acquire();        synchronized (this)        {            o = objs[takePos];            objs[takePos] = null;            takePos = (takePos + 1) % size;        }        avialable.release();        return o;    }    /**     * 放一个元素     *      * @param o     * @throws InterruptedException     */    public void put(T o) throws InterruptedException    {        avialable.acquire();        synchronized (this)        {            objs[putPos] = o;            putPos = (putPos + 1) % size;        }        used.release();    }}

测试程序:

/** *  * author:gaoxingliang@outlook.com * created:2015年9月2日 下午8:43:37   */package datastruct;import static org.junit.Assert.assertFalse;import static org.junit.Assert.assertTrue;import static org.junit.Assert.fail;import java.security.SecureRandom;import org.junit.Ignore;import org.junit.Test;/** * @author gxl * */public class BoundedBufferTestCase{    @Test    public void testbase1()    {        // 测试基础方法        BoundedBuffer<Integer> bb = new BoundedBuffer<Integer>(10);        assertTrue(bb.isEmpty());        assertFalse(bb.isFull());    }    @Test    public void testIsFullWhenPuts() throws InterruptedException    {        int size = 10;        BoundedBuffer<Integer> bb = new BoundedBuffer<Integer>(size);        assertTrue(bb.isEmpty());        assertFalse(bb.isFull());        for (int i = 0; i < size; i++)        {            bb.put(i);        }        assertTrue(bb.isFull());        assertFalse(bb.isEmpty());    }    @Ignore    public void testTakeWhenEmpty()    {        int size = 10;        final BoundedBuffer<Integer> bb = new BoundedBuffer<Integer>(size);        Thread taker = new Thread(new Runnable()        {            @Override            public void run()            {                try                {                    bb.take();                    fail("Cannt take suc.");                }                catch (InterruptedException e)                {                }            }        });        try        {            taker.start();            Thread.sleep(10000);            taker.interrupt();            taker.join(10000);            assertFalse(taker.isAlive());        }        catch (InterruptedException e)        {            fail(e.getMessage());        }    }    @Test    public void testCorrectness()    {        SecureRandom r = new SecureRandom();        for (int i = 0; i< 10; i++)        {            boolean res = new PutTakeTest(r.nextInt(20000) + 1, r.nextInt(35) + 10, r.nextInt(50) + 10).test();            assertTrue(res);        }    }}
/** *  * author:gaoxingliang@outlook.com * created:2015年9月2日 下午8:59:46   */package datastruct;import java.util.concurrent.CyclicBarrier;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;import java.util.concurrent.atomic.AtomicInteger;/** * 辅助测试BoundedBuffer安全性的测试 *  * @author gxl * */public class PutTakeTest{    private int tryTime, pairCount;    private final AtomicInteger putSum = new AtomicInteger();    private final AtomicInteger takeSum = new AtomicInteger();    private CyclicBarrier barrier;    private static final ExecutorService es = Executors.newCachedThreadPool();    private BoundedBuffer<Integer> bb;    /**     * constructor     *      * @param tryTime     *            测试次数/累加次数     * @param pairCount     *            生产者和消费者各pairCount个     * @param buffSize     *            缓冲池大小     */    public PutTakeTest(int tryTime, int pairCount, int buffSize)    {        this.tryTime = tryTime;        this.pairCount = pairCount;        this.barrier = new CyclicBarrier(pairCount * 2 + 1);        this.bb = new BoundedBuffer<Integer>(buffSize);    }    public boolean test()    {        try        {            for (int i = 0; i< pairCount; i ++)            {                es.execute( new Producer(bb, barrier));                es.execute(new Consumer(bb, barrier));            }            barrier.await();//WAIT UNTIL ALL IS READY            barrier.await();//WAIT UNTIL ALL IS FINISHED            return putSum.get() == takeSum.get();        }        catch (Exception e)        {            e.printStackTrace();            return false;        }    }    class Producer implements Runnable    {        private BoundedBuffer<Integer> outBuffer;        private CyclicBarrier outBarrier;        /**         * @param bb         * @param barrier         */        public Producer(BoundedBuffer<Integer> bb, CyclicBarrier barrier)        {            super();            this.outBuffer = bb;            this.outBarrier = barrier;        }        /*         * (non-Javadoc)         *          * @see java.lang.Runnable#run()         */        @Override        public void run()        {            try            {                int seed = (this.hashCode() ^ (int) System.nanoTime());                outBarrier.await();                int sum = 0;                for (int i = 0; i < tryTime; i++)                {                    outBuffer.put(seed);                    sum += seed;                    seed = xOrShift(seed);                }                putSum.getAndAdd(sum);                outBarrier.await();            }            catch (Exception e)            {                // TODO: handle exception            }        }    }    class Consumer implements Runnable    {        private BoundedBuffer<Integer> outBuffer;        private CyclicBarrier outBarrier;        /**         * @param bb         * @param barrier         */        public Consumer(BoundedBuffer<Integer> bb, CyclicBarrier barrier)        {            super();            this.outBuffer = bb;            this.outBarrier = barrier;        }        /*         * (non-Javadoc)         *          * @see java.lang.Runnable#run()         */        @Override        public void run()        {            try            {                outBarrier.await();                int sum = 0;                for (int i = 0; i < tryTime; i++)                {                    sum += outBuffer.take();                }                takeSum.getAndAdd(sum);                outBarrier.await();            }            catch (Exception e)            {                e.printStackTrace();                throw new RuntimeException(e);            }        }    }    static int xOrShift(int y)    {        y ^= (y << 6);        y ^= (y >>> 21);        y ^= (y << 7);        return y;    }}
0 0
原创粉丝点击