使用ReentrantLock时出现死锁

时间:2019-02-24 06:48:10

标签: java multithreading

使用ReentrantLock实施生产者消费者问题

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同步了两种方法,但有时该进程与之死锁了

o / p 我会好起来吗 内部生产者方法

运行堆转储

引用处理程序”#2守护程序prio = 10 os_prio = 31 cpu = 0.26ms经过的时间= 540.35s tid = 0x00007fd5f186f800 nid = 0x4603等待条件[0x0000700002357000]

 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 个答案:

答案 0 :(得分:1)

如果消费者先致电consume,然后生产者致电produce,则生产者将错过signal并陷入困境。

答案 1 :(得分:0)

您可以使用Phaser。问题在于,对于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()需要互斥访问和/或注册方进行了相应更改(取决于您需要的语义)