ReentrantLock实现自己的BlockingQueue

LinkedBlockingQueue的实现也是通过ReentrantLock 实现put的代码如下:

/**
 * @throws NullPointerException {@inheritDoc}
 * @throws InterruptedException {@inheritDoc}
 */
public void putLast(E e) throws InterruptedException {
    if (e == null) throw new NullPointerException();
    Node<E> node = new Node<E>(e);
    final ReentrantLock lock = this.lock;
    lock.lock();
    try {
        while (!linkLast(node))
            notFull.await();
    } finally {
        lock.unlock();
    }
}

take的代码:

public E takeFirst() throws InterruptedException {
    final ReentrantLock lock = this.lock;
    lock.lock();
    try {
        E x;
        while ( (x = unlinkFirst()) == null)
            notEmpty.await();
        return x;
    } finally {
        lock.unlock();
    }
}

现在我们用LinkedBlockingQueue的思想去实现一个自己的阻塞队列(生产者、消费者队列)

static class MyBlockingQueue<T>{

    private final T[] items ;

    /** Main lock guarding all access */
    final ReentrantLock lock = new ReentrantLock();

    /** Condition for waiting takes */
    private final Condition notEmpty = lock.newCondition();

    /** Condition for waiting puts */
    private final Condition notFull = lock.newCondition();

    private int takeIndex,putIndex,count;

    MyBlockingQueue(int max) {
        this.items = (T[]) new Object[max];
    }

    public void put(T t){
        lock.lock();
        try{
            //如果数据组的里对象 = 设定的数据那么说明满了,要等到被消费一个时才能重新放
            if (count == getLength()) {
                System.out.println("生产速度太快,爆仓,等待消费中……");
                notFull.await();
            }
            items[putIndex] = t;
            //如果放到最后一个位置了,那么,又得从第0个重新开始放
            if (++putIndex == getLength()) {
                putIndex = 0;
            }
            ++count;
            notEmpty.signalAll();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
           lock.unlock();
        }
    }

    public T take(){
        lock.lock();
        T t = null;
        try {
            //如果数据组没内存,那么等待
            if (count == 0) {
                System.out.println("生产速度太慢了,员工等待中……");
                notEmpty.await();
            }
            t = items[takeIndex];
            //消除引用,避免内存泄露
            items[takeIndex] = null;
            //如果取到最后一个位置了,就从第0个开始取
            if (++takeIndex == getLength()) {
                takeIndex = 0;
            }
            --count;
            notFull.signalAll();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
           lock.unlock();
        }
        return t;
    }

    private int getLength(){
        return items.length;
    }
}

写一段代码测试:

@Test
public void testMyQueue() throws InterruptedException {
    final MyBlockingQueue<String> queue = new MyBlockingQueue<String>(6);
    Thread put = new Thread(new Runnable() {
        @Override
        public void run() {
            for (int i = 0; i < 10000; i++) {
                queue.put("product:" + i);
                System.out.println("生产了:" + "product" + i);
                try {
                    TimeUnit.SECONDS.sleep(4);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    });
    Thread take = new Thread(new Runnable() {
        @Override
        public void run() {
            for (int i = 0; i < 10000; i++) {
                System.out.println("消费了:" + queue.take());
                try {
                    TimeUnit.SECONDS.sleep(1);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    });
    put.start();
    take.start();
    put.join();
    take.join();
}

控制台输出:

1、4秒生产一个,1秒消费一个情况

生产了:product0
消费了:product:0
生产速度太慢了,员工等待中……
生产了:product1
消费了:product:1
生产速度太慢了,员工等待中……
生产了:product2
消费了:product:2
生产速度太慢了,员工等待中……
2、 1秒生产一个,4秒消费一个的情况

生产了:product0
消费了:product:0
生产了:product1
生产了:product2
生产了:product3
消费了:product:1
生产了:product4
生产了:product5
生产了:product6
生产了:product7
生产速度太快,爆仓,等待消费中……
消费了:product:2
生产了:product8
生产速度太快,爆仓,等待消费中……
消费了:product:3
生产了:product9
生产速度太快,爆仓,等待消费中……

你可能感兴趣的:(java多线程)