Question

Parfois, de nombreuses applications telles que msn, le lecteur multimédia Windows, etc., sont des applications à instance unique (lorsque l'utilisateur s'exécute lorsque l'application est en cours d'exécution, une nouvelle instance d'application ne sera pas créée).

En C #, j'utilise la classe Mutex pour cela, mais je ne sais pas comment faire cela en Java.

Était-ce utile?

La solution

Si je crois ceci, cet article , par:

  

ayant la première instance tente d’ouvrir un socket d’écoute sur l’interface localhost. S'il est capable d'ouvrir le socket, on suppose qu'il s'agit de la première instance de l'application à être lancée. Dans le cas contraire, l'hypothèse est qu'une instance de cette application est déjà en cours d'exécution. La nouvelle instance doit notifier à l'instance existante qu'un lancement a été tenté, puis quitter. L’instance existante prend le relais après la réception de la notification et déclenche un événement pour le programme d’écoute qui gère l’action.

Remarque: Ahe mentionne dans le commentaire qu'il est possible d'utiliser InetAddress.getLocalHost () . délicat:

  
      
  • il ne fonctionne pas comme prévu dans l'environnement DHCP, car l'adresse renvoyée dépend du type d'accès de l'ordinateur au réseau.
      La solution consistait à ouvrir une connexion avec InetAddress.getByAddress (nouvel octet [] {127, 0, 0, 1}) ;
      Probablement lié au bug 4435662 .
  •   
  • J'ai également trouvé un bug 4665037 qui indique que les résultats attendus sont les suivants: getLocalHost : renvoie l'adresse IP de la machine, par opposition aux résultats réels: renvoie 127.0.0.1 .
  

il est surprenant que getLocalHost renvoie 127.0.0.1 sous Linux mais pas sous Windows.

Ou vous pouvez utiliser ManagementFactory . Comme expliqué ici :

  

La méthode getMonitoredVMs (int processPid) reçoit en paramètre le PID de l'application actuelle et récupère le nom de l'application appelée à partir de la ligne de commande. Par exemple, l'application a été démarrée à partir de c: \ java \ app \ test.jar , la variable de valeur est " c: \\ java \\ app \\ test.jar ". De cette façon, nous attraperons simplement le nom de l'application sur la ligne 17 du code ci-dessous.
  Ensuite, nous recherchons un autre processus portant le même nom sur JVM. Si nous le trouvons et si le PID de l’application est différent, cela signifie que c’est la deuxième instance de l’application.

JNLP propose également un SingleInstanceListener

Autres conseils

J'utilise la méthode suivante dans la méthode principale. C’est la méthode la plus simple, la plus robuste et la moins intrusive que j’ai vue; j’ai donc pensé que je la partagerais.

private static boolean lockInstance(final String lockFile) {
    try {
        final File file = new File(lockFile);
        final RandomAccessFile randomAccessFile = new RandomAccessFile(file, "rw");
        final FileLock fileLock = randomAccessFile.getChannel().tryLock();
        if (fileLock != null) {
            Runtime.getRuntime().addShutdownHook(new Thread() {
                public void run() {
                    try {
                        fileLock.release();
                        randomAccessFile.close();
                        file.delete();
                    } catch (Exception e) {
                        log.error("Unable to remove lock file: " + lockFile, e);
                    }
                }
            });
            return true;
        }
    } catch (Exception e) {
        log.error("Unable to create and/or lock file: " + lockFile, e);
    }
    return false;
}

Si l'application. a une interface graphique, lancez-le avec JWS et utilisez SingleInstanceService . Voir la démonstration. de SingleInstanceService pour un exemple de code.

Oui, c’est une réponse vraiment décente pour l’application à une seule instance eclipse RCP eclipse ci-dessous est mon code

dans application.java

if(!isFileshipAlreadyRunning()){
        MessageDialog.openError(display.getActiveShell(), "Fileship already running", "Another instance of this application is already running.  Exiting.");
        return IApplication.EXIT_OK;
    } 


private static boolean isFileshipAlreadyRunning() {
    // socket concept is shown at http://www.rbgrn.net/content/43-java-single-application-instance
    // but this one is really great
    try {
        final File file = new File("FileshipReserved.txt");
        final RandomAccessFile randomAccessFile = new RandomAccessFile(file, "rw");
        final FileLock fileLock = randomAccessFile.getChannel().tryLock();
        if (fileLock != null) {
            Runtime.getRuntime().addShutdownHook(new Thread() {
                public void run() {
                    try {
                        fileLock.release();
                        randomAccessFile.close();
                        file.delete();
                    } catch (Exception e) {
                        //log.error("Unable to remove lock file: " + lockFile, e);
                    }
                }
            });
            return true;
        }
    } catch (Exception e) {
       // log.error("Unable to create and/or lock file: " + lockFile, e);
    }
    return false;
}

Pour ce faire, nous utilisons le verrouillage de fichier (un verrou exclusif sur un fichier magique se trouvant dans le répertoire de données de l'application de l'utilisateur), mais nous souhaitons principalement empêcher l'exécution de plusieurs instances.

Si vous essayez de faire passer la deuxième instance d'arguments de ligne de commande, etc. à la première instance, l'utilisation d'une connexion socket sur localhost fera d'une pierre deux coups. Algorithme général:

  • Au lancement, essayez d'ouvrir le programme d'écoute sur le port XXXX sur localhost
  • si échec, ouvrez un écrivain sur ce port sur localhost et envoyez les arguments de ligne de commande, puis arrêtez
  • sinon, écoutez sur le port XXXXX sur localhost. Lorsque vous recevez des arguments en ligne de commande, traitez-les comme si l'application avait été lancée avec cette ligne de commande.

J'ai trouvé une solution, une explication un peu caricaturale, mais fonctionne toujours dans la plupart des cas. Il utilise l’ancien vieux fichier de verrouillage pour créer des éléments, mais dans une vue très différente:

http://javalandscape.blogspot.com/ 2008/07 / instance unique de votre application.html

Je pense que ce sera une aide pour ceux qui appliquent un pare-feu strict.

Vous pouvez utiliser la bibliothèque JUnique. Il fournit un support pour l'exécution d'une application Java à instance unique et est open source.

http://www.sauronsoftware.it/projects/junique/

  

La bibliothèque JUnique peut être utilisée pour empêcher un utilisateur de s'exécuter de la même manière.   temps plus d'instances de la même application Java.

     

JUnique implémente des verrous et des canaux de communication partagés entre tous   les instances JVM lancées par le même utilisateur.

public static void main(String[] args) {
    String appId = "myapplicationid";
    boolean alreadyRunning;
    try {
        JUnique.acquireLock(appId, new MessageHandler() {
            public String handle(String message) {
                // A brand new argument received! Handle it!
                return null;
            }
        });
        alreadyRunning = false;
    } catch (AlreadyLockedException e) {
        alreadyRunning = true;
    }
    if (!alreadyRunning) {
        // Start sequence here
    } else {
        for (int i = 0; i < args.length; i++) {
            JUnique.sendMessage(appId, args[0]));
        }
    }
}

