我的代码中有一个 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 方法是线程安全的,我不想同步它,因为这样事件循环的漏洞点就没用了。
最佳答案
没有任何 API 方法可以完全满足您的要求。
最有效的方法是这样的:
try {
lock.lock();
} finally {
lock.unlock();
}
换句话说,暂时捕获锁然后释放它。
但是问题来了。
一般来说,在您释放锁的那一刻,其他线程可能会立即获取它。因此,您的
array.add()
调用可能会与其他线程对array
执行操作同时发生。即使您的用例意味着另一个线程获取锁的可能性极小,它仍然可能发生;例如如果您的服务器负载严重,当前线程在释放锁后立即被抢占。大概您正在
array.add()
中执行内存写入。除非通过适当的同步来执行,否则这些更新可能对其他线程不可见。 (你说“addToArray 方法是线程安全的”,但是如果没有清晰、详细地解释你的意思,我会不愿意说这个代码是线程安全的。 )如果您在此处尝试执行的是在发生其他事情后
array.add()
,那么测试锁/等待它被释放不会告诉您如果事件真的发生了。它只是告诉您,这并不是在测试成功的那一刻发生的。
简而言之,我怀疑在进行更新之前等待锁被释放实际上是一个正确的解决方案......无论您如何实现等待。
另一种看待这个问题的方式。
如果
array.add()
是完全线程安全的,并且无论其他线程是否持有锁都可以正常工作,为什么您需要来测试锁?只需调用该方法即可。如果您实际上尝试在某个与释放锁同时发生的事件之后发生
array.add()
调用,请使用循环屏障或类似的方法。
注意:我阅读并试图理解您的解释,但我对您所说的内容感到困惑。我认为是由于“语言问题”。
关于java - 如果 ReentrantLock 已锁定,则等待但不锁定该锁,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49695996/