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 生产速度太快,爆仓,等待消费中……