Java 在重入锁中等待条件

Java 在重入锁中等待条件,java,synchronization,Java,Synchronization,以下代码取自: 想象两个线程,消费者和生产者,一个使用获取,一个将放在绑定缓冲区的单个实例上 假设消费者首先运行take(),在其中他锁定lock,现在循环notEmpty.await() 现在生产者如何才能进入put()方法,而不锁定消费者已经持有的锁 我错过了什么?线程等待某个条件时,锁是否“临时释放”?锁的可重入性到底意味着什么?无论是lock还是synchronized都允许一个线程在等待时放弃锁,而另一个线程可以获得锁。要停止等待,线程必须重新获取锁 注意:它们不会完全释放它,如果您进

以下代码取自:

想象两个线程,消费者和生产者,一个使用
获取
,一个
放在
绑定缓冲区
的单个实例上

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

现在生产者如何才能进入
put()
方法,而不锁定消费者已经持有的


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

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

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

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

  • 其他一些线程为此条件调用signal()方法,而当前线程恰好被选为要唤醒的线程;或
  • 其他一些线程为此条件调用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);

您能提供相关文档的链接吗?@PeterLawrey
(其他人将等待)
或阻止?我认为他们应该处于阻塞状态`?你能解释一下这句话吗:“锁和同步都暂时允许其他人在等待时获得锁。”这对我来说没有意义。@Chin当锁的持有者在等待时,它释放了锁,可以被另一个线程持有。我想让人困惑的是,在你的句子中,“其他人”和“他们”并不是指同一个实体。我大约有两个人问了完全相同的问题,在JavaDoc上有完全相同的例子:)避免了我浪费时间。有时术语“递归锁”也用于可重入锁,请参阅。
 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);