windows Java中的跨进程同步
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/5297813/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Cross process synchronization in Java
提问by Saar
How can I synchornize two Java processes running on Windows ?
如何同步运行在 Windows 上的两个 Java 进程?
I am looking for something like the Win32 Named Mutex object which allows two processes to use the same locking object.
我正在寻找类似 Win32 Named Mutex 对象的东西,它允许两个进程使用相同的锁定对象。
Thanks
谢谢
采纳答案by bezmax
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:
在 Java 中不可能做你想做的事情。不同的 Java 应用程序将使用不同的 JVM,将它们自己完全分离到不同的“黑盒”中。但是,您有两个选择:
- 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.
- 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".
- 使用套接字(或通道)。基本上,一个应用程序将打开侦听套接字并开始等待,直到它收到一些信号。另一个应用程序将连接到那里,并在完成某事后发送信号。我想说这是在 99.9% 的应用程序中使用的首选方式。
- 您可以从 Java 调用 winapi。我不记得具体细节,但如果你用谷歌搜索“java winapi”,你可以找到大量的例子。
回答by Java42
Java cross process lock:
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();
}
});
}
回答by Ilya Gazman
I simplified Java42answer
我简化了Java42答案
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.
successLockRunnable 中的代码将使用此实现锁定同一台机器上的任何其他进程。
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();
}
}
}
}
回答by vickirk
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.
不确定您要做什么,我可能会通过 JMX 公开某些内容并让单独的进程设置一个状态标志,然后以编程方式将您的线程从等待状态中恢复过来。您当然可以使用套接字/RMI 代替 JMX。
回答by philwb
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.
我认为 java 平台中没有用于此的本机方法。但是,根据您尝试完成的同步,有多种方法可以获得相同类型的效果。除了让进程通过网络连接(直接套接字、带选举的多播等)进行通信或丢弃到特定于平台的调用之外,您还可以探索获取共享文件的文件锁(请参阅 activemq 被动备用以共享文件系统为例)或使用具有选择更新或表行的乐观更新之类的数据库。
回答by andriy
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.
使用套接字进行跨进程同步是常见的做法。不仅适用于 java 应用程序,因为在大多数 *nix 环境中,我们没有像在 Windows 中那样的系统范围的互斥锁。
回答by Benjamin Sonday
We use these kinds of statements to make sure only one process can do a block of code keyed by "myLockKey":
我们使用这些类型的语句来确保只有一个进程可以执行由“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);
}
}
}