【问题标题】:Java Conditions with Locks带锁的 Java 条件
【发布时间】:2021-12-14 00:10:42
【问题描述】:

Java 文档来自这里https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/locks/Condition.html

我正在尝试理解条件概念。在下面的代码中,将两者都放在同一个锁上等待。文档说,在调用任何 condition.await() 之前,我们需要获取相应的锁 (here line 2 : final Lock lock = new ReentrantLock();).

我的问题是,假设缓冲区已满。在这种情况下,如果我们尝试插入一个对象,线程将被阻塞直到count == items.length,但这里的锁仍然保留在试图放入的线程中。我们如何调用方法 take() 来减少计数,因为 take() 需要获取同一个 Lock 的持有。在我看来,这将是死锁,因为无法调用 take(),如果项目为空,我们将无法调用 put(),因为现在锁已经使用 take()。

如果我遗漏了什么,请帮助我理解。提前致谢。

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

【问题讨论】:

  • await()-javadoc:“与此条件关联的锁被自动释放,当前线程出于线程调度的目的而被禁用,并且处于休眠状态,直到发生以下四种情况之一:...”,还请“小字”;)

标签: java multithreading blocking locks


【解决方案1】:

如果您查看 Condition#await (https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/locks/Condition.html) 的 api 文档,它会说:

与此 Condition 关联的锁被自动释放,当前线程出于线程调度目的而被禁用并处于休眠状态,直到发生以下四种情况之一:

既然锁被释放了,那么put获取锁就没有问题了。

【讨论】:

  • 所以它类似于在任何对象上调用 wait() 。我的意思是我们可以在一个对象上同步而不是锁,比如 obj 然后等待那个 obj.wait()
  • @cjava: 是的,想法是一样的,只是一个锁可以有不同的条件是一个很大的优势。而且 synchronized 也使用了锁,它是对象上的隐式锁。
  • 我想在这里使用 countdownlatch 会更好,因为调用信号不会完全确保被阻塞的线程被唤醒。你有什么建议
  • @cjava:调用信号意味着等待该条件的线程得到通知。使用同步后,如果线程出于不同的原因等待,线程可能会在无法取得进展时收到唤醒。但是,如果您适当地使用条件,这不是问题,在发布的代码中就是这种情况。
  • 来自文档,谢谢,最后一点,你的意思是信号会唤醒同一个线程吗:与此条件关联的锁被原子释放,当前线程出于线程调度目的而被禁用并处于休眠状态,直到发生以下四种情况之一: 其他线程为此 Condition 调用 signal() 方法,并且当前线程恰好被选为要唤醒的线程;或
猜你喜欢
  • 2019-12-05
  • 2014-06-07
  • 1970-01-01
  • 2016-02-29
  • 2021-02-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-10-22
相关资源
最近更新 更多