Comment puis-je synchroniser deux processus Java en cours d'exécution sur Windows? p>
Je cherche quelque chose comme l'objet Win32 nommé Mutex qui permet à deux processus d'utiliser le même objet de verrouillage. P>
merci p>
7 Réponses :
Il n'est pas possible de faire quelque chose comme vous le souhaitez en Java. Différentes applications Java utiliseront différents JVM se séparant complètement en différents 'Blackbox'es. Cependant, vous avez 2 options: p>
Le fait que cela puisse être deux JVM différents le rend intéressant. Merci!
Vous ne savez pas ce que vous essayez de faire, je le ferais éventuellement en exposant quelque chose via JMX et que les processus distincts définissent un indicateur d'état qui reviennent de manière programmable votre thread d'un état d'attente. Au lieu de JMX, vous pouvez bien sûr utiliser une prise / RMI. P>
Je ne pense pas qu'il existe des méthodes natales dans la plate-forme Java pour cela. Cependant, il existe plusieurs façons d'obtenir le même type d'effet en fonction de la synchronisation que vous essayez d'accomplir. En plus de la communication des processus communiquant sur des connexions réseau (prises directes, multidiffusion avec une élection, etc.) ou de laisser tomber les appels spécifiques à la plate-forme, vous pouvez également explorer l'obtention d'un verrouillage de fichier à un fichier partagé (voir Activemq Passif Stand-By avec un Système de fichiers partagé pour un exemple) ou en utilisant une base de données soit avec quelque chose comme une sélection de mise à jour ou une mise à jour optimiste d'une ligne de table. P>
Utiliser les sockets pour les processus de processus croisés est une pratique courante. Non seulement pour les applications Java, car dans la plupart des environnements * Nix, nous n'avons pas de mutiles à l'échelle du système que nous avons sous Windows. p>
Verrouillage croisé 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();
}
});
}
J'ai simplifié java42 strong> réponse
Le code dans la successlockRunnable verrouille tout autre processus sur la même machine à l'aide de cette implémentation. P>
/**
* 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();
}
}
}
}
Nous utilisons ce type d'instructions pour vous assurer qu'un seul processus peut faire un bloc de code clé par "myLOOsKey": ici, nous utilisons cette classe: P > 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);
}
}
}
Je ne suis pas sûr que les processus de synchronisation soient une bonne idée. Vous pouvez expliquer pourquoi vous avez besoin de cela? Je ne peux pas penser à une seule utilisation de cette synchronisation.
Si vous avez plusieurs tâches nécessaires pour partager des données / serrures, ils doivent être dans le même JVM. Il y a beaucoup moins de raison pour rompre un processus unique en plusieurs processus en Java par rapport à C / C ++.
Par exemple, si j'ai besoin de calculs nécessitant plus de 1,6 Go, je aurais besoin de plusieurs processus (sur une machine 32 bits).
Oui, mais si vous démarrez même 2 processus w / 1.6 Go, vous êtes déjà hors de l'espace adressé Windows. Même si vous démarrez un processus avec une grande mémoire, il serait peu probable qu'il soit peu susceptible de commencer une autre. Outre les sockets (ou éventuellement des fichiers), vous êtes pratiquement des options.