Sous le capot, il crée des verrous de fichiers dans le dossier% USER_DATA% /. junique et crée un socket de serveur sur un port aléatoire pour chaque application unique permettant d'envoyer / de recevoir des messages entre des applications java.

Sous Windows, vous pouvez utiliser launch4j .

Classe ManagementFactory prise en charge dans J2SE version 5.0 ou ultérieure détail

mais maintenant j'utilise J2SE 1.4 et j'ai trouvé celui-ci http://audiprimadhanty.wordpress.com/2008/06/30/ensuring-one-instance-of-application-running-at-one-time/ , mais Je n'ai jamais testé. Qu'en pensez-vous?

Vous pouvez essayer d’utiliser l’API de préférences. C'est une plateforme indépendante.

Un moyen plus générique de limiter le nombre d'instances sur une seule machine, voire sur un réseau entier, consiste à utiliser un socket multidiffusion.

L’utilisation d’un socket multidiffusion vous permet de diffuser un message à n’importe quel nombre d’instances de votre application, dont certaines peuvent se trouver sur des machines physiquement distantes d’un réseau d’entreprise.

De cette manière, vous pouvez activer de nombreux types de configurations pour contrôler des éléments tels que

.
  • Une ou plusieurs instances par machine
  • Une ou plusieurs instances par réseau (par exemple, contrôle des installations sur un site client)

La prise en charge de la multidiffusion par Java s'effectue via le package java.net avec MulticastSocket & amp; DatagramSocket étant les principaux outils.

