对LinkedBlockingQueue使用非线程安全列表

时间:2015-02-22 07:23:02

标签: java multithreading concurrency thread-safety blockingqueue

我想知道如果我们将基础数据结构更改为像java.util.LinkedList这样的非线程安全列表,为什么LinkedBlockingQueue不会工作?我尝试时得到NoSuchElementException。它是否被锁(takeLock)保护,使其成为线程安全的?

private final List<E> list;
private final ReentrantLock takeLock;
private final ReentrantLock putLock;
private final Condition     notFull;
private final Condition     notEmpty;
private final AtomicInteger count;

public LinkedBlockingQueue() {
    takeLock = new ReentrantLock();
    putLock = new ReentrantLock();
    notFull = putLock.newCondition();
    notEmpty = takeLock.newCondition();
    count = new AtomicInteger(0);
    list = new LinkedList<E>();
}

public E get() {
   E item = null;
   int c = -1;
   try {
      takeLock.lockInterruptibly();
      while (count.get() == 0) notEmpty.await();

      // original -> item = dequeue();
      item = list.remove();   // NoSuchElementException

      c = count.getAndDecrement();
   } 
   catch (InterruptedException ie) {} 
   finally {
      takeLock.unlock();
   }

   if (c == capacity) signalNotFull();
   return item;
}

public void put(E e) {
   int c = -1;
   try {
      putLock.lockInterruptibly();
      while (count.get() == BOUND_SIZE) notFull.await();

      // original -> enqueue(node);
      list.add(e);

      c = count.getAndIncrement();
   } 
   catch (InterruptedException ie) {} 
   finally {
      putLock.unlock();
   }

   if (c == 0) signalNotEmpty();
}

1 个答案:

答案 0 :(得分:1)

您正在使用两个单独的锁定对象:

takeLock = new ReentrantLock();
putLock = new ReentrantLock();
notFull = putLock.newCondition();
notEmpty = takeLock.newCondition();

这是错误的。首先,您必须对put和take操作使用相同的锁定对象。此外,您必须使用相同的锁定对象创建条件。

lock = new ReentrantLock();
notFull = lock.newCondition();
notEmpty = lock.newCondition();

你应该用给定的锁定引用替换你的takeLock和putLock用法。

http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/locks/Lock.html http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/locks/Condition.html