Асинхронная (неблокирующая) версия synchronized () {} - PullRequest
0 голосов
/ 07 февраля 2019

Есть ли хороший способ реализовать асинхронную версию синхронизированного ключевого слова?Очевидно, что ключевое слово synchronized () часто блокирует текущий поток.Например:

  public static boolean getLockSync(Runnable r) {

    if (isLocked) {
      r.run();
      return true;
    }

    synchronized (My.lock) { // this is blocking, could block for more than 1-2 ms
      isLocked = true;
      r.run();
      isLocked = false;
      return false;
    }

  }

Я могу вернуть логическое значение из этого блока - это синхронно.Есть ли способ сделать это асинхронно?

Как-то так:

  public static void getLockAsync(Runnable r) {

    if (isLocked) {
      CompletableFuture.runAsync(r);
      return;
    }

    Object.onLockAcquisition(My.lock, () -> { // this is non-blocking
           isLocked = true;
           r.run();
           isLocked = false;
           Object.releaseLock(My.lock);
     });

  }

Я создал метод Object.onLockAcquisition, но искал что-то подобное.

Ответы [ 3 ]

0 голосов
/ 07 февраля 2019

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

  • альтернативы с двойной блокировкой (с использованием volatile + monitor и двойной проверкой volatile, один раз передблокировка, один раз после блокировки)
  • используйте AtomicXXX, и там сравнивайте AndSet / compareAndExchange и т.д .. методы
  • используйте java.util.concurrent.locks
  • используйте однопоточный исполнитель длявыполнить критическую секцию
  • использовать очередь
0 голосов
/ 09 февраля 2019

Правильным решением с точки зрения Vert.x будет использование SharedData.getLock()
Причина этого заключается в том, что асинхронность является частью определенной библиотеки, а не платформы JVM.

Если только Vert.x работает в кластерном режиме, возвращается к локальной блокировке:

public void getLockWithTimeout(String name, long timeout, Handler<AsyncResult<Lock>> resultHandler) {
    ...
    if (clusterManager == null) {
      getLocalLock(name, timeout, resultHandler);
    } else {
      ...
    }
  }

getLock использует LocalAsyncLocal под:

localAsyncLocks.acquire(vertx.getOrCreateContext(), name, timeout, resultHandler);

acquire() использует ConcurrentHashMap.compute подкапот: https://github.com/eclipse-vertx/vert.x/blob/master/src/main/java/io/vertx/core/shareddata/impl/LocalAsyncLocks.java#L91

Так что, если вы действительно хотите иметь собственную реализацию, вы можете черпать вдохновение из приведенного выше кода.

0 голосов
/ 07 февраля 2019

Одним из решений в Vertx является асинхронная блокировка вызовов инструментария:

https://vertx.io/docs/vertx-core/java/#_asynchronous_locks

, которая выглядит следующим образом:

sd.getLock("mylock", res -> {
   Lock lock = res.result();
   vertx.setTimer(5000, tid -> lock.release());
});

однако это не действительно решение, которое я ищу, поскольку это сетевая блокировка, что означает, что она довольно медленная по сравнению с обычной блокировкой в ​​памяти.Мне нужно только создать блокировку в одном потоке, а не между потоками или процессами.

...