有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java在可重入锁中等待条件

以下代码取自JavaDoc of ^{}

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();
    }
  } 
}

想象两个线程,消费者生产者,一个使用take,一个putBoundedBuffer的单个实例上

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

现在生产者如何通过锁定lock进入put()方法,而lock已经由消费者持有

我错过了什么?当线程等待某个条件时,lock是否“临时释放”?锁的重入到底意味着什么


共 (3) 个答案

  1. # 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);
    
  2. # 2 楼答案

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

    注意:它们不会完全释放,如果进行堆栈跟踪,可能会有多个线程同时持有锁,但最多有一个线程正在运行(其余线程将被阻塞)

    Condition.await()

    The lock associated with this Condition is atomically released and the current thread becomes disabled for thread scheduling purposes and lies dormant until one of four things happens:

    • Some other thread invokes the signal() method for this Condition and the current thread happens to be chosen as the thread to be awakened; or
    • Some other thread invokes the signalAll() method for this Condition; or
    • Some other thread interrupts the current thread, and interruption of thread suspension is supported; or
    • A "spurious wakeup" occurs.

    In all cases, before this method can return the current thread must re-acquire the lock associated with this condition. When the thread returns it is guaranteed to hold this lock

  3. # 3 楼答案

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

    重新进入并不意味着理解你的问题