在重入锁定的条件下等待

以下代码取自Condition的JavaDoc :

 class BoundedBuffer { final Lock lock = new ReentrantLock(); final Condition notFull = lock.newCondition(); final Condition notEmpty = lock.newCondition(); final Object[] items = new Object[100]; int putptr, takeptr, count; public void put(Object x) throws InterruptedException { lock.lock(); try { while (count == items.length) notFull.await(); items[putptr] = x; if (++putptr == items.length) putptr = 0; ++count; notEmpty.signal(); } finally { lock.unlock(); } } public Object take() throws InterruptedException { lock.lock(); try { while (count == 0) notEmpty.await(); Object x = items[takeptr]; if (++takeptr == items.length) takeptr = 0; --count; notFull.signal(); return x; } finally { lock.unlock(); } } } 

想象一下2个线程, 消费者生产者 ,一个使用take ,一个put BoundedBuffer的单个实例上。

假设消费者首先运行,运行take()在其中锁定lock ,现在循环在notEmpty.await();

现在生产者怎么可能进入put()方法过去锁定已经被消费者持有的lock

我在这里想念的是什么? 当线程在其中一个条件上等待时, lock是否“暂时释放”? 锁的重入是什么意思呢?

Locksynchronized允许线程在等待时放弃锁定,而另一个线程可以获得锁定。 要停止等待,线程必须重新获取锁定。

注意:它们不会完全释放它,如果你采用堆栈跟踪,你可以有多个线程,它们似乎一次持有锁,但最多其中一个将运行(其余的将阻塞)

来自Condition.await()

与此条件关联的锁被primefaces释放,并且当前线程因线程调度而被禁用,并处于hibernate状态,直到发生以下四种情况之一:

  • 一些其他线程为此Condition调用signal()方法,并且当前线程恰好被选为要被唤醒的线程; 要么
  • 其他一些线程为此Condition调用signalAll()方法; 要么
  • 其他一些线程会中断当前线程,并支持线程挂起中断; 要么
  • 发生“虚假唤醒”。

在所有情况下,在此方法返回之前,当前线程必须重新获取与此条件关联的锁。 当线程返回时,保证保持此锁定

就重入而言,这意味着持有某个锁的线程可以再次重新获得相同的锁。 如果不是这样,则synchronized方法将无法调用同一对象的另一个synchronized方法。

重新参与不涉及对您的问题的理解。

我用单显示器测试下面的代码,下面总是表现更好 – 在2核心机器上测试,条件性能平均低于10-15%

  final Object sync = new Object(); AtomicInteger add=new AtomicInteger(); AtomicInteger remove=new AtomicInteger(); final Object[] items = new Object[1]; int putptr, takeptr, count; public void add(Object x) throws InterruptedException { add.incrementAndGet(); synchronized (sync) { while (count == items.length) sync.wait(); items[putptr] = x; if (++putptr == items.length) putptr = 0; ++count; sync.notify(); } } public Object remove() throws InterruptedException { remove.incrementAndGet(); synchronized (sync) { while (count == 0) sync.wait(); Object x = items[takeptr]; if (++takeptr == items.length) takeptr = 0; --count; sync.notify(); return x; } } public static void main(String[] args) { final BoundedBuffer bf=new BoundedBuffer(); Thread put =new Thread(){ public void run(){ try { while(true) bf.add(new Object()); } catch (InterruptedException e) { } } }; put.start(); Thread take= new Thread(){ public void run(){ try { while(true) bf.remove(); } catch (InterruptedException e) { } } }; take.start(); try { Thread.sleep(1000L); put.interrupt(); take.interrupt(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } System.out.println("add:"+bf.add); System.out.println("remove:"+bf.remove);