代码之家  ›  专栏  ›  技术社区  ›  javaworld

使用ReentrantLock时出现死锁

  •  1
  • javaworld  · 技术社区  · 6 年前

    使用ReentrantLock实现生产者-消费者问题的IM

    public class Processor {
       Lock lock =  new ReentrantLock(true);
       Condition condn = lock.newCondition();
        public void produce() throws InterruptedException{
           lock.lock();
                System.out.println("inside producer method");
                condn.await();
                System.out.println("thread again wakeup");
            lock.unlock();
        }
    
        public void consume() throws InterruptedException{
              lock.lock();
                Thread.sleep(1000);
                condn.signal();
                System.out.println("will i ever be ok ");
                lock.unlock();
        }
    
    
    }
    

    ReentrantLock同步了两种方法,但有时进程会死锁

    开/关 我会没事的吗 内部生产者法

    运行堆转储时

    引用处理程序“2守护程序prio=10操作系统prio=31 cpu=0.26ms已用时间=540.35s tid=0x00007fd5f186f800 nid=0x4603等待条件[0x000070000235700]

     java.lang.Thread.State: RUNNABLE
        at java.lang.ref.Reference.waitForReferencePendingList(java.base@11.0.1/Native Method)
        at java.lang.ref.Reference.processPendingReferences(java.base@11.0.1/Reference.java:241)
        at java.lang.ref.Reference$ReferenceHandler.run(java.base@11.0.1/Reference.java:213)
    
    "Finalizer" #3 daemon prio=8 os_prio=31 cpu=0.67ms elapsed=540.35s tid=0x00007fd5f1883000 nid=0x4303 in Object.wait()  [0x000070000245a000]
       java.lang.Thread.State: WAITING (on object monitor)
        at java.lang.Object.wait(java.base@11.0.1/Native Method)
        - waiting on <0x0000000787f08f80> (a java.lang.ref.ReferenceQueue$Lock)
        at java.lang.ref.ReferenceQueue.remove(java.base@11.0.1/ReferenceQueue.java:155)
        - waiting to re-lock in wait() <0x0000000787f08f80> (a java.lang.ref.ReferenceQueue$Lock)
        at java.lang.ref.ReferenceQueue.remove(java.base@11.0.1/ReferenceQueue.java:176)
        at java.lang.ref.Finalizer$FinalizerThread.run(java.base@11.0.1/Finalizer.java:170)
    
    "Signal Dispatcher" #4 daemon prio=9 os_prio=31 cpu=0.34ms elapsed=540.27s tid=0x00007fd5f1884000 nid=0x3903 waiting on condition  [0x0000000000000000]
       java.lang.Thread.State: RUNNABLE
    
    
    "Thread-0" #12 prio=5 os_prio=31 cpu=1.72ms elapsed=540.07s tid=0x00007fd5f00c7000 nid=0xa303 waiting on condition  [0x0000700002d75000]
       java.lang.Thread.State: WAITING (parking)
        at jdk.internal.misc.Unsafe.park(java.base@11.0.1/Native Method)
        - parking to wait for  <0x0000000787ed4030> (a java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject)
        at java.util.concurrent.locks.LockSupport.park(java.base@11.0.1/LockSupport.java:194)
        at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(java.base@11.0.1/AbstractQueuedSynchronizer.java:2081)
        at Processor.produce(Processor.java:11)
        at RunnableExample$1.run(RunnableExample.java:13)
        at java.lang.Thread.run(java.base@11.0.1/Thread.java:834)
    

    为什么在我使用

        condn.signal();
    
    2 回复  |  直到 6 年前
        1
  •  1
  •   xingbin    6 年前

    如果消费者打电话 consume 先是制片人打电话 produce ,则制作人将错过 signal 然后被卡住。

        2
  •  0
  •   Some Name    6 年前

    你可以用 Phaser 为了这个。关键是 移相器 制片人问:“我错过了一些消费吗?”如果没有,它正在等待,如果是,它将立即进一步进行。下面是一个例子:

    public class Processor {
       private final Phaser phaser = new Phaser(1);
       private volatile int lastPhaseId = 0;
    
        public void produce() throws InterruptedException{
                System.out.println("inside producer method");
                lastPhaseId = phaser.awaitAdvance(lastPhaseId);
                System.out.println("thread again wakeup");
        }
    
        public void consume() throws InterruptedException{
                Thread.sleep(1000);
                phaser.arrive();
                System.out.println("will i ever be ok ");
        }
    }
    

    这对单一消费者有效。如果假设多个消费者 phase.arrive() 需要互斥访问和/或注册方相应更改(取决于所需的语义)