繁体   English   中英

将ReentrantLock放入HashMap时,锁丢失

[英]Lock is lost when putting ReentrantLock into HashMap

我试图使多个消费者线程侦听一个生产者线程,直到生产者发布一些东西。 我认为可以工作的代码“失去了”进入共享类和从共享类中取出的锁。

在控制器类中,我启动运行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;
    }

消费者类将线程的详细信息放入Map中,如下所示:

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中,我可以看到,当我从Map中读取锁定时,它现在的状态为“未锁定”。 放入线程14时,其状态为“已锁定”。

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

有没有一种方法可以在多个使用者线程和服务器线程之间共享锁,而不会丢失锁?

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

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

你需要调用unlock()ServerLock ,其被锁定的Consumer 我认为调用signal()就足够了。

考虑一下。

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

lock.unlock();

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

如果当前线程不是此锁的持有者,则抛出IllegalMonitorStateException

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM