繁体   English   中英

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

[英]if ReentrantLock is locked wait but dont lock the lock

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

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

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

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

最有效的方法是这样的:

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

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

但这是问题所在。

  1. 通常,在您释放锁定的瞬间,其他一些线程可能会立即抓住它。 所以,你的array.add()调用可能与一些其他线程做的事情同时发生array 即使你的用例意味着抓住锁的另一个线程极不可能,它仍然会发生; 例如,如果您的服务器处于严重负载状态,并且当前线程在释放锁定后立即被抢占。

  2. 大概是你在array.add()中执行内存写入。 除非它们以适当的同步执行,否则这些更新可能对其他线程不可见 (你说“addToArray方法是防线程的” ,但如果没有明确,详细的解释你的意思,我会说这段代码是线程安全的。)

  3. 如果你在这里尝试做的是在发生其他事情之后的array.add() ,那么测试锁/等待它被释放并不会告诉你事件是否真的发生了。 所有它告诉你的是,在测试成功的那一刻它没有发生。

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


另一种看待这个的方法。

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

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


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

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

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

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

暂无
暂无

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

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