Java 使用RentrantLock实现生产者-消费者时发生IllegalMonitorStateException

Java 使用RentrantLock实现生产者-消费者时发生IllegalMonitorStateException,java,multithreading,Java,Multithreading,我试图在java中使用ReentrantLock实现生产者消费者 Condition producerlock = lock.newCondition(); Condition consumerlock = lock.newCondition(); 它有两个条件,一个是生产者,另一个是消费者 这里我们有一个处理器类,它有两个方法生产者消费者和一个堆栈 Stack<Integer> hellostrack = new Stack<>(); p

我试图在java中使用ReentrantLock实现生产者消费者

    Condition producerlock = lock.newCondition();
    Condition consumerlock = lock.newCondition();
它有两个条件,一个是生产者,另一个是消费者

这里我们有一个处理器类,它有两个方法生产者消费者和一个堆栈

   Stack<Integer> hellostrack = new Stack<>();



 public void produce() throws InterruptedException {
        lock.tryLock();
        System.out.println("inside producer method");
        while (true) {
            try {

                if (hellostrack.size() > 8) {
                    System.out.println("stack is full its time for me to go to sleep");
                    producerlock.await();
                }
                System.out.println("thread is alive and kicking");
                hellostrack.add(new Random().nextInt());
                consumerlock.signalAll();


            } finally {
                System.out.println("Exception occours in producer Thread");
                lock.unlock();
            }
        }
    }


public void consume() throws InterruptedException{
             System.out.println("inside consumer method");
             lock.tryLock();
          try {
              while (true) {
                  if (hellostrack.isEmpty()) {
                      System.out.println("stack is empty im going to sleep");
                      consumerlock.await();

                  } else {
                      System.out.println("poping elelmts from stock" + hellostrack.pop());
                      consumerlock.signalAll();


                  }

          } }finally {
              System.out.println("Exception occours at consumer");
              lock.unlock();
          }
     }

请注意,您处于
while(true)
循环中。您永远不会离开循环,这意味着您将解锁,然后再也不会重新锁定。在第一个循环之后,您将再次尝试解锁,但由于您不拥有该锁,因此将引发异常


tryLock
移动到
while(true)
下,可能会工作得更好。

请注意,您处于
while(true)
循环中。您永远不会离开循环,这意味着您将解锁,然后再也不会重新锁定。在第一个循环之后,您将再次尝试解锁,但由于您不拥有该锁,因此将引发异常

tryLock
移动到
while(true)
下,可能会工作得更好。

此外,您的代码还有一些其他问题

  • 您正在使用:

    仅当锁在调用时可用时才获取锁

    获取锁(如果可用),并立即返回值true。如果锁不可用,则此方法将立即返回值false

    此方法的典型用法是:

    Lock lock = ...;
    if (lock.tryLock()) {
      try {
         // manipulate protected state
      } finally {
        lock.unlock();
      }
    } else {
      // perform alternative actions
    }
    
    此用法可确保在获得锁时将其解锁,而在未获得锁时不会尝试解锁

    您的代码不会检查
    tryLock
    的结果,这意味着线程有可能在不持有锁的情况下移动到受保护的代码中。这意味着除了不正确同步的访问之外,还有可能在不持有锁的情况下调用
    wait()
    signalAll()
    、和
    unlock()

    在这种情况下,您要调用的方法是:

    获得锁

    如果锁不可用,则出于线程调度目的,当前线程将被禁用,并处于休眠状态,直到获得锁为止

    这意味着线程将等待获得锁后再继续。但是,由于您的方法已经抛出了
    InterruptedException
    ,因此您最好使用。这与
    lock()
    基本相同,但等待可能会被中断

  • 您正在调用
    consumerlock.signalAll()
    方法中的
    consumer()

    一旦您消费了一个元素,您就要通知生产者有更多的可用空间。您应该调用
    producerlock.signalAll()

  • 在循环中不能调用
    await()

    在检查条件的循环中调用
    await()
    是一种很好的做法。原因是线程可以出于任何原因(很少)唤醒。如果发生这种情况,并且存在循环,线程将重新检查条件,如果合适,将再次调用
    await()

    此外,您正在使用
    signalAll()
    。该方法通知所有等待的线程唤醒,尝试获取锁,然后继续。由于不使用循环,所有唤醒的线程都将继续执行可能导致不一致/不正确状态的任何修改。相反,拥有循环意味着如果其中一个唤醒的线程导致等待条件再次为真,则任何后续线程都将返回等待状态

    使用循环类似于:

    while (hellostrack.size() > 8) { // should this be >= 8?
        producerlock.await();
    }
    
    // and
    
    while (hellostrack.isEmpty()) {
        consumerlock.await();
    }
    
  • 除此之外,您的代码还存在一些其他问题

  • 您正在使用:

    仅当锁在调用时可用时才获取锁

    获取锁(如果可用),并立即返回值true。如果锁不可用,则此方法将立即返回值false

    此方法的典型用法是:

    Lock lock = ...;
    if (lock.tryLock()) {
      try {
         // manipulate protected state
      } finally {
        lock.unlock();
      }
    } else {
      // perform alternative actions
    }
    
    此用法可确保在获得锁时将其解锁,而在未获得锁时不会尝试解锁

    您的代码不会检查
    tryLock
    的结果,这意味着线程有可能在不持有锁的情况下移动到受保护的代码中。这意味着除了不正确同步的访问之外,还有可能在不持有锁的情况下调用
    wait()
    signalAll()
    、和
    unlock()

    在这种情况下,您要调用的方法是:

    获得锁

    如果锁不可用,则出于线程调度目的,当前线程将被禁用,并处于休眠状态,直到获得锁为止

    这意味着线程将等待获得锁后再继续。但是,由于您的方法已经抛出了
    InterruptedException
    ,因此您最好使用。这与
    lock()
    基本相同,但等待可能会被中断

  • 您正在调用
    consumerlock.signalAll()
    方法中的
    consumer()

    一旦您消费了一个元素,您就要通知生产者有更多的可用空间。您应该调用
    producerlock.signalAll()

  • 在循环中不能调用
    await()

    在检查条件的循环中调用
    await()
    是一种很好的做法。原因是线程可以出于任何原因(很少)唤醒。如果发生这种情况,并且存在循环,线程将重新检查条件,如果合适,将再次调用
    await()

    此外,您正在使用
    signalAll()
    。该方法通知所有等待的线程唤醒,尝试获取锁,然后继续。由于不使用循环,所有唤醒的线程都将继续执行可能导致不一致/不正确状态的任何修改。相反,拥有循环意味着