当前位置: 首页 > 知识库问答 >
问题:

将ReentrantLock放入HashMap时,锁丢失

凌宏大
2023-03-14

我试图让多个消费者线程侦听一个生产者线程,直到生产者有东西要发布。我认为可以工作的代码在放入和取出共享类时“丢失”了锁。

在控制器类中,我启动运行Server server=new Server()的线程;

    Thread serverThread = new Thread(server,"Server");
    serverThread.start(); 

    Consumer consumer = new Consumer();
    Thread consumerThread;
    for (int i =0;i<6;i++){
        consumerThread = new Thread(consumer,"Consumer No:"+i);
    consumerThread.start();
    server.threadRefs[i]= consumerThread;
    }

consumer类将线程的详细信息放入映射中,如下所示:

public class Consumer implements Runnable {

private ReentrantLock lock = new ReentrantLock();
private Condition cond = lock.newCondition();

@Override
public void run() {

    long threadID = Thread.currentThread().getId();
    while (true) {
        try {

            lock.lock();

            MDRequest.threadLocks.put(threadID, lock);
            System.out.println("Thread " + threadID + "  lock = " + lock.toString());

            cond.await();
            System.out.println("Thread " + threadID + "  done waiting");
        } catch (InterruptedException ex) {
            System.out.println("Interruped " + threadID);
        } finally {
            lock.unlock();
        }

        System.out.println("Finished " + threadID);
    }

}

共享类仅为:

public class MDRequest {

    protected static ConcurrentHashMap<Long, ReentrantLock> threadLocks = new ConcurrentHashMap<Long, ReentrantLock>();

服务器有以下run()方法:

public void run() {
    try {
        Thread.sleep(5000);
    } catch (InterruptedException ex) {
        Logger.getLogger(Server.class.getName()).log(Level.SEVERE, null, ex);
    }
    Set<Long> keys = MDRequest.threadLocks.keySet();
    Long[] threadIDs = keys.toArray(new Long[1]);

    // generates a random series of numbers for each thread and notifies threads about them 
    while (true) {


        Random random = new Random();
        int threadRef = random.nextInt(5);

        System.out.println("About to signal thread " + threadIDs[threadRef].toString());

        // notify the thread of the data 
        ReentrantLock lock = MDRequest.threadLocks.get(threadIDs[threadRef]);
        System.out.println("Thread " + threadIDs[threadRef].toString() + "  lock = " + lock.toString());

        Condition cond = lock.newCondition();
        cond.signal();
        lock.unlock();

    }

输出如下:

Thread 11  lock = java.util.concurrent.locks.ReentrantLock@272d7a10[Locked by thread Consumer No:0]
Thread 12  lock = java.util.concurrent.locks.ReentrantLock@272d7a10[Locked by thread Consumer No:1]
Thread 13  lock = java.util.concurrent.locks.ReentrantLock@272d7a10[Locked by thread Consumer No:2]
Thread 14  lock = java.util.concurrent.locks.ReentrantLock@272d7a10[Locked by thread Consumer No:3]
Thread 15  lock = java.util.concurrent.locks.ReentrantLock@272d7a10[Locked by thread Consumer No:4]
Thread 16  lock = java.util.concurrent.locks.ReentrantLock@272d7a10[Locked by thread Consumer No:5]
About to signal thread 14
Thread 14  lock = java.util.concurrent.locks.ReentrantLock@272d7a10[Unlocked]
Exception in thread "Price Server" java.lang.IllegalMonitorStateException
    at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.signal(AbstractQueuedSynchronizer.java:1885)
    at faster.Server.run(Server.java:46)
    at java.lang.Thread.run(Thread.java:695)

从服务器类的输出int中,我可以看到,当我从映射中读取锁时,它现在的状态为“Unlocked”。当它被放入时,它的状态为锁定在线程14上。

为什么对ReentrantLock的引用会“丢失”锁?

是否有一种方法可以在多个消费者线程和服务器线程之间以不丢失锁的方式共享锁?

共有2个答案

廉展鹏
2023-03-14

问题是Server类中的线程尝试解锁但没有锁定Lock

lock.unlock();

请参阅ReentrantLock文档,其中明确说明:

如果当前线程不是此锁的持有者,则会引发非法监视器状态异常(IllegalMonitorStateException)。

云霖
2023-03-14

您面临的问题可能是由于服务器中的以下行

Condition cond = lock.newCondition();
cond.signal();
lock.unlock();

您是否需要从Server调用lock()以获取被消费者锁定的Lock?我认为调用信号()就足够了。

想想这个。

 类似资料:
  • 问题内容: 我当前正在从文本文件中读取200万行,如上一个问题中所述 。Java读取200万行文本文件的最快方法 现在,我将这些信息存储到HashMap中,并希望通过TreeMap对其进行排序,因为我想使用ceilingkey。以下方法正确吗? 问题答案: HashMap hashMap = new HashMap (); TreeMap treeMap = new TreeMap (); tre

  • 主要内容:1 ReentrantLock的概述,1.1 ReentrantLock的API方法,1.2 可重入,1.3 公平与非公平,2 ReentrantLock的原理,2.1 基本结构,2.2 构造器,2.3 非公平模式加锁原理,2.4 公平模式加锁原理,2.5 解锁原理,3 ReentrantLock总结Java的ReentrantLock的源码实现,包括加锁、解锁的源码,以及公平性、重入性的实现! 1 ReentrantLock的概述 public class ReentrantLock

  • 本文向大家介绍详解java并发之重入锁-ReentrantLock,包括了详解java并发之重入锁-ReentrantLock的使用技巧和注意事项,需要的朋友参考一下 前言 目前主流的锁有两种,一种是synchronized,另一种就是ReentrantLock,JDK优化到现在目前为止synchronized的性能已经和重入锁不分伯仲了,但是重入锁的功能和灵活性要比这个关键字多的多,所以重入锁是

  • 本文向大家介绍Java源码解析之可重入锁ReentrantLock,包括了Java源码解析之可重入锁ReentrantLock的使用技巧和注意事项,需要的朋友参考一下 本文基于jdk1.8进行分析。 ReentrantLock是一个可重入锁,在ConcurrentHashMap中使用了ReentrantLock。 首先看一下源码中对ReentrantLock的介绍。如下图。ReentrantLoc

  • 问题内容: 我正在寻找仅使用JSTL设置HashMap的键值对。这可能吗? 我知道如何检索键值对,但是还没有找到设置它们的方法。 任何帮助,将不胜感激。 使用JSTL检索HashMap键/值对的示例: 问题答案: 您可以使用。

  • 问题内容: 我建立了一个由Hashmap中定义的nameValue对组成的json对象 我遇到的问题是当我调用时: 它像这样添加nameValue对: 代替 有什么想法吗? 谢谢 问题答案: 遍历HashMap并放入jsonObject: