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

基于ReentrantLock实现H2O持续生成线程报错问题排查

分析你的代码问题与解决方案

首先,我们来拆解你遇到的IllegalMonitorStateException异常以及代码中的其他逻辑问题:

一、异常的直接原因:锁的获取位置错误

你在hydrogenProducer和oxygenProducer方法中,把lock.lock()放在了try代码块内部:

try {
 lock.lock();
 // ... 其他代码
} finally {
 lock.unlock();
}

这种写法存在风险:如果lock.lock()抛出异常(比如安全管理器阻止获取锁、或者极端情况下的JVM错误),线程并没有成功获取锁,但finally块仍然会执行lock.unlock()。而ReentrantLock的unlock()方法要求调用线程必须持有锁,否则就会抛出IllegalMonitorStateException。

正确的写法应该是在try块之外先获取锁,确保只有获取锁成功后才进入try块:

lock.lock(); // 先获取锁,失败则不会进入后续逻辑
try {
 // ... 业务逻辑
} finally {
 lock.unlock();
}

二、核心逻辑错误:未实现H₂O的生成规则

你的代码完全没有实现“每两个H和一个O组成一组”的需求,只是让三个线程各自打印字符,没有任何等待协调逻辑,具体问题包括:

  • O线程调用错误方法:在main方法中,创建生成O的线程时,错误调用了hydrogenProducer(),导致O线程也打印h,完全无法生成氧原子。
  • 缺乏等待条件:没有维护H和O的计数,也没有让线程在条件不满足时等待(比如H不足两个时,O线程需要等待;O不足一个时,H线程需要等待),无法保证生成的是合法的H₂O分子。

三、修正后的完整代码

下面是使用Lock和生产者消费者模式实现的正确代码,确保每次生成两个H和一个O的组合:

package com.threads.reentrantlock.consumerproducer;

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class H2OProducer {
    // 全局锁
    private static final Lock lock = new ReentrantLock(true);
    // 等待条件:H的数量足够生成H2O
    private static final Condition hCondition = lock.newCondition();
    // 等待条件:O的数量足够生成H2O
    private static final Condition oCondition = lock.newCondition();
    // 记录当前已生成的未配对的H数量
    private static int hCount = 0;

    public static void main(String[] args) {
        // 两个生成H的线程
        Thread h1 = new Thread(() -> {
            try {
                hydrogenProducer();
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
                e.printStackTrace();
            }
        });
        Thread h2 = new Thread(() -> {
            try {
                hydrogenProducer();
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
                e.printStackTrace();
            }
        });
        // 一个生成O的线程
        Thread o = new Thread(() -> {
            try {
                oxygenProducer();
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
                e.printStackTrace();
            }
        });

        h1.start();
        h2.start();
        o.start();

        try {
            h1.join();
            h2.join();
            o.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public static void hydrogenProducer() throws InterruptedException {
        while (true) { // 持续生成H
            lock.lock();
            try {
                // 如果当前H数量已经是2,等待O线程消耗后再生成
                while (hCount == 2) {
                    hCondition.await();
                }
                System.out.print("H");
                hCount++;
                // 如果H数量达到2,唤醒O线程可以生成O了
                if (hCount == 2) {
                    oCondition.signal();
                }
            } finally {
                lock.unlock();
            }
            // 模拟生成间隔,避免太快输出
            Thread.sleep(500);
        }
    }

    public static void oxygenProducer() throws InterruptedException {
        while (true) { // 持续生成O
            lock.lock();
            try {
                // 如果当前H数量不足2,等待H线程生成足够的H
                while (hCount < 2) {
                    oCondition.await();
                }
                System.out.println("O"); // 打印O后换行,代表一个H2O分子生成完成
                hCount = 0; // 重置H计数,准备下一个H2O
                // 唤醒H线程继续生成H
                hCondition.signalAll();
            } finally {
                lock.unlock();
            }
            // 模拟生成间隔
            Thread.sleep(500);
        }
    }
}

修正后的逻辑说明:

  1. 用hCount记录当前已生成的未配对的H数量。
  2. H线程:当hCount达到2时,进入等待,直到O线程消耗后重置计数。
  3. O线程:当hCount不足2时,进入等待,直到H线程生成足够的H后唤醒它。
  4. 每次O生成后,重置hCount并唤醒所有H线程,开始下一轮的H₂O生成。
  5. 所有线程持续运行(通过while(true)实现持续生成)。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.12 04:52:34