首页 > 代码库 > JDK6中LinkedBlockingQueue中的锁机制

JDK6中LinkedBlockingQueue中的锁机制

常识,之前有的没搞清楚,导致写代码时不少疑惑。

比较典型的同步例子,用了两个Condition,notEmpty和notFull,分别对应两个lock,takeLock和putLock。查看take的代码:

E x;

int c = -1;

final AtomicInteger count = this.count;

final AtomicInteger takeLock = this.takeLock;

takeLock.lockInterruptibly();

try {

  try {

    while (count.get() == 0) notEmpty.await();

  } catch (InterruptedException ie) {

    notEmpty.signal();

    throw ie;

  }

  x = extract();

  c = count.getAndDecrement();

  if (c > 1) {

    notEmpty.signal();

  }

} finally {

  takeLock.unlock();

}

if (c == capacity) {

  signalNotFull();

}

return x;

singalNotFull中代码:

putLock.lock();

try { notFull.signal(); } finally { putLock.unlock(); }

可以看出:

1.take操作可能会block,应允许终端,所以用lockInterruptably更友好

2.for循环await是java文档推荐的,await成功不代表条件满足,这种唤醒称为伪唤醒(spurious wakeup)

3.await()抛出InterruptedException后signal让下一个等待线程伪唤醒

4.用signal而不是signalAll,一次只唤醒一个线程,取完之后发现还有就再signal,唤醒下一个等待线程,这是因为condition可用时不一定能让所有take线程获取成功(看队列当前size够不够),因而不必signalAll

5.使用了两把锁,take时notEmpty(lock await)=>notFull(lock signal),put时:notFull(lock await) => notEmpty(lock signal),因此take和put可以兵法,另外有个问题是put在notFull lock后进入await,block住了,take线程会不会拿不到notFull的锁signal而导致死锁呢?答案是不会,因为await会先释放掉锁然后在返回钱重新获得锁。其实object的wait也有相同特性。

JDK6中LinkedBlockingQueue中的锁机制