我有一个数据结构,其中的成员不是线程安全的,调用者需要锁定资源以进行适当的读写。这是一个最小的代码示例:
class ExampleResource : LockableProjectItem {
override val readWriteLock: ReadWriteLock = ReentrantReadWriteLock()
@RequiresReadLock
val nonThreadSafeMember: String = ""
}
interface LockableProjectItem {
val readWriteLock: ReadWriteLock
}
fun <T : LockableProjectItem, Out> T.readLock(block: T.() -> Out): Out {
try {
readWriteLock.readLock().lock()
return block(this)
} finally {
readWriteLock.readLock().unlock()
}
}
fun <T : LockableProjectItem, Out> T.writeLock(block: T.() -> Out): Out {
try {
readWriteLock.writeLock().lock()
return block(this)
} finally {
readWriteLock.writeLock().unlock()
}
}
annotation class RequiresReadLock
调用 ExampleResource.nonThreadSafeMember
可能如下所示:
val resource = ExampleResource()
val readResult = resource.readLock { nonThreadSafeMember }
为了确保调用者知道需要锁定资源,我希望 IDE 对任何用 @RequiresReadLock
注解且未用readLock
block 。有没有办法在 IntelliJ 中执行此操作,而无需为 IDE 编写自定义插件?
最佳答案
我认为这是一种黑客攻击,但使用 context receivers可能会起作用。但我认为它们不打算以这种方式使用。
您可以声明一个虚拟人 object
充当上下文接收器,并将其作为上下文接收器添加到属性中:
object ReadLock
class ExampleResource : LockableProjectItem {
override val readWriteLock: ReadWriteLock = ReentrantReadWriteLock()
// properties with context receivers cannot have a backing field, so we need to explicitly declare this
private val nonThreadSafeMemberField: String = ""
context(ReadLock)
val nonThreadSafeMember: String
get() = nonThreadSafeMemberField
}
然后在 readLock
,您通过 object
:
fun <T : LockableProjectItem, Out> T.readLock(block: context(ReadLock) T.() -> Out): Out {
try {
readWriteLock.readLock().lock()
return block(ReadLock, this)
} finally {
readWriteLock.readLock().unlock()
}
}
注释:
如果您尝试访问
nonThreadSafeMember
,则会出现错误没有上下文接收器:val resource = ExampleResource() val readResult = resource.nonThreadSafeMember //error
您仍然可以访问
nonThreadSafeMember
无需通过执行例如操作来获取读锁with(ReadLock) { // with(ReadLock) doesn't acquire the lock, just gets the context receiver resource.nonThreadSafeMember // no error }
但是不小心写出这样的东西要困难得多,我认为这正是你想要阻止的。
如果你调用
readLock
内的另一个函数,并且您想要访问nonThreadSafeMember
在该函数内,您应该用context(ReadLock)
标记该函数也。例如fun main() { val resource = ExampleResource() val readResult = resource.readLock { foo(this) } } context(ReadLock) fun foo(x: ExampleResource) { x.nonThreadSafeMember }
上下文接收器通过传播。
关于kotlin - 如果带注释的成员没有被特定 block 包围,则发出 IDE 警告,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/74431315/