Remarque : MulticastSocket ne garantit pas la livraison des paquets de données. Vous devez donc utiliser un outil créé au-dessus des sockets multidiffusion, tel que JGroups . JGroups garantit la livraison de toutes les données. C'est un fichier jar unique, avec une API très simple.

JGroups existe depuis un certain temps et a des utilisations impressionnantes dans l’industrie. Par exemple, le mécanisme de clustering de JBoss diffuse des données vers toutes les instances d’un cluster.

Pour utiliser JGroups, limiter le nombre d'instances d'une application (sur une machine ou un réseau, disons: au nombre de licences qu'un client a achetées) est très simple sur le plan conceptuel:

  • Au démarrage de votre application, chaque instance tente de rejoindre un groupe nommé, par exemple "Mon groupe d'applications géniales". Vous aurez configuré ce groupe pour autoriser 0, 1 ou N membres
  • Lorsque le nombre de membres du groupe est supérieur à celui que vous avez configuré pour cela, votre application doit refuser de démarrer.

Vous pouvez ouvrir un fichier mappé en mémoire et voir si ce fichier est déjà ouvert. s'il est déjà ouvert, vous pouvez revenir du menu principal.

Vous pouvez également utiliser des fichiers de verrouillage (pratique standard Unix). Une autre méthode consiste à insérer quelque chose dans le presse-papiers lorsque l’enregistrement principal démarre après avoir vérifié si quelque chose se trouve déjà dans le presse-papiers.

Sinon, vous pouvez ouvrir un socket en mode d'écoute (ServerSocket). Essayez d'abord de vous connecter à sa prise; si vous ne pouvez pas vous connecter, ouvrez un socketservers si vous vous connectez, alors vous savez qu'une autre instance est déjà en cours d'exécution.

Ainsi, pratiquement toutes les ressources système peuvent être utilisées pour savoir qu'une application est en cours d'exécution.

BR, ~ A

J'ai utilisé des sockets pour cela et, selon que l'application est côté client ou côté serveur, le comportement est un peu différent:

  • côté client: si une instance existe déjà (je ne peux pas écouter sur un port spécifique), je transmettrai les paramètres de l'application et quitterai (vous souhaiterez peut-être effectuer certaines actions dans l'instance précédente). Sinon, je lancerai l'application. / li>
  • côté serveur: si une instance existe déjà, je vais imprimer un message et quitter. Sinon, je vais lancer l'application.
public class SingleInstance {
    public static final String LOCK = System.getProperty("user.home") + File.separator + "test.lock";
    public static final String PIPE = System.getProperty("user.home") + File.separator + "test.pipe";
    private static JFrame frame = null;

    public static void main(String[] args) {
        try {
            FileChannel lockChannel = new RandomAccessFile(LOCK, "rw").getChannel();
            FileLock flk = null; 
            try {
                flk = lockChannel.tryLock();
            } catch(Throwable t) {
                t.printStackTrace();
            }
            if (flk == null || !flk.isValid()) {
                System.out.println("alread running, leaving a message to pipe and quitting...");
                FileChannel pipeChannel = null;
                try {
                    pipeChannel = new RandomAccessFile(PIPE, "rw").getChannel();
                    MappedByteBuffer bb = pipeChannel.map(FileChannel.MapMode.READ_WRITE, 0, 1);
                    bb.put(0, (byte)1);
                    bb.force();
                } catch (Throwable t) {
                    t.printStackTrace();
                } finally {
                    if (pipeChannel != null) {
                        try {
                            pipeChannel.close();
                        } catch (Throwable t) {
                            t.printStackTrace();
                        }
                    } 
                }
                System.exit(0);
            }
            //We do not release the lock and close the channel here, 
            //  which will be done after the application crashes or closes normally. 
            SwingUtilities.invokeLater(
                new Runnable() {
                    public void run() {
                        createAndShowGUI();
                    }
                }
            );

            FileChannel pipeChannel = null;
            try {
                pipeChannel = new RandomAccessFile(PIPE, "rw").getChannel();
                MappedByteBuffer bb = pipeChannel.map(FileChannel.MapMode.READ_WRITE, 0, 1);
                while (true) {
                    byte b = bb.get(0);
                    if (b > 0) {
                        bb.put(0, (byte)0);
                        bb.force();
                        SwingUtilities.invokeLater(
                            new Runnable() {
                                public void run() {
                                    frame.setExtendedState(JFrame.NORMAL);
                                    frame.setAlwaysOnTop(true);
                                    frame.toFront();
                                    frame.setAlwaysOnTop(false);
                                }
                            }
                        );
                    }
                    Thread.sleep(1000);
                }
            } catch (Throwable t) {
                t.printStackTrace();
            } finally {
                if (pipeChannel != null) {
                    try {
                        pipeChannel.close();
                    } catch (Throwable t) {
                        t.printStackTrace();
                    } 
                } 
            }
        } catch(Throwable t) {
            t.printStackTrace();
        } 
    }

