我还需要找到解决方案,因此搜索了 Java Concurrency API 并遇到了StampedLock。该项目使用 Java 8。
我正在使用与本机库通信并包含长期配置对象的重线程异步数据服务,有时需要复杂的并发逻辑;谢天谢地,这对于 StampedLock 类来说相对简单。
StampedLock 有一个名为tryOptimisticRead 的方法,它不等待,它只是以长时间时间戳的形式返回状态,其中零 (0) 表示持有独占锁。然后我会延迟一秒钟,但您可以直接使用该功能而不会有任何延迟。
这是我检测是否存在独占锁的方法,该范例用于多个位置并包括错误处理:
int delayCount = 0;
//Makes sure that if there is data being written to this field at
// this moment, wait until the operation is finished writing the
// updated data.
while (data1StampedLock.tryOptimisticRead() == 0)
{
try
{
delay(WRITE_LOCK_SHORT_DELAY);
delayCount += 1;
}
catch (InterruptedException e)
{
logError("Interrupted while waiting for the write lock to be
released!", e);
Thread.currentThread().interrupt();
//There may be an issue with the JVM if this occurs, treat
// it like we might crash and try to release the write lock.
data1StampedLock.tryUnlockWrite();
break;
}
if (delayCount * WRITE_LOCK_SHORT_DELAY > TimeUnit.SECONDS.toMillis(1))
{
logWarningWithAlert("Something is holding a write lock on" +
" the data for a very, very long time (>1s). This may" +
" indicate a problem that could cause cascading" +
" problems in the near future." +
" Also, the value for the data that is about to be" +
" retrieved could potentially be invalid.");
break;
}
}
long nonExclusiveLockStamp = data1StampedLock.readLock();
Data data1NonVolatile = data1;
data1StampedLock.unlockRead(nonExclusiveLockStamp);
return data1NonVolatile;
StampedLock 上的读锁是非排他的,就像从线程安全的 Map 或 HashTable 中读取一样,它是多读/单写的。
这是我如何使用排他锁与正在写入实例数据的其他线程进行通信:
long d1LockStamp = data1StampedLock.writeLock();
this.data1 = data1;
data1StampedLock.unlockWrite(d1LockStamp);
因此,如果您只想检查某物是否在任何给定时刻被锁定,您只需要像以下语句这样简单的东西来获取状态:
boolean data1IsLocked = data1StampedLock.tryOptimisticRead() == 0;
然后检查那个布尔值。
当然,其他答案中提到的警告和Here Be Dragons信息(即信息立即过时),但如果你真的需要锁定某些东西并从另一个线程检查该锁定,这在我看来是最合理、最安全、最有效的使用java.util.concurrency包的方式,没有外部依赖。