Java中的跨进程同步

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

我正在寻找像Win32命名互斥对象,它允许两个进程使用相同的locking对象。

谢谢

在Java中不可能做到像你想要的那样。 不同的Java应用程序将使用不同的JVM将自己完全分离到不同的“黑盒子”中。 但是,您有2个选项:

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

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(); } }); } 

我简化了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(); } } } } 

不知道你在做什么,我可能会通过JMX暴露一些东西来做到这一点,让单独的进程设置一个状态标志,然后以编程方式从等待状态恢复线程。 而不是JMX,你当然可以使用套接字/ RMI。

我不认为这是在Java平台的本地方法。 但是,根据您尝试完成的同步,有几种方法可以获得相同类型的效果。 除了通过网络连接进行通信(直接套接字,带选举的多播等)或下降到特定于平台的调用之外,还可以探索获取对共享文件的文件锁定(请参阅activemq被动备用共享文件系统的例子),或者使用一个数据库,或者像一个选择更新或乐观更新表行。

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

我们使用这些类型的语句来确保只有一个进程可以执行由“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); } } }