    public static void createAndShowGUI() {

        frame = new JFrame();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setSize(800, 650);
        frame.getContentPane().add(new JLabel("MAIN WINDOW", 
                    SwingConstants.CENTER), BorderLayout.CENTER);
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    }
}

MODIFIER : au lieu d'utiliser cette approche WatchService, vous pouvez utiliser un simple thread d'horloge d'une seconde pour vérifier si le fichier indicatorFile.exists (). Supprimez-le, puis apportez l'application toFront ().

MODIFIER : je voudrais savoir pourquoi cette décision a été rejetée. C'est la meilleure solution que j'ai vue jusqu'à présent. Par exemple. L’approche socket serveur échoue si une autre application écoute déjà le port.

Il suffit de télécharger Microsoft Windows Sysinternals TCPView (ou d'utiliser netstat) , lancez-le, triez-le par "État", recherchez le bloc de ligne indiquant "ÉCOUTE", choisissez-en une dont l'adresse distante indique le nom de votre ordinateur, mettez ce port dans votre solution new-Socket (). Dans ma mise en œuvre, je peux produire un échec à chaque fois. Et c’est logique , car c’est le fondement même de l’approche. Ou qu'est-ce que je ne comprends pas en ce qui concerne la mise en œuvre?

S'il vous plaît, informez-moi si et comment je me trompe!

Mon point de vue - que je vous demande de réfuter si possible - est d’inviter les développeurs à utiliser une approche du code de production qui échouera dans au moins 1 cas sur environ 60000. Et si ce point de vue est correct, il se peut pas que la solution présentée qui ne présente pas ce problème soit rejetée et critiquée pour sa quantité de code.

Inconvénients de l’approche socket en comparaison:

  • Echoue si le mauvais ticket de loterie (numéro de port) est choisi.
  • Échec dans un environnement multi-utilisateurs: un seul utilisateur peut exécuter l'application en même temps. (Mon approche devra être légèrement modifiée pour créer le (s) fichier (s) dans l'arborescence de l'utilisateur, mais c'est trivial.)
  • Échec si les règles du pare-feu sont trop strictes.
  • Les utilisateurs suspects (que j’ai rencontrés à l’état sauvage) se demandent ce que vous êtes en train de manigancer lorsque votre éditeur de texte réclame un socket de serveur.

Je viens d'avoir une bonne idée sur la façon de résoudre le problème de communication Java d'une instance à une instance existante d'une manière qui devrait fonctionner sur tous les systèmes. Alors, j'ai préparé cette classe en deux heures environ. Fonctionne comme un charme: D

