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

在 Controller 类中,我启动运行的线程
服务器服务器= 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)

从Server类的输出int中,我可以看到,当我从Map中读取锁定时,它现在的状态为“Unlocked”。放入线程14时,其状态为“已锁定”。

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

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

最佳答案

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

lock.unlock();

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

关于java - 将ReentrantLock放入HashMap时,锁丢失,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/20894516/

10-08 23:32