在CompletableFuture世界之前,如果我想锁定一个变量,我可以这样做:
private ReentrantLock myLock = new ReentrantLock();
private List<UUID> myLockableList = new ArrayList<>();
public void doStuff()
{
try
{
myLock.lock();
myLockableList.clear();
}
finally
{
if (myLock.isLocked())
{
myLock.unlock();
}
}
}(显然,这是一个非常简单的例子,我还有其他方法试图在myLockableList上操作)。
根据ReentrantLock的说法,三种场景中的一种会发生:
这一切都很好,而且正是我期望它的表现:如果在同一个线程中工作,我应该知道我是否锁定了资源,如果另一个线程已经锁定了资源,我希望等到它可用为止。
进入CompletableFutures..。
private ReentrantLock myLock = new ReentrantLock();
private List<UUID> myLockableList = new ArrayList<>();
public CompletionStage<Void> doStuff()
{
return CompletableFuture.runAsync(() -> {
try
{
myLock.lock();
myLockableList.clear();
}
finally
{
if (myLock.isLocked())
{
myLock.unlock();
}
}
});
}我希望CompletableFuture的行为也是一样的。但是,CompletableFuture可能使用一个新线程来执行上面的内容,或者(如果我的理解是正确的)它可能使用一个已经在使用的线程。如果第二个发生了(被重用的线程已经获得了锁),那么我的锁不会暂停线程并等待锁,相反,它可能会立即返回(看起来就像获得了锁一样)!
我似乎在文档中找不到明确的答案。我正确地理解了情况吗?如果是这样,那么在使用CompletableFuture时我们应该如何锁定资源呢?
非常感谢您的建议!
发布于 2020-01-14 16:47:02
除了评论中推荐的并发教程之外,用于ReentrantLock的Javadoc还有很好的信息值得阅读。
例如,这一点:
ReentrantLock属于线程最后成功锁定的线程,但尚未解除锁定。
您的示例使用isLocked(),Javadoc说您不应该这样做:
该方法用于监测系统状态,而不是用于同步控制。
最后,Javadoc包含一个很好的使用示例,在"try“块中显示lock(),在" Finally”块中显示unlock()。
推荐的做法是始终立即按照调用使用try块锁定,最典型的情况是在构造之前/之后,例如:
class X {
private final ReentrantLock lock = new ReentrantLock();
// ...
public void m() {
lock.lock(); // block until condition holds
try {
// ... method body
} finally {
lock.unlock()
}
}
}https://stackoverflow.com/questions/59732830
复制相似问题