如果ReentrantLock被锁定,请等待,但不要锁定锁

时间:2018-04-06 15:16:28

标签: java multithreading reentrantlock

我的代码中有一个ReentrantLock,想要每秒清除一次数组;我不希望其他线程在清除时更改阵列,但如果我当前没有清除阵列,则其他线程不必等待,如下所示:

public void addToArray(Object a) {
    lock.waitforunlock(); //not a real method just to clarify my intentions
    array.add(a);
}

为了更好地阐明我的意图,我将解释这个过程:netty eventloop将调用我的网络处理程序,然后网络处理程序将从之前调用addToArray方法,每秒一次我永远不会是Netty线程的主线程将清除数组,在这个时候每个netty线程都必须等到这个结束!注意:addToArray方法是线程的,我不想同步它,因为那时事件循环的漏洞是没用的。

2 个答案:

答案 0 :(得分:3)

没有API方法可以完全满足您的要求。

最有效的方法是:

try {
    lock.lock();
} finally {
    lock.unlock();
}

换句话说,暂时抓住锁然后释放它。

但这是问题所在。

  1. 一般情况下,当你释放锁定时,其他一些线程可能会立即抓住它。因此,array.add()调用可能会与其他线程同时发生array。即使你的用例意味着抓住锁的另一个线程极不可能,它仍然会发生;例如如果你的服务器负载很重,当前线程在释放锁后立即被抢占。

  2. 据推测,您正在array.add()执行内存写入。除非通过适当的同步执行,否则这些更新可能对其他线程不可见。 (你说“addToArray方法是线程保护的”,但如果没有明确,详细的解释你的意思,我会对说这个代码是线程安全感到不舒服。 )

  3. 如果您在此处尝试执行的操作是array.add()之后发生了其他事情,那么测试锁定/等待它被释放并不会告诉您事件是否真的发生了。它告诉你的一切都是在测试成功的那一刻没有发生。

  4. 简而言之,我怀疑在进行更新之前等待锁定被释放实际上是一个正确的解决方案......无论你如何实现等待。

    另一种看待这个的方法。

    • 如果array.add()完全是线程安全的,并且无论其他线程持有什么线程都能正常工作,为什么需要来测试锁?只需调用方法。

    • 如果您实际上尝试在与正在发布的锁定一致的某个事件之后发生array.add()调用,请使用循环障碍或类似操作。

    注意:我阅读并尝试理解你的解释,但我迷失了你所说的话。由于“语言问题”,我认为。

答案 1 :(得分:0)

据我了解,你有两个或多个单独的线程改变列表:主线程偶尔清除列表,netty线程添加到列表中。您希望确保他们不会同时尝试修改列表。

最简单的解决方案是使用线程安全列表,并确保主线程使用List.clear()方法清除列表。这样,clear()调用将是原子的 - 一旦启动它将在任何其他访问列表之前完成 - 所以你不必担心添加到列表"在&#34中间; clear()调用。

在对另一个答案的评论中,您提到您使用的是CopyOnWriteArrayList,它是线程安全的。因此,您只需调用add()添加到列表中的代码,而无需担心同步;如果清除列表,add()调用将自动等待,否则继续。您也可以从主线程中删除ReentrantLock的使用,除非有其他原因,除了保护此列表外,还要使用锁。