在重入锁定的条件下等待

时间:2012-09-25 08:06:58

标签: java synchronization

以下代码取自JavaDoc of Condition

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个线程, Consumer Producer ,一个使用take,一个putBoundedBuffer的单个实例上。

让我们说消费者先行,运行take(),然后锁定lock,现在循环notEmpty.await();

现在 Producer 如何能够进入put()方法,锁定{em>消费者已经拥有的lock

我在这里缺少什么?当线程正在等待其中一个条件时,lock“暂时释放”吗?锁的重入究竟是什么意思?

3 个答案:

答案 0 :(得分:28)

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

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

来自Condition.await()

  

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

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

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

答案 1 :(得分:6)

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

重新入侵不参与了解你的问题。

答案 2 :(得分:-1)

我用单显示器测试下面的代码,下面总是表现更好 - 在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);