Java 具有完全未来的可重入锁定

Java 具有完全未来的可重入锁定,java,multithreading,locking,completable-future,reentrantlock,Java,Multithreading,Locking,Completable Future,Reentrantlock,在CompletableFuture出现之前,如果我想锁定一个变量,我可以这样做: private ReentrantLock myLock = new ReentrantLock(); private List<UUID> myLockableList = new ArrayList<>(); public void doStuff() { try { myLock.lock(); myLockableList.

在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();
      }
    }
  }
private ReentrantLock myLock=new ReentrantLock();
私有列表myLockableList=新建ArrayList();
公共空间
{
尝试
{
myLock.lock();
myLockableList.clear();
}
最后
{
if(myLock.isLocked())
{
myLock.unlock();
}
}
}
(显然,这是一个非常简化的示例,我还有其他方法尝试对myLockableList进行操作)

根据ReentrantLock,将出现3种情况中的1种:

  • 如果锁未被另一个线程持有,则获取锁并立即返回,将锁持有计数设置为1
  • 如果当前线程已经持有锁,那么持有计数将增加1,并且方法立即返回
  • 如果锁由另一个线程持有,则当前线程出于线程调度目的将被禁用,并处于休眠状态,直到获得锁为止,此时锁持有计数设置为1
这一切都很好,也正是我期望它的表现:如果在同一个线程中工作,我应该知道我是否锁定了资源,如果另一个线程锁定了资源,我希望等待它变得可用

输入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();
        }
      }
    });
  }
private ReentrantLock myLock=new ReentrantLock();
私有列表myLockableList=新建ArrayList();
公共完成阶段doStuff()
{
返回CompletableFuture.runAsync(()->{
尝试
{
myLock.lock();
myLockableList.clear();
}
最后
{
if(myLock.isLocked())
{
myLock.unlock();
}
}
});
}
我希望未来的行为也会如此。但是,CompletableFuture可能会使用一个新线程执行上述操作,或者(如果我的理解正确的话)可能会使用一个已经在使用的线程。如果发生第二种情况(被重用的线程已经获得了锁),那么我的锁不会暂停线程并等待锁,相反,它可能会立即返回(看起来它已经获得了锁)

我似乎在文档中找不到明确的答案。我对形势的理解正确吗?如果是这样,那么在使用CompletableFuture时,我们应该如何锁定资源

非常感谢你的建议

除了评论中推荐的内容外,还有很多值得一读的信息

例如:

ReentrantLock属于上次成功锁定但尚未解锁的线程

您的示例使用,Javadoc说您不应该这样做:

此方法设计用于监视系统状态,而不是用于同步控制

最后,Javadoc包含一个很好的使用示例,在“try”块中显示
lock()
,在“Finally”块中显示
unlock()

建议在调用后立即使用try块锁定,最典型的是在构建之前/之后,例如:


“它可能使用已在使用的线程”。不,可能不会,因为线程正在使用中。它可能使用一个空闲线程,该线程将尝试正常获取锁。您的
finally
子句错误,您不应该检查
isLocked()
。您可以在
try
的开头使用
lock()
,在
finally
子句中使用
unlock()
。没有如果。好的,谢谢。所以我的理解是不正确的:)所以我对锁定没有问题。好吧,你是这样做的(使用
isLocked()
),所以你可能想看看这个,我会看一看-谢谢,W.R.T
isLocked()
,我在
lock()
之前有一个方法处理一些东西,这取决于结果,可能意味着
lock()
未被调用。发生这种情况时,调用
unlock()
会引发非法异常。我本可以使用嵌套的try-finally块,但那会变得混乱
isLocked()
的常见(尽管非常罕见)用例是与
tryLock()一起使用的。更好的方法是使用更高级别的并发原语,这样就不需要处理原始锁。我建议您阅读并发教程。我同意您所说的一切-我在没有首先查找的情况下将
isLocked()
方法放进去了。我真正的误解来自于思考完整的未来。
 class X {
   private final ReentrantLock lock = new ReentrantLock();
   // ...

   public void m() {
     lock.lock();  // block until condition holds
     try {
       // ... method body
     } finally {
       lock.unlock()
     }
   }
 }