แก้ไข : แทนที่จะใช้แนวทาง WatchService นี้สามารถใช้เธรดตัวจับเวลา 1 วินาทีแบบธรรมดาเพื่อตรวจสอบว่า indicatorFile.exists () หรือไม่ ลบออกจากนั้นนำแอปพลิเคชันไปที่ Front ()
แก้ไข : ฉันอยากทราบว่าเหตุใดจึงถูกลดคะแนน เป็นทางออกที่ดีที่สุดที่ฉันเคยเห็นมา เช่นวิธีการซ็อกเก็ตเซิร์ฟเวอร์ล้มเหลวหากมีแอพพลิเคชั่นอื่นกำลังฟังพอร์ตอยู่แล้ว
เพียงดาวน์โหลด Microsoft Windows Sysinternals TCPView (หรือใช้ netstat) เริ่มต้นโดยจัดเรียงตาม "สถานะ" มองหาบล็อกบรรทัดที่ระบุว่า "LISTENING" เลือกที่อยู่ระยะไกลที่ระบุชื่อคอมพิวเตอร์ของคุณใส่พอร์ตนั้นลงในซ็อกเก็ตใหม่ของคุณ ()-วิธีการแก้. ในการนำไปใช้งานของฉันฉันสามารถสร้างความล้มเหลวได้ทุกครั้ง และมันก็มีเหตุผลเพราะมันเป็นรากฐานของแนวทาง หรือฉันไม่ได้รับอะไรเกี่ยวกับวิธีการนำไปใช้?
โปรดแจ้งให้ฉันทราบว่าฉันผิดเกี่ยวกับเรื่องนี้อย่างไร!
มุมมองของฉัน - ซึ่งฉันขอให้คุณพิสูจน์ว่าเป็นไปได้ - คือการที่นักพัฒนาได้รับคำแนะนำให้ใช้แนวทางในรหัสการผลิตที่จะล้มเหลวอย่างน้อย 1 ในประมาณ 60000 กรณี และหากมุมมองนี้เกิดขึ้นถูกต้องก็เป็นไปไม่ได้เลยที่วิธีการแก้ปัญหาที่นำเสนอซึ่งไม่มีปัญหานี้จะถูกลดลงและถูกวิพากษ์วิจารณ์ถึงจำนวนรหัส
ข้อเสียของการเปรียบเทียบวิธีซ็อกเก็ต:
- ล้มเหลวหากเลือกตั๋วลอตเตอรีผิด (หมายเลขพอร์ต)
 
- ล้มเหลวในสภาพแวดล้อมที่มีผู้ใช้หลายคน: ผู้ใช้เพียงคนเดียวสามารถเรียกใช้แอปพลิเคชันพร้อมกัน (แนวทางของฉันจะต้องเปลี่ยนแปลงเล็กน้อยเพื่อสร้างไฟล์ในโครงสร้างผู้ใช้ แต่นั่นเป็นเรื่องเล็กน้อย)
 
- ล้มเหลวหากกฎของไฟร์วอลล์เข้มงวดเกินไป
 
- ทำให้ผู้ใช้ที่น่าสงสัย (ซึ่งฉันได้พบในป่า) สงสัยว่าคุณกำลังทำอะไรอยู่เมื่อโปรแกรมแก้ไขข้อความของคุณอ้างสิทธิ์ในซ็อกเก็ตเซิร์ฟเวอร์
 
ฉันมีความคิดที่ดีสำหรับวิธีแก้ปัญหาการสื่อสาร Java แบบอินสแตนซ์ใหม่ไปยังอินสแตนซ์ที่มีอยู่ในแบบที่ควรใช้กับทุกระบบ ดังนั้นฉันจึงจบคลาสนี้ในเวลาประมาณสองชั่วโมง ใช้งานได้เหมือนมีเสน่ห์: D
มันขึ้นอยู่กับวิธีการล็อกไฟล์ของRobert (เช่นในหน้านี้) ซึ่งฉันก็ใช้มาตลอด เพื่อบอกอินสแตนซ์ที่ทำงานอยู่แล้วว่าอินสแตนซ์อื่นพยายามเริ่มต้น (แต่ไม่ได้) ... ไฟล์จะถูกสร้างและลบทันทีและอินสแตนซ์แรกใช้ WatchService เพื่อตรวจจับการเปลี่ยนแปลงเนื้อหาของโฟลเดอร์นี้ ฉันไม่อยากจะเชื่อเลยว่านี่เป็นแนวคิดใหม่เนื่องจากพื้นฐานของปัญหาเป็นอย่างไร
สิ่งนี้สามารถเปลี่ยนได้อย่างง่ายดายเพียงแค่สร้างและไม่ลบไฟล์จากนั้นสามารถใส่ข้อมูลที่อินสแตนซ์ที่เหมาะสมสามารถประเมินได้เช่นอาร์กิวเมนต์บรรทัดคำสั่งและจากนั้นอินสแตนซ์ที่เหมาะสมก็สามารถทำการลบได้ โดยส่วนตัวแล้วฉันจำเป็นต้องรู้ว่าเมื่อใดที่จะกู้คืนหน้าต่างแอปพลิเคชันของฉันและส่งไปที่ด้านหน้า
ตัวอย่างการใช้งาน:
public static void main(final String[] args) {
    
    if (!SingleInstanceChecker.INSTANCE.isOnlyInstance(Main::otherInstanceTriedToLaunch, false)) {
        System.exit(0);
    }
    
    System.out.println("Application starts properly because it's the only instance.");
}
private static void otherInstanceTriedToLaunch() {
    
    
    System.err.println("Deiconified because other instance tried to start.");
}
นี่คือชั้นเรียน:
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.*;
public enum SingleInstanceChecker {
    INSTANCE; 
    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;
    
    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) {
                
                installOtherInstanceLaunchAttemptWatcher(codeToRunIfOtherInstanceTriesToStart, executeOnAWTEventDispatchThread);
            } else {
                
                
                
                
                
                
                createAndDeleteOtherInstanceWatcherTriggerFile();
            }
        }
        optionallyInstallShutdownHookThatCleansEverythingUp();
        return ret;
    }
    private void createAndDeleteOtherInstanceWatcherTriggerFile() {
        try {
            final RandomAccessFile randomAccessFileForDetection = new RandomAccessFile(DETECTFILE, "rw");
            randomAccessFileForDetection.close();
            Files.deleteIfExists(DETECTFILE.toPath()); 
        } 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) {
        
        try {
            watchService = FileSystems.getDefault().newWatchService();
        } catch (IOException e) {
            e.printStackTrace();
            return;
        }
        final File appFolder = new File("").getAbsoluteFile(); 
        final Path appFolderWatchable = appFolder.toPath();
        
        try {
            appFolderWatchable.register(watchService, StandardWatchEventKinds.ENTRY_DELETE);
        } catch (IOException e) {
            e.printStackTrace();
            return;
        }
        
        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) { 
            try {
                Thread.sleep(POLLINTERVAL);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            final WatchKey wk;
            try {
                wk = watchService.poll();
            } catch (ClosedWatchServiceException e) {
                
                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();
        }
    }
}