Java中的跨进程同步

发布于 2024-10-22 12:58:56 字数 96 浏览 1 评论 0原文

如何同步 Windows 上运行的两个 Java 进程?

我正在寻找类似 Win32 命名互斥对象的东西,它允许两个进程使用相同的锁定对象。

谢谢

How can I synchornize two Java processes running on Windows ?

I am looking for something like the Win32 Named Mutex object which allows two processes to use the same locking object.

Thanks

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

不羁少年 2024-10-29 12:58:56

Java跨进程锁:

// Tester
try {
    if (crossProcessLockAcquire(SomeClassInYourApp.class, 3000)) {
       // Success - This process now has the lock. (Don't keep it too long.)
    }
    else {
       // Fail (Timeout) - Another process still had the lock after 3 seconds.
    }
} finally {
    crossProcessLockRelease(); // try/finally is very important.
}

// Acquire - Returns success ( true/false )
private static boolean crossProcessLockAcquire(final Class<?> c, final long waitMS) {
    if (fileLock == null && c != null && waitMS > 0) {
        try {
            long dropDeadTime = System.currentTimeMillis() + waitMS;
            File file = new File(lockTempDir, c.getName() + ".lock");
            RandomAccessFile randomAccessFile = new RandomAccessFile(file, "rw");
            FileChannel fileChannel = randomAccessFile.getChannel();
            while (System.currentTimeMillis() < dropDeadTime) {
                fileLock = fileChannel.tryLock();
                if (fileLock != null) {
                    break;
                }
                Thread.sleep(250); // 4 attempts/sec
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    return fileLock == null ? false : true;
}

// Release
private static void crossProcessLockRelease() {
    if (fileLock != null) {
        try {
            fileLock.release();
            fileLock = null;
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

// Some class vars and a failsafe lock release.
private static File lockTempDir = new File(System.getProperty("java.io.tmpdir") + File.separator + "locks");
private static FileLock fileLock = null;
static {
    Runtime.getRuntime().addShutdownHook(new Thread() {
        public void run(){
            crossProcessLockRelease();
        }
    });
}    

Java cross process lock:

// Tester
try {
    if (crossProcessLockAcquire(SomeClassInYourApp.class, 3000)) {
       // Success - This process now has the lock. (Don't keep it too long.)
    }
    else {
       // Fail (Timeout) - Another process still had the lock after 3 seconds.
    }
} finally {
    crossProcessLockRelease(); // try/finally is very important.
}

// Acquire - Returns success ( true/false )
private static boolean crossProcessLockAcquire(final Class<?> c, final long waitMS) {
    if (fileLock == null && c != null && waitMS > 0) {
        try {
            long dropDeadTime = System.currentTimeMillis() + waitMS;
            File file = new File(lockTempDir, c.getName() + ".lock");
            RandomAccessFile randomAccessFile = new RandomAccessFile(file, "rw");
            FileChannel fileChannel = randomAccessFile.getChannel();
            while (System.currentTimeMillis() < dropDeadTime) {
                fileLock = fileChannel.tryLock();
                if (fileLock != null) {
                    break;
                }
                Thread.sleep(250); // 4 attempts/sec
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    return fileLock == null ? false : true;
}

// Release
private static void crossProcessLockRelease() {
    if (fileLock != null) {
        try {
            fileLock.release();
            fileLock = null;
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

// Some class vars and a failsafe lock release.
private static File lockTempDir = new File(System.getProperty("java.io.tmpdir") + File.separator + "locks");
private static FileLock fileLock = null;
static {
    Runtime.getRuntime().addShutdownHook(new Thread() {
        public void run(){
            crossProcessLockRelease();
        }
    });
}    
丶情人眼里出诗心の 2024-10-29 12:58:56

我简化了 Java42 答案

用法

ProcessLock lock = new ProcessLock("lockKey");
lock.run(successLockRunnable, timeOutLockRunnable);

successLockRunnable 中的代码将使用以下命令锁定同一台计算机上的任何其他进程这个实施。

来源

/**
 * Created by Ilya Gazman on 13/06/2016.
 * Based on https://stackoverflow.com/a/9577667/1129332
 */
public class ProcessLock {
    // Some class vars and a fail safe lock release.
    private File lockTempDir = new File(System.getProperty("java.io.tmpdir") + File.separator + "locks");
    private FileLock fileLock = null;
    private String key;

    public ProcessLock() {
        this("lock");
    }

    public ProcessLock(String key) {
        this.key = key;
        Runtime.getRuntime().addShutdownHook(new Thread() {
            public void run() {
                crossProcessLockRelease();
            }
        });
    }

    public void run(Runnable successCallback) {
        run(successCallback, null);
    }

    public void run(Runnable successCallback, Runnable timeOutCallback) {
        try {
            if (crossProcessLockAcquire(3000)) {
                successCallback.run();
            } else if (timeOutCallback != null) {
                timeOutCallback.run();
            }
        } finally {
            crossProcessLockRelease(); // try/finally is very important.
        }
    }

    // Acquire - Returns success ( true/false )
    private boolean crossProcessLockAcquire(final long waitMS) {
        if (fileLock == null && waitMS > 0) {
            try {
                long dropDeadTime = System.currentTimeMillis() + waitMS;
                File file = new File(lockTempDir, "_" + key + ".lock");
                RandomAccessFile randomAccessFile = new RandomAccessFile(file, "rw");
                FileChannel fileChannel = randomAccessFile.getChannel();
                while (System.currentTimeMillis() < dropDeadTime) {
                    fileLock = fileChannel.tryLock();
                    if (fileLock != null) {
                        break;
                    }
                    Thread.sleep(250); // 4 attempts/sec
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return fileLock != null;
    }

    // Release
    private void crossProcessLockRelease() {
        if (fileLock != null) {
            try {
                fileLock.release();
                fileLock = null;
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

I simplified Java42 answer

Usage

ProcessLock lock = new ProcessLock("lockKey");
lock.run(successLockRunnable, timeOutLockRunnable);

The code in successLockRunnable will lock any other process on the same machine using this implementation.

Source

/**
 * Created by Ilya Gazman on 13/06/2016.
 * Based on https://stackoverflow.com/a/9577667/1129332
 */
public class ProcessLock {
    // Some class vars and a fail safe lock release.
    private File lockTempDir = new File(System.getProperty("java.io.tmpdir") + File.separator + "locks");
    private FileLock fileLock = null;
    private String key;

    public ProcessLock() {
        this("lock");
    }

    public ProcessLock(String key) {
        this.key = key;
        Runtime.getRuntime().addShutdownHook(new Thread() {
            public void run() {
                crossProcessLockRelease();
            }
        });
    }

    public void run(Runnable successCallback) {
        run(successCallback, null);
    }

    public void run(Runnable successCallback, Runnable timeOutCallback) {
        try {
            if (crossProcessLockAcquire(3000)) {
                successCallback.run();
            } else if (timeOutCallback != null) {
                timeOutCallback.run();
            }
        } finally {
            crossProcessLockRelease(); // try/finally is very important.
        }
    }

    // Acquire - Returns success ( true/false )
    private boolean crossProcessLockAcquire(final long waitMS) {
        if (fileLock == null && waitMS > 0) {
            try {
                long dropDeadTime = System.currentTimeMillis() + waitMS;
                File file = new File(lockTempDir, "_" + key + ".lock");
                RandomAccessFile randomAccessFile = new RandomAccessFile(file, "rw");
                FileChannel fileChannel = randomAccessFile.getChannel();
                while (System.currentTimeMillis() < dropDeadTime) {
                    fileLock = fileChannel.tryLock();
                    if (fileLock != null) {
                        break;
                    }
                    Thread.sleep(250); // 4 attempts/sec
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return fileLock != null;
    }

    // Release
    private void crossProcessLockRelease() {
        if (fileLock != null) {
            try {
                fileLock.release();
                fileLock = null;
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}
臻嫒无言 2024-10-29 12:58:56

在 Java 中不可能做你想做的事情。不同的 Java 应用程序将使用不同的 JVM,将自己完全分成不同的“黑匣子”。但是,您有 2 个选择:

  1. 使用套接字(或通道)。基本上,一个应用程序将打开侦听套接字并开始等待,直到收到一些信号。另一个应用程序将连接到那里,并在完成某些操作后发送信号。我想说这是 99.9% 的应用程序中使用的首选方式。
  2. 您可以从 Java 调用 winapi。我不记得具体细节,但如果你用谷歌搜索“java winapi”,你可以找到大量的例子。

It is not possible to do something like you want in Java. Different Java applications will use different JVM's fully separating themselves into different 'blackbox'es. However, you have 2 options:

  1. Use sockets (or channels). Basically one application will open the listening socket and start waiting until it receives some signal. The other application will connect there, and send signals when it had completed something. I'd say this is a preferred way used in 99.9% of applications.
  2. You can call winapi from Java. I do not remember the specifics, but you can find a plethora of example if you google "java winapi".
最冷一天 2024-10-29 12:58:56

我们使用这些类型的语句来确保只有一个进程可以执行由“myLockKey”键入的代码块:

new LocalFileLock("myLockKey").doWithLock(() -> {
  doSomething();
  return null; // must return something
});    

在这里,我们使用此类:

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

import com.headlandstech.utils.FileUtils;
import com.headlandstech.utils.Log;

public class LocalFileLock {

  private final File lockFile;

  public LocalFileLock(String name) {
    this.lockFile = new File(FileUtils.TEMP_DIR, name + ".lock");
    if (!lockFile.isFile()) {
      FileUtils.writeStringToFile("", lockFile);
    }
  }

  public <T> T doWithLock(Supplier<T> f) {
    Log.log.info("Waiting on lock " + lockFile);
    try (FileChannel channel = new RandomAccessFile(lockFile, "rw").getChannel()) {
      final FileLock fileLock = channel.lock();
      Log.log.info("Lock " + lockFile + " obtained");
      T result = f.get();
      fileLock.release();
      Log.log.info("Lock " + lockFile + " released");
      return result;
    } catch (IOException e) {
      throw new RuntimeException(e);
    }
  }

}

We use these kinds of statements to make sure only one process can do a block of code keyed by "myLockKey":

new LocalFileLock("myLockKey").doWithLock(() -> {
  doSomething();
  return null; // must return something
});    

Here, we make use of this class:

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

import com.headlandstech.utils.FileUtils;
import com.headlandstech.utils.Log;

public class LocalFileLock {

  private final File lockFile;

  public LocalFileLock(String name) {
    this.lockFile = new File(FileUtils.TEMP_DIR, name + ".lock");
    if (!lockFile.isFile()) {
      FileUtils.writeStringToFile("", lockFile);
    }
  }

  public <T> T doWithLock(Supplier<T> f) {
    Log.log.info("Waiting on lock " + lockFile);
    try (FileChannel channel = new RandomAccessFile(lockFile, "rw").getChannel()) {
      final FileLock fileLock = channel.lock();
      Log.log.info("Lock " + lockFile + " obtained");
      T result = f.get();
      fileLock.release();
      Log.log.info("Lock " + lockFile + " released");
      return result;
    } catch (IOException e) {
      throw new RuntimeException(e);
    }
  }

}
思念满溢 2024-10-29 12:58:56

我认为 java 平台中没有为此提供的本机方法。但是,有多种方法可以获得相同类型的效果,具体取决于您想要完成的同步。除了让进程通过网络连接(直接套接字、带有选举的多播等)进行通信或放弃平台特定的调用之外,您还可以探索获取共享文件的文件锁(请参阅 activemq 被动备用)例如,共享文件系统)或使用数据库以及诸如选择更新或表行的乐观更新之类的东西。

I don't think there are native methods in the java platform for this. However, there are several ways to go about obtaining the same type of effect depending on what synchronization you are trying to accomplish. In addition to having the processes communicate over network connections (direct sockets, multicast with an election, etc.) or dropping to platform specific calls, you can also explore obtaining a file lock to a shared file (see activemq passive stand-by with a shared file system for an example) or using a database either with something like a select for update or an optimistic update of a table row.

短暂陪伴 2024-10-29 12:58:56

不确定您要做什么,我可能会通过 JMX 公开某些内容并让单独的进程设置一个状态标志,然后以编程方式将您的线程从等待状态恢复。当然,您可以使用套接字/RMI 来代替 JMX。

Not sure what you are trying to do, I'd possibly do this by exposing something via JMX and having the separate processes set a status flag which then programmatically revives your thread from a wait state. Instead of JMX you could of course use a socket/RMI.

陌上青苔 2024-10-29 12:58:56

使用套接字进行跨进程同步是常见的做法。不仅适用于 java 应用程序,因为在大多数 *nix 环境中,我们没有像 Windows 中那样的系统范围互斥锁。

using sockets for cross processes synchronizations is common practice . not only for java applications because in most *nix environments we have not system-wide mutexes as we have in Windows.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文