当用户尝试在多线程上下文中使用类的非线程安全方法时,有没有办法抛出异常?我想问题主要是检测到多个线程正在尝试使用该方法。或者,我可以在函数声明中使用“not_synchronous”关键字/标签吗?
4 回答
您可以在允许线程运行之前检查该方法是否已在使用中 - 但这与使用锁没有太大区别(注意:我的示例不是可重入的):
private static final AtomicBoolean used = new AtomicBoolean();
public static void unsafe() throws InterruptedException {
if(!used.compareAndSet(false, true)) {
throw new IllegalStateException();
}
//do you stuff
used.set(false);
}
没有简单的方法可以做到这一点,不。如果您检测到多个线程正在使用一个方法,那么您很可能必须使用线程安全集合等。如果您正在做所有这些,那么您可能还必须使方法本身成为线程安全的。
扩展格雷的答案:假设您想这样做(检测一个方法何时被多个线程使用)。一个幼稚(且不正确)的实现可能如下所示:
volatile boolean methodBeingUsed = false;
public void doSomething() {
if (methodBeingUsed) throw new IllegalStateException("You can't do that!");
try {
methodBeingUsed = true;
// do something...
} finally {
methodBeingUsed = false;
}
}
好吧,好吧……但是两个线程都可以通过第一次if (methodBeingUsed)
检查并同时进入临界区。所以现在也许我们尝试添加一个锁来保护methodBeingUsed
标志:
Lock methodLock = new ReentrantLock();
volatile boolean methodBeingUsed = false;
public void doSomething() {
try {
lock.lock();
if (methodBeingUsed) throw new IllegalStateException("You can't do that!");
methodBeingUsed = true;
} finally {
lock.unlock();
}
try {
// do something...
} finally {
try {
lock.lock();
methodBeingUsed = false;
} finally {
lock.unlock();
}
}
}
当然,这假设 doSomething() 不能递归调用自身。如果可以,那么您还必须跟踪调用线程。添加更多检查以解决我现在没有考虑的其他条件,并且很容易看出花在同步逻辑以检测多个线程正在使用的方法上的工作最好只花在使方法线程上- 安全开始。
实际上,如果您的目标是确定“多个线程正在尝试使用此方法”,并且您没有将其限制为“多个方法......同时” - 那么(请原谅我)Alex 的代码可以修改很好:
更改
methodBeingUsed
为threadOwningMethod
,并将其设置为线程而不是true
。您不需要在最后清除它 - 保存那些锁定/解锁步骤。一旦拥有,就拥有了(资本主义猪!!)。
threadOwningMethod
可以预先检查它是否匹配当前线程(A-OK)或不匹配(抛出异常),而不必产生锁定。如果它没有设置(null),那么你会招致一次性命中:check/lock/check&set/unlock;这是安全的,因为threadOwningMethod
标记为 volatile。