Il est basé sur la méthode de verrouillage des fichiers de Robert (également sur cette page) utilisée par , que j'ai utilisée depuis. Pour indiquer à l'instance déjà en cours d'exécution qu'une autre instance a essayé de démarrer (mais ne l'a pas fait) ... un fichier est créé et immédiatement supprimé, et la première instance utilise WatchService pour détecter cette modification du contenu du dossier. Je n'arrive pas à croire qu'il s'agit apparemment d'une nouvelle idée, compte tenu de la nature fondamentale du problème.

Cela peut facilement être modifié pour simplement créer et ne pas supprimer le fichier. Des informations peuvent ensuite être insérées dans le fichier, ce que l'instance appropriée peut évaluer, par exemple. les arguments de ligne de commande - et l'instance appropriée peut alors effectuer la suppression. Personnellement, je devais seulement savoir quand restaurer la fenêtre de mon application et l’envoyer au premier plan.

Exemple d'utilisation:

public static void main(final String[] args) {

    // ENSURE SINGLE INSTANCE
    if (!SingleInstanceChecker.INSTANCE.isOnlyInstance(Main::otherInstanceTriedToLaunch, false)) {
        System.exit(0);
    }

    // launch rest of application here
    System.out.println("Application starts properly because it's the only instance.");
}

private static void otherInstanceTriedToLaunch() {
    // Restore your application window and bring it to front.
    // But make sure your situation is apt: This method could be called at *any* time.
    System.err.println("Deiconified because other instance tried to start.");
}

Voici la classe:

package yourpackagehere;

import javax.swing.*;
import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.channels.FileLock;
import java.nio.file.*;




/**
 * SingleInstanceChecker v[(2), 2016-04-22 08:00 UTC] by dreamspace-president.com
 * <p>
 * (file lock single instance solution by Robert https://stackoverflow.com/a/2002948/3500521)
 */
public enum SingleInstanceChecker {

    INSTANCE; // HAHA! The CONFUSION!


    final public static int POLLINTERVAL = 1000;
    final public static File LOCKFILE = new File("SINGLE_INSTANCE_LOCKFILE");
    final public static File DETECTFILE = new File("EXTRA_INSTANCE_DETECTFILE");


    private boolean hasBeenUsedAlready = false;


    private WatchService watchService = null;
    private RandomAccessFile randomAccessFileForLock = null;
    private FileLock fileLock = null;


    /**
     * CAN ONLY BE CALLED ONCE.
     * <p>
     * Assumes that the program will close if FALSE is returned: The other-instance-tries-to-launch listener is not
     * installed in that case.
     * <p>
     * Checks if another instance is already running (temp file lock / shutdownhook). Depending on the accessibility of
     * the temp file the return value will be true or false. This approach even works even if the virtual machine
     * process gets killed. On the next run, the program can even detect if it has shut down irregularly, because then
     * the file will still exist. (Thanks to Robert https://stackoverflow.com/a/2002948/3500521 for that solution!)
     * <p>
     * Additionally, the method checks if another instance tries to start. In a crappy way, because as awesome as Java
     * is, it lacks some fundamental features. Don't worry, it has only been 25 years, it'll sure come eventually.
     *
     * @param codeToRunIfOtherInstanceTriesToStart Can be null. If not null and another instance tries to start (which
     *                                             changes the detect-file), the code will be executed. Could be used to
     *                                             bring the current (=old=only) instance to front. If null, then the
     *                                             watcher will not be installed at all, nor will the trigger file be
     *                                             created. (Null means that you just don't want to make use of this
     *                                             half of the class' purpose, but then you would be better advised to
     *                                             just use the 24 line method by Robert.)
     *                                             <p>
     *                                             BE CAREFUL with the code: It will potentially be called until the
     *                                             very last moment of the program's existence, so if you e.g. have a
     *                                             shutdown procedure or a window that would be brought to front, check
     *                                             if the procedure has not been triggered yet or if the window still
     *                                             exists / hasn't been disposed of yet. Or edit this class to be more
     *                                             comfortable. This would e.g. allow you to remove some crappy
     *                                             comments. Attribution would be nice, though.
     * @param executeOnAWTEventDispatchThread      Convenience function. If false, the code will just be executed. If
     *                                             true, it will be detected if we're currently on that thread. If so,
     *                                             the code will just be executed. If not so, the code will be run via
     *                                             SwingUtilities.invokeLater().
     * @return if this is the only instance
     */
    public boolean isOnlyInstance(final Runnable codeToRunIfOtherInstanceTriesToStart, final boolean executeOnAWTEventDispatchThread) {

        if (hasBeenUsedAlready) {
            throw new IllegalStateException("This class/method can only be used once, which kinda makes sense if you think about it.");
        }
        hasBeenUsedAlready = true;

        final boolean ret = canLockFileBeCreatedAndLocked();

        if (codeToRunIfOtherInstanceTriesToStart != null) {
            if (ret) {
                // Only if this is the only instance, it makes sense to install a watcher for additional instances.
                installOtherInstanceLaunchAttemptWatcher(codeToRunIfOtherInstanceTriesToStart, executeOnAWTEventDispatchThread);
            } else {
                // Only if this is NOT the only instance, it makes sense to create&delete the trigger file that will effect notification of the other instance.
                //
                // Regarding "codeToRunIfOtherInstanceTriesToStart != null":
                // While creation/deletion of the file concerns THE OTHER instance of the program,
                // making it dependent on the call made in THIS instance makes sense
                // because the code executed is probably the same.
                createAndDeleteOtherInstanceWatcherTriggerFile();
            }
        }

        optionallyInstallShutdownHookThatCleansEverythingUp();

        return ret;
    }


    private void createAndDeleteOtherInstanceWatcherTriggerFile() {

        try {
            final RandomAccessFile randomAccessFileForDetection = new RandomAccessFile(DETECTFILE, "rw");
            randomAccessFileForDetection.close();
            Files.deleteIfExists(DETECTFILE.toPath()); // File is created and then instantly deleted. Not a problem for the WatchService :)
        } catch (Exception e) {
            e.printStackTrace();
        }
    }


    private boolean canLockFileBeCreatedAndLocked() {

        try {
            randomAccessFileForLock = new RandomAccessFile(LOCKFILE, "rw");
            fileLock = randomAccessFileForLock.getChannel().tryLock();
            return fileLock != null;
        } catch (Exception e) {
            return false;
        }
    }


    private void installOtherInstanceLaunchAttemptWatcher(final Runnable codeToRunIfOtherInstanceTriesToStart, final boolean executeOnAWTEventDispatchThread) {

        // PREPARE WATCHSERVICE AND STUFF
        try {
            watchService = FileSystems.getDefault().newWatchService();
        } catch (IOException e) {
            e.printStackTrace();
            return;
        }
        final File appFolder = new File("").getAbsoluteFile(); // points to current folder
        final Path appFolderWatchable = appFolder.toPath();


        // REGISTER CURRENT FOLDER FOR WATCHING FOR FILE DELETIONS
        try {
            appFolderWatchable.register(watchService, StandardWatchEventKinds.ENTRY_DELETE);
        } catch (IOException e) {
            e.printStackTrace();
            return;
        }


        // INSTALL WATCHER THAT LOOKS IF OUR detectFile SHOWS UP IN THE DIRECTORY CHANGES. IF THERE'S A CHANGE, ANOTHER INSTANCE TRIED TO START, SO NOTIFY THE CURRENT ONE OF THAT.
        final Thread t = new Thread(() -> watchForDirectoryChangesOnExtraThread(codeToRunIfOtherInstanceTriesToStart, executeOnAWTEventDispatchThread));
        t.setDaemon(true);
        t.setName("directory content change watcher");
        t.start();
    }


    private void optionallyInstallShutdownHookThatCleansEverythingUp() {

        if (fileLock == null && randomAccessFileForLock == null && watchService == null) {
            return;
        }

        final Thread shutdownHookThread = new Thread(() -> {
            try {
                if (fileLock != null) {
                    fileLock.release();
                }
                if (randomAccessFileForLock != null) {
                    randomAccessFileForLock.close();
                }
                Files.deleteIfExists(LOCKFILE.toPath());
            } catch (Exception ignore) {
            }
            if (watchService != null) {
                try {
                    watchService.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        });
        Runtime.getRuntime().addShutdownHook(shutdownHookThread);
    }


    private void watchForDirectoryChangesOnExtraThread(final Runnable codeToRunIfOtherInstanceTriesToStart, final boolean executeOnAWTEventDispatchThread) {

        while (true) { // To eternity and beyond! Until the universe shuts down. (Should be a volatile boolean, but this class only has absolutely required features.)

            try {
                Thread.sleep(POLLINTERVAL);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }


            final WatchKey wk;
            try {
                wk = watchService.poll();
            } catch (ClosedWatchServiceException e) {
                // This situation would be normal if the watcher has been closed, but our application never does that.
                e.printStackTrace();
                return;
            }

            if (wk == null || !wk.isValid()) {
                continue;
            }


            for (WatchEvent<?> we : wk.pollEvents()) {

                final WatchEvent.Kind<?> kind = we.kind();
                if (kind == StandardWatchEventKinds.OVERFLOW) {
                    System.err.println("OVERFLOW of directory change events!");
                    continue;
                }


                final WatchEvent<Path> watchEvent = (WatchEvent<Path>) we;
                final File file = watchEvent.context().toFile();


                if (file.equals(DETECTFILE)) {

                    if (!executeOnAWTEventDispatchThread || SwingUtilities.isEventDispatchThread()) {
                        codeToRunIfOtherInstanceTriesToStart.run();
                    } else {
                        SwingUtilities.invokeLater(codeToRunIfOtherInstanceTriesToStart);
                    }

                    break;

                } else {
                    System.err.println("THIS IS THE FILE THAT WAS DELETED: " + file);
                }

            }

            wk.reset();
        }
    }

}
scroll top