Java Reentrantlock-为什么我们需要多次获取锁?

Java Reentrantlock-为什么我们需要多次获取锁?,java,multithreading,concurrency,reentrantlock,Java,Multithreading,Concurrency,Reentrantlock,我最近一直在学习java中的多线程概念。我有一些疑问没有通过查找StackOverflow上的相关线程来解决。我无法找到以下问题的满意答案: wait()方法使线程等待直到获得锁。然而,wait(longtimeout)方法使线程等待'timeout'毫秒数,如果它仍然没有获得锁,则返回到runnable状态。但要真正进入运行状态,它需要锁。那么等待(长超时)方法的要点是什么?然而,当线程处于等待状态时,它会释放它获取的锁。因此,差异甚至不在于它所获得的资源。如果线程处于等待状态或可运行状态,会

我最近一直在学习java中的多线程概念。我有一些疑问没有通过查找StackOverflow上的相关线程来解决。我无法找到以下问题的满意答案:

  • wait()方法使线程等待直到获得锁。然而,wait(longtimeout)方法使线程等待'timeout'毫秒数,如果它仍然没有获得锁,则返回到runnable状态。但要真正进入运行状态,它需要锁。那么等待(长超时)方法的要点是什么?然而,当线程处于等待状态时,它会释放它获取的锁。因此,差异甚至不在于它所获得的资源。如果线程处于等待状态或可运行状态,会有什么区别?与wait()方法相比,wait(长超时)有什么优势

  • synchonized关键字或块提供对调用方法或块的对象的锁定。它会导致另一个试图获取同一实例锁的线程等待。但是在ReentrantLock的情况下,锁是在哪个对象上获得的?试图获取其锁的线程被设置为等待

  • ReentrantLock如何避免死锁?假设有两种方法m1和m2。两者都需要一把锁。m1调用m2,m2调用m1。在这种情况下,如何使用ReentrantLock避免死锁?可能我们可以使用tryLock()并为无法获取锁的线程提供备用操作。但可能的替代行动是什么?如果线程必须使用锁才能工作,该怎么办

  • 我发现使用ReentrantLock可以多次获得锁。但为什么我们必须多次获得锁?我读过关于这个问题的理论答案,但没有真正理解。如果您能用清晰的示例代码进行演示,这将非常有用

  • 为什么我们需要多次获取锁

    显然,你不需要这么做。但应用程序“偶然”完成这项任务并不罕见。例如:

      public void binaryOperation(Operand op1, Operand op2) {
          synchronized (op1) {
              synchronized (op2) {
                   // do something that needs the locks
              }
          }
      }
    
      // now call passing the same object for both operands
      Operand op = ...
      binaryOperation(op, op); 
    
    在本例中,
    op
    对象实际上会被锁定两次。如果原语锁不是可重入的,这可能会失败(或死锁)

    现在我们可以修复
    binaryOperation
    方法,使其不这样做,但这会使代码变得更加复杂

    同样的情况也可能发生在
    ReentrantLock


    问题1

    但要真正进入运行状态,它需要锁。那么等待(长超时)方法的要点是什么

    这是关于
    Object::wait
    ReentrantLock
    API不支持此操作。(注意:您可以对
    ReentrantLock
    对象使用
    wait
    notify
    ,但前提是将其视为基本锁。这不是一个好主意!)

    wait
    正在等待通知,
    timeout
    表示调用方准备等待通知的时间。正如政府所说:

    使当前线程等待,直到另一个线程调用此对象的
    notify()
    方法或
    notifyAll()
    方法,或者经过指定的时间

    对于
    wait()
    wait(timeout)
    ,由调用方检查其期望“通知”的条件是否实际满足。(请参阅关于“虚假唤醒”的注释……以及示例代码。)

    与wait()方法相比,wait(长超时)有什么优势

    简单地说,它为您提供了只等待有限时间的通知的选项。如果这是没有用的,不要使用它


    问题2

    但是在
    可重入锁
    的情况下,在哪个对象上获取锁

    严格地说,这是锁本身。锁的实际含义将取决于如何编写类。但这与原始互斥体完全相同

    Java中的锁定不会阻止一些行为不端的代码在不持有锁的情况下访问和/或更新某些共享状态。这取决于程序员如何正确地完成它

    试图获取其锁的线程被设置为等待


    问题3

    ReentrantLock如何避免死锁

    一般来说,它不是

    在可重入锁定的情况下(即线程在持有锁a的同时尝试获取锁a的情况下),
    ReentrantLock
    实现会注意到持有锁的线程就是获取锁的线程。计数器递增,以便实现知道锁必须释放两次

    在这种情况下,如何使用ReentrantLock避免死锁?可能我们可以使用tryLock()并为无法获取锁的线程提供备用操作

    这是一种方法

    但可能的替代行动是什么

  • 确保所有线程以相同的顺序获取锁。(当线程试图以不同的顺序获取两个或多个线程时,会发生死锁。)

  • 如果
    tryLock
    在持有其他锁时失败,请释放锁,稍等片刻,然后重试

  • 如果线程必须使用锁才能工作,该怎么办

    然后设计逻辑以避免死锁;请参见上面的备选方案


    问题4

    但为什么我们必须多次获得锁

    如上所述,您通常不会。但是,
    ReentrantLock
    的要点是,如果您最终两次获得锁,您不必担心。。。不管什么原因