Запретить использование многопоточного контекста без использования потоков

Есть ли способ вызвать исключение, когда пользователь пытается использовать не поточнобезопасный метод класса в многопоточном контексте? Я предполагаю, что проблема в основном состоит в том, чтобы обнаружить, что несколько потоков пытаются использовать метод. Или есть ключевое слово /тег not_synchronous, которое я мог бы использовать в объявлении функции?

7 голосов | спросил Frank 31 J000000Tuesday12 2012, 20:05:38

4 ответа


0

Нет простого способа сделать это, нет. Если вы обнаружите, что метод используется несколькими потоками, скорее всего, вам придется использовать потоковые коллекции и тому подобное. Если вы делаете все это, то вам, возможно, придется сделать сам метод поточно-ориентированным.

ответил Gray 31 J000000Tuesday12 2012, 20:07:52
0

Вы можете проверить, используется ли метод уже перед тем, как разрешить потоку его запускать, но это не сильно отличается от использования блокировки (примечание: мой пример не реентерабелен):

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);
}
ответил assylias 31 J000000Tuesday12 2012, 20:18:36
0

Более подробно об ответе Грея: предположим, что вы хотели это сделать (определите, когда метод используется несколькими потоками). Наивная (и неправильная) реализация этого может выглядеть так:

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 31 J000000Tuesday12 2012, 20:22:00
0

На самом деле, если ваша цель - определить, что «несколько потоков пытаются использовать этот метод», и вы не ограничиваете это «несколькими методами ... одновременно», - тогда (простите) код Алекса можно адаптировать красиво:

  1. Измените methodBeingUsed на threadOwningMethod и установите его в поток вместо true.

  2. Вам не нужно очищать его в конце - сохраните эти шаги блокировки /разблокировки. Как только он принадлежит, он принадлежит (капиталистическая свинья !!).

  3. threadOwningMethod можно предварительно проверить, соответствует ли он текущему потоку (A-OK) или нет ( выбросить исключение) без необходимости брать на себя блокировку. Если он не установлен (ноль), вы получаете одноразовый удар: check /lock /check & set /unlock; это безопасно, потому что threadOwningMethod помечен как изменчивый.

ответил Richard Sitze 31 J000000Tuesday12 2012, 20:37:27

Похожие вопросы

Популярные теги

security × 330linux × 316macos × 2827 × 268performance × 244command-line × 241sql-server × 235joomla-3.x × 222java × 189c++ × 186windows × 180cisco × 168bash × 158c# × 142gmail × 139arduino-uno × 139javascript × 134ssh × 133seo × 132mysql × 132