All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.github.hcoona.utils.NamedMutexFileLockImpl Maven / Gradle / Ivy

Go to download

Cross platform named mutex which provide a system-wide mutex synchronization primitive

The newest version!
package io.github.hcoona.utils;

import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Preconditions;

import java.io.IOException;
import java.nio.channels.FileChannel;
import java.nio.channels.FileLock;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.util.concurrent.Callable;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.concurrent.locks.ReentrantLock;

/**
 * Please use {@link io.github.hcoona.concurrent.NamedMutexFileLockImpl} instead.
 */
@Deprecated
public class NamedMutexFileLockImpl extends NamedMutex {
  private static final ConcurrentHashMap INTERNAL_LOCK_CACHE =
      new ConcurrentHashMap<>();

  private final FileChannel lockFileChannel;
  private final ScheduledExecutorService executor;
  private FileLock lock;
  private final ReentrantLock internalLock;
  private boolean disposed = false;

  @VisibleForTesting
  NamedMutexFileLockImpl(String name) throws IOException {
    this(false, name);
  }

  @VisibleForTesting
  NamedMutexFileLockImpl(boolean initiallyOwned, String name) throws IOException {
    final Path lockFilePath = Paths.get(System.getProperty("java.io.tmpdir"), name + ".lock");

    this.executor = Executors.newSingleThreadScheduledExecutor();

    if (!INTERNAL_LOCK_CACHE.containsKey(name)) {
      INTERNAL_LOCK_CACHE.putIfAbsent(name, new ReentrantLock());
    }
    this.internalLock = INTERNAL_LOCK_CACHE.get(name);

    this.lockFileChannel = FileChannel.open(lockFilePath,
        StandardOpenOption.CREATE,
        StandardOpenOption.READ,
        StandardOpenOption.WRITE);
    if (internalLock.tryLock()) {
      try {
        this.lock = lockFileChannel.tryLock();
      } finally {
        if (lock == null || !lock.isValid()) {
          internalLock.unlock();
        }
      }
    }
  }

  @Override
  public boolean waitOne() throws Exception {
    Preconditions.checkState(!disposed);

    internalLock.lockInterruptibly();
    try {
      if (lock == null) {
        lock = lockFileChannel.lock();
      } else if (!lock.isValid()) {
        lock = lockFileChannel.lock();
      } else {
        internalLock.unlock();
      }

      return true;
    } finally {
      if (lock == null || !lock.isValid()) {
        internalLock.unlock();
      }
    }
  }

  @Override
  public boolean waitOne(long interval, TimeUnit intervalTimeUnit) throws Exception {
    Preconditions.checkState(!disposed);
    Preconditions.checkArgument(interval >= -1);

    if (internalLock.tryLock(interval, intervalTimeUnit)) {
      try {
        if (lock != null && lock.isValid()) {
          internalLock.unlock();
          return true;
        } else {
          ScheduledFuture lockFuture = executor.schedule(
              (Callable) lockFileChannel::lock,
              interval, intervalTimeUnit);

          try {
            lock = lockFuture.get(interval, intervalTimeUnit);
            return lock.isValid();
          } catch (TimeoutException ignored) {
            lockFuture.cancel(true);
            return false;
          }
        }
      } finally {
        if (lock == null || !lock.isValid()) {
          internalLock.unlock();
        }
      }
    } else {
      return false;
    }
  }

  @Override
  public void release() throws Exception {
    Preconditions.checkState(!disposed);

    if (internalLock.tryLock()) {
      try {
        if (lock != null && lock.isValid()) {
          lock.release();
          internalLock.unlock();
        }
      } finally {
        internalLock.unlock();
      }
    }
  }

  @Override
  public void close() throws Exception {
    if (!disposed) {
      release();
      lockFileChannel.close();
      disposed = true;
    }
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy