使用条件变量读写锁

时间:2017-01-22 05:16:05

标签: java multithreading

我有一个我实现的fifo队列,它有两个方法add()remove(),它们都在队列上执行写操作。为了使其线程安全,我正在使用ReentrantLock。我有两个条件,(i)如果队列为空并且试图删除,则阻塞一个线程; (ii)如果队列已满并且尝试添加,则阻塞线程。现在,我想实现一个peek操作,它允许多个线程同时执行peek,但没有线程能够写入。如果我使用ReentrantLock我无法实现,因为我必须获得锁并且它是互斥的。我可以在ReentrantReadWriteLock中进行查看操作,但它没有我需要的条件变量。有什么建议吗?

2 个答案:

答案 0 :(得分:0)

为什么peek()需要锁定?

peek() 不可能提供有保证的正确答案。

if (q.peek() != NULL) {
    ... q could be empty at this point because some other consumer
        could have removed the last item after the peek() returned...
} else {
    ... q could be non-empty at this point because a consumer could
        have added new items after the peek() returned...
}

如果只有一个使用者,那么peek()方法会更有用。在那种情况下:

if (q.peek() != NULL) {
    ...q MUST be non-empty here, because there is no other thread that 
       could have removed anything from the queue...
}

当然,peek()可能需要锁定的一个原因是你实现了一个链接的队列。在这种情况下,您可能需要锁定以防止peek()方法跟踪错误的指针并使程序崩溃。

答案 1 :(得分:0)

如果您只是在寻找解决方案,快速解决方法是在释放锁之前创建重复数组(队列),但在每次更新之后。这个数组可能是peek()的引用变量。

我不确定java是否在线程时支持这个,但你可以创建另一个变量,比如查询,它是对原始队列的引用。这将允许您立即查看peek()的更新。虽然我在Java方面略显新手,但大多数语言通过使用以下内容实现此目的:

query = &queue;

& sign是引用运算符的传递。