You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Java生产者-消费者模型中由竞态条件复现死锁?

Turning Race Conditions into Deadlock in Producer-Consumer Model

Got it, let's walk through how to turn that race-prone producer-consumer pseudocode into a deadlock scenario. First, let's fill in the missing bits of the original pseudocode to make it complete (since your snippet cut off):

int itemCount = 0;
#define BUFFER_SIZE 5

procedure producer() {
    while (true) {
        item = produceItem();
        if (itemCount == BUFFER_SIZE) {
            sleep();
        }
        putItemIntoBuffer(item);
        itemCount = itemCount + 1;
        if (itemCount == 1) {
            wakeup(consumer);
        }
    }
}

procedure consumer() {
    while (true) {
        if (itemCount == 0) {
            sleep();
        }
        item = removeItemFromBuffer();
        itemCount = itemCount - 1;
        if (itemCount == BUFFER_SIZE - 1) {
            wakeup(producer);
        }
        consumeItem(item);
    }
}

Original Problem: Race Conditions (No Deadlock)

This code has critical race conditions (e.g., multiple producers/consumers reading/writing itemCount simultaneously, leading to incorrect buffer counts or lost wakeups), but it won't deadlock. Deadlock requires specific conditions to be met, so we need to introduce intentional mistakes in how we add synchronization.

How to Introduce Deadlock

Deadlock happens when four conditions are satisfied:

  1. Mutual Exclusion: Resources can't be shared between threads.
  2. Hold and Wait: A thread holds one resource while waiting for another.
  3. No Preemption: Resources can't be forcefully taken from a thread.
  4. Circular Wait: Threads wait on each other in a cycle.

We'll introduce two separate locks and make the producer and consumer acquire them in opposite orders to trigger circular wait. Here's the modified pseudocode with deadlock:

int itemCount = 0;
#define BUFFER_SIZE 5
lock bufferLock;    // Protects buffer add/remove operations
lock countLock;     // Protects reads/writes to itemCount

procedure producer() {
    while (true) {
        item = produceItem();
        
        // Producer first grabs bufferLock, then tries to get countLock
        acquire(bufferLock);
        
        // Add a small delay to increase chance of race for locks
        sleep(100);
        
        acquire(countLock);
        
        if (itemCount < BUFFER_SIZE) {
            putItemIntoBuffer(item);
            itemCount++;
            if (itemCount == 1) {
                wakeup(consumer);
            }
        }
        
        release(countLock);
        release(bufferLock);
    }
}

procedure consumer() {
    while (true) {
        // Consumer first grabs countLock, then tries to get bufferLock
        acquire(countLock);
        
        // Add a small delay to increase chance of race for locks
        sleep(100);
        
        acquire(bufferLock);
        
        if (itemCount > 0) {
            item = removeItemFromBuffer();
            itemCount--;
            if (itemCount == BUFFER_SIZE - 1) {
                wakeup(producer);
            }
            consumeItem(item);
        }
        
        release(bufferLock);
        release(countLock);
    }
}

Why This Deadlocks

Let's walk through the deadlock scenario:

  1. The producer starts first and successfully acquires bufferLock.
  2. Before the producer can grab countLock, the consumer starts and acquires countLock.
  3. Now the producer is waiting for countLock (held by the consumer), and the consumer is waiting for bufferLock (held by the producer).
  4. Neither thread can release their held lock until they get the other one, so they're stuck forever.

This hits all four deadlock conditions:

  • Mutual Exclusion: Each lock is held by only one thread at a time.
  • Hold and Wait: Producer holds bufferLock while waiting for countLock; consumer holds countLock while waiting for bufferLock.
  • No Preemption: Locks can't be taken from either thread—they have to release voluntarily.
  • Circular Wait: Producer waits on consumer's lock, consumer waits on producer's lock, creating a cycle.

Triggering the Deadlock

Run the producer and consumer threads concurrently. The added sleep(100) calls increase the odds that each thread grabs its first lock before the other can grab both, but even without the delay, high concurrency will eventually hit this scenario.

内容的提问来源于stack exchange,提问作者CB95

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.21 08:25:32