4

インスタンスを 1 つだけ実行する Java でアプリケーションを作成していました。この目的のために、ファイルを作成し、アプリケーションの実行中にロックを取得しました。

Windows では動作するが、Linux では失敗する次のコードがあります。ロックを解除せずにロックを取得すると、別のロックを取得できます。

import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.channels.FileChannel;
import java.nio.channels.FileLock;

public class MyApp {

private static File f;
private static FileChannel channel;
private static FileLock lock;

public static void main(String[] args) {
    try {
        f = new File("RingOnRequest.lock");
        // Check if the lock exist
        if (f.exists()) {
            // if exist try to delete it
            f.delete();
        }
        // Try to get the lock
        channel = new RandomAccessFile(f, "rw").getChannel();
        lock = channel.tryLock();
        if(lock == null)
        {
            // File is lock by other application
            channel.close();
            throw new RuntimeException("Only 1 instance of MyApp can run.");
        }
        // Add shutdown hook to release lock when application shutdown
        ShutdownHook shutdownHook = new ShutdownHook();
        Runtime.getRuntime().addShutdownHook(shutdownHook);

        //Your application tasks here..
        System.out.println("Running");
        try {
            Thread.sleep(10000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

    }
    catch(IOException e)
    {
        throw new RuntimeException("Could not start process.", e);
    }

}

public static void unlockFile() {
    // release and delete file lock
    try {
        if(lock != null) {
            lock.release();
            channel.close();
            f.delete();
        }
    } catch(IOException e) {
        e.printStackTrace();
    }
}

static class ShutdownHook extends Thread {

    public void run() {
        unlockFile();
    }
}

}
4

6 に答える 6

5

実行するたびにロックファイルを削除するため、1つのプロセスのみがロックを設定できます。

を使用する場合FileLock、これは純粋に助言です。ファイルのロックを取得しても、何もできなくなることはありません。別のプロセスがロックを取得した場合でも、ファイルの読み取り、書き込み、削除はすべて可能です。特定のプラットフォームでは、ロックがこれ以上のことを行う場合がありますが、この動作は指定されておらず、クラスのドキュメントで保証されている以上のものに依存することは失敗の秘訣です。

「アドバイザリロック」は、わざわざそれを探す他のプロセスに見えるシグナルにすぎません。それ以上に依存している場合、他のプラットフォームで実行するとプログラムが壊れます。

とにかくロックファイルを削除するのはなぜですか?ロックファイルは、システム上のすべてのプロセスに表示されるブールフラグのようなものです。そのように使用するようにプロトコルを設計すると、信頼性の高いクロスプラットフォームのロックメカニズムが得られます。

于 2012-06-26T17:46:56.300 に答える
2

PID をファイルに保存して、ファイルをロックする代わりに、その ID を持つプロセスがあるかどうかを確認してください。存在し、それがアプリケーションのインスタンスである場合、既に実行されていることがわかります。

実行中のインスタンスと通信するためにソケットを使用できるため、ソケットも良い考えです。

編集:

また、FileLock の javadocから:

ロックによって別のプログラムがロックされた領域のコンテンツにアクセスするのを実際に防止するかどうかは、システムに依存するため未指定です。

于 2012-06-26T06:51:21.707 に答える
1

を使用しmkdirます。UNIX システムでは、これは不可分な操作です。新しいディレクトリが正常に作成された場合は成功し、それ以外の場合は失敗します。

例:

File lockFile = new File("/path/to/lockdir");
boolean hasLock = lockFile.mkdir();
if (!hasLock) {
  throw new IOException("could not get lock");
}
// do stuff
lockFile.delete();
于 2015-08-14T10:26:54.343 に答える
0

最近、同じ種類の問題が発生しましたが、私の場合は利点がありました。アプリケーションは、タイムアウト後にのみディレクトリをポーリングしました。私のアプリケーションはディレクトリをすぐにポーリングしなかったため、init メソッド内に独自の PID を使用してロック ファイルを作成する特別なクラスを作成しました。その後、ディレクトリを操作する前に呼び出す必要がownedLock()あります。true が返された場合は作業でき、それ以外の場合は終了します。 (コードは Kotlin ですが、主なアイデアは理解できます):

import java.io.File
import java.lang.management.ManagementFactory
class DirectoryLocker(private val directory: String, private val lockName: String) {
   private val lockFile by lazy { File("$directory/$lockName.lock") }

   // Will try to acquire lock to directory, whoever last writes its pid to file owns the directory
   fun acquireLock() = with(lockFile) {
      createNewFile()
      writeText(currentPID())
   }

   fun ownedLock(): Boolean = lockFilePid() == currentPID()

   fun releaseOwnedLock() {
      if(lockFilePid() == currentPID()) lockFile.delete()
   }

   private fun currentPID(): String {
      val processName = ManagementFactory.getRuntimeMXBean().name
      return processName.split("@".toRegex()).first()
   }

   private fun lockFilePid(): String? {
      return if(lockFile.exists()) lockFile.readLines().first() else null
   }
}
于 2017-12-08T14:09:44.010 に答える
0

私はあなたと同じサンプルを使用しましたが、Mac OS X でも同じ問題が発生しました。POSIX システムでは、ファイル ロックはファイルの削除を妨げないようです。ロックを解除するまで、アプリはそのファイルへの何らかのハンドルを保持します。そのため、名前 (またはファイル内) に PID を含むロック ファイルを使用することを検討してください。

于 2012-06-26T07:19:05.330 に答える