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

Java生产者消费者程序触发IllegalMonitorStateException且无法终止

问题:生产者消费者模型抛出IllegalMonitorStateException且无法正常终止

代码实现

package com.example.springlearn1.demo;

import java.util.LinkedList;
import java.util.Random;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

class Producer implements Runnable {
    Random rand = new Random();
    ReentrantLock lk;
    Condition cp;
    Condition cc;
    LinkedList<Integer> l;
    int cap;
    public Producer(LinkedList<Integer> l, ReentrantLock lk, int cap, Condition cp, Condition cc) {
        this.l = l;
        this.lk = lk;
        this.cap = cap;
        this.cp = cp;
        this.cc = cc;
    }

    @Override
    public void run() {
        while(true) {
            try {
                Thread.sleep(500);
                lk.lock();
                System.out.println("In producer");
                while(l.size() == cap) {
                    cp.await();
                }
                cc.signalAll();
                if(Thread.currentThread().isInterrupted()) {
                    System.out.println("Producer Aborting now...");
                    break;
                }
                l.addLast(rand.nextInt(4000));
            } catch (InterruptedException e) {
                if(Thread.currentThread().isInterrupted()) {
                    System.out.println("Producer Thread is interrupted.");
                    Thread.currentThread().interrupt();
                }
                //throw new RuntimeException(e);
            } finally {
                lk.unlock();
            }
        }
    }
}

class Consumer implements Runnable {
    ReentrantLock lk;
    LinkedList<Integer> l;
    Condition cp;
    Condition cc;
    int cap;
    public Consumer(LinkedList<Integer> l, ReentrantLock lk, int cap, Condition cp, Condition cc) {
        this.l = l;
        this.lk = lk;
        this.cap = cap;
        this.cp = cp;
        this.cc = cc;
    }

    @Override
    public void run() {
        while(true) {
            try {
                Thread.sleep(1000);
                lk.lock();
                System.out.println("In consumer");
                while(l.size() == 0) {
                    cc.await();
                }
                cp.signalAll();
                if(Thread.currentThread().isInterrupted()) {
                    System.out.println("Aborting now...");
                    break;
                }
                System.out.println("Element is "+l.removeFirst());
            } catch (InterruptedException e) {
                if(Thread.currentThread().isInterrupted()) {
                    System.out.println("Consumer Thread is interrupted.");
                    Thread.currentThread().interrupt();
                }
                //throw new RuntimeException(e);
            } finally {
                lk.unlock();
            }
        }
    }
}
public class ProducerConsumer {
    public static void main(String[] args) throws InterruptedException {
        LinkedList<Integer> queue = new LinkedList<>();
        ReentrantLock lock = new ReentrantLock();
        Condition cp = lock.newCondition();
        Condition cc = lock.newCondition();
        int capacity = 10;

        Thread producerThread = new Thread(new Producer(queue, lock, capacity, cp,cc));
        Thread consumerThread = new Thread(new Consumer(queue, lock, capacity,cp,cc));

        consumerThread.start();
        producerThread.start();
        System.out.println("Started both threads");
        try {
            Thread.sleep(60000); // Run for 1 minute
        } catch (InterruptedException e) {
            System.out.println("Threads interrupted, exiting.");
        }

        producerThread.interrupt();
        consumerThread.interrupt();
        producerThread.join();
        consumerThread.join();
    }
}

报错信息

Exception in thread "Thread-1" java.lang.IllegalMonitorStateException
    at java.base/java.util.concurrent.locks.ReentrantLock$Sync.tryRelease(ReentrantLock.java:175)
    at java.base/java.util.concurrent.locks.AbstractQueuedSynchronizer.release(AbstractQueuedSynchronizer.java:1007)
    at java.base/java.util.concurrent.locks.ReentrantLock.unlock(ReentrantLock.java:494)
    at com.example.springlearn1.demo.Consumer.run(ProducerConsumer.java:89)
    at java.base/java.lang.Thread.run(Thread.java:842)
In producer

问题分析与修复

1. IllegalMonitorStateException 触发原因

这个异常的核心是线程在未持有锁的情况下调用了unlock():

  • 当线程调用Condition.await()时,方法会自动释放当前持有的锁,让其他线程可以获取锁执行逻辑。
  • 如果此时线程被外部中断,await()会抛出InterruptedException进入catch块,但你的代码中finally块会无条件执行lk.unlock(),而此时线程已经不再持有锁,导致重复释放锁,触发异常。

2. 程序无法正常终止的原因

  • 中断处理逻辑错误:当线程在await()或sleep()时被中断,catch块仅重新设置中断标志,但未退出while(true)循环,线程会继续执行循环体,无法正常终止。
  • 未捕获的异常直接终止线程:IllegalMonitorStateException属于运行时异常,未被捕获会直接终止消费者线程,而生产者线程可能仍在运行,导致程序无法按预期在1分钟后退出。

3. 修复方案

调整锁的使用结构

采用双层try-finally结构,外层处理线程中断和sleep异常,内层处理锁的获取与释放,确保unlock()仅在线程持有锁时执行。

修正中断处理逻辑

收到中断信号后直接退出循环,让线程正常终止,无需冗余的中断标志重置。

修复后的代码

package com.example.springlearn1.demo;

import java.util.LinkedList;
import java.util.Random;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

class Producer implements Runnable {
    Random rand = new Random();
    ReentrantLock lk;
    Condition cp;
    Condition cc;
    LinkedList<Integer> l;
    int cap;

    public Producer(LinkedList<Integer> l, ReentrantLock lk, int cap, Condition cp, Condition cc) {
        this.l = l;
        this.lk = lk;
        this.cap = cap;
        this.cp = cp;
        this.cc = cc;
    }

    @Override
    public void run() {
        while (true) {
            try {
                Thread.sleep(500);
                lk.lock();
                // 内层try-finally确保锁在持有状态下被释放
                try {
                    System.out.println("In producer");
                    while (l.size() == cap) {
                        cp.await();
                    }
                    cc.signalAll();
                    if (Thread.currentThread().isInterrupted()) {
                        System.out.println("Producer Aborting now...");
                        break;
                    }
                    l.addLast(rand.nextInt(4000));
                } finally {
                    lk.unlock();
                }
            } catch (InterruptedException e) {
                System.out.println("Producer Thread is interrupted.");
                // 收到中断后直接退出循环
                break;
            }
        }
    }
}

class Consumer implements Runnable {
    ReentrantLock lk;
    LinkedList<Integer> l;
    Condition cp;
    Condition cc;
    int cap;

    public Consumer(LinkedList<Integer> l, ReentrantLock lk, int cap, Condition cp, Condition cc) {
        this.l = l;
        this.lk = lk;
        this.cap = cap;
        this.cp = cp;
        this.cc = cc;
    }

    @Override
    public void run() {
        while (true) {
            try {
                Thread.sleep(1000);
                lk.lock();
                // 内层try-finally确保锁在持有状态下被释放
                try {
                    System.out.println("In consumer");
                    while (l.size() == 0) {
                        cc.await();
                    }
                    cp.signalAll();
                    if (Thread.currentThread().isInterrupted()) {
                        System.out.println("Aborting now...");
                        break;
                    }
                    System.out.println("Element is " + l.removeFirst());
                } finally {
                    lk.unlock();
                }
            } catch (InterruptedException e) {
                System.out.println("Consumer Thread is interrupted.");
                // 收到中断后直接退出循环
                break;
            }
        }
    }
}

public class ProducerConsumer {
    public static void main(String[] args) throws InterruptedException {
        LinkedList<Integer> queue = new LinkedList<>();
        ReentrantLock lock = new ReentrantLock();
        Condition cp = lock.newCondition();
        Condition cc = lock.newCondition();
        int capacity = 10;

        Thread producerThread = new Thread(new Producer(queue, lock, capacity, cp, cc));
        Thread consumerThread = new Thread(new Consumer(queue, lock, capacity, cp, cc));

        consumerThread.start();
        producerThread.start();
        System.out.println("Started both threads");
        try {
            Thread.sleep(60000); // Run for 1 minute
        } catch (InterruptedException e) {
            System.out.println("Threads interrupted, exiting.");
        }

        producerThread.interrupt();
        consumerThread.interrupt();
        producerThread.join();
        consumerThread.join();
        System.out.println("All threads terminated.");
    }
}

修复说明

  • 双层try-finally结构彻底避免了重复解锁的问题,内层finally确保锁一定会在持有状态下被释放。
  • 中断处理逻辑简化,收到中断信号后直接退出循环,确保线程能快速、正常终止。
  • 移除了冗余的中断标志重置操作,因为抛出InterruptedException时中断标志已被清除,且直接退出循环无需保留标志。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.17 11:04:54