【问题标题】:Prevent non thread-safe method to be used in multithreaded context防止在多线程上下文中使用非线程安全方法
【发布时间】:2012-07-31 16:05:38
【问题描述】:

当用户尝试在多线程上下文中使用类的非线程安全方法时,有没有办法抛出异常?我想问题主要是检测到多个线程正在尝试使用该方法。或者,我可以在函数声明中使用“not_synchronous”关键字/标签吗?

【问题讨论】:

  • 对于大约相同数量的工作,您可以使方法线程安全。
  • @Alex 工作量可能会减少 ;-)
  • 如果您真的担心多线程访问,为什么不将该方法设为线程安全?
  • 声明它为初学者同步? ;)
  • 我们的 Java 核心库类在设计上不是线程安全的,所以 Frank 的问题很有趣。也就是说,正如所有人都指出的那样 - 您可能会通过检查而失去性能优势。你可以安全(r),也可以快速(er),但你不能拥有一切。

标签: java multithreading thread-safety


【解决方案1】:

您可以在允许线程运行之前检查该方法是否已在使用 - 但这与使用锁没有太大区别(注意:我的示例不是可重入的):

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);
}

【讨论】:

  • 比我的例子更理智:)
【解决方案2】:

没有简单的方法可以做到这一点,不。如果您检测到多个线程正在使用一个方法,那么您很可能必须使用线程安全集合等。如果您正在做所有这些,那么您可能还必须使方法本身成为线程安全的。

【讨论】:

  • 另一种(可能很弱)选项是标准集合的迭代器使用的策略。
  • 有趣的想法,但不能保证它会起作用,但是@assylias。不保证你会参加比赛。
【解决方案3】:

扩展 Gray 的回答:假设您想这样做(检测一个方法何时被多个线程使用)。一个幼稚(且不正确)的实现可能如下所示:

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() 不能递归调用自身。如果可以,那么您还必须跟踪调用线程。添加更多检查以解决我现在没有考虑的其他条件,并且很容易看出花在同步逻辑以检测多个线程正在使用的方法上的工作最好只花在使方法线程上- 安全开始。

【讨论】:

    【解决方案4】:

    实际上,如果您的目标是确定“多个线程正在尝试使用此方法”,并且您没有将其限制为“多个方法......同时” - 那么(请原谅我)Alex 的代码可以很好地适应:

    1. methodBeingUsed更改为threadOwningMethod,并将其设置为线程而不是true

    2. 您不需要在最后清除它 - 保存那些锁定/解锁步骤。一旦拥有,就拥有了(资本主义猪!!)。

    3. threadOwningMethod 可以预先检查以查看它是否匹配当前线程 (A-OK) 或不匹配(抛出异常),而无需产生锁定。如果它没有设置(null),那么你会招致一次性命中:check/lock/check&set/unlock;这是安全的,因为 threadOwningMethod 被标记为 volatile。

    【讨论】:

    • 从 Frank 的最后评论来看,这可能不是他想要的。
    猜你喜欢
    • 2012-11-18
    • 1970-01-01
    • 1970-01-01
    • 2011-03-30
    • 1970-01-01
    • 1970-01-01
    • 2014-08-10
    • 2022-11-21
    • 2014-07-10
    相关资源
    最近更新 更多