كيفية السماح بتشغيل مثيل واحد فقط من برنامج Java في وقت واحد؟

StackOverflow https://stackoverflow.com/questions/920386

  •  06-09-2019
  •  | 
  •  

سؤال

أحتاج إلى منع المستخدمين من بدء تطبيق Java الخاص بي (تطبيق Webstart Swing) عدة مرات. لذلك إذا كان التطبيق يعمل بالفعل، فلا ينبغي أن يكون من الممكن بدء تشغيله مرة أخرى أو إظهار تحذير / إغلاقه مرة أخرى.

هل هناك بعض طريقة مريحة لتحقيق ذلك؟ فكرت في حظر منفذ أو اكتب sth إلى ملف. ولكن نأمل أن تتمكن من الوصول إلى بعض خصائص النظام أو JVM؟

بالمناسبة. النظام الأساسي المستهدف هو نظام التشغيل Windows XP مع Java 1.5

هل كانت مفيدة؟

المحلول

أعتقد أن اقتراحك لفتح منفذ للاستماع عند بدء طلبك هو أفضل فكرة.

من السهل جدا القيام به ولا داعي للقلق بشأن تنظيفه عند إغلاق طلبك. على سبيل المثال، إذا كتبت إلى ملف، لكن شخصا ما يقتل العمليات باستخدام إدارة المهام لن يتم حذف الملف.

أيضا، إذا كنت أتذكر بشكل صحيح، فلا توجد طريقة سهلة للحصول على PID من عملية Java من داخل JVM، لذلك لا تحاول صياغة حل باستخدام PIDS.

شيء من هذا القبيل يجب أن يفعل الخدعة:

private static final int PORT = 9999;
private static ServerSocket socket;    

private static void checkIfRunning() {
  try {
    //Bind to localhost adapter with a zero connection queue 
    socket = new ServerSocket(PORT,0,InetAddress.getByAddress(new byte[] {127,0,0,1}));
  }
  catch (BindException e) {
    System.err.println("Already running.");
    System.exit(1);
  }
  catch (IOException e) {
    System.err.println("Unexpected error.");
    e.printStackTrace();
    System.exit(2);
  }
}

هذا نموذج التعليمات البرمجية يرتبط صراحة 127.0.0.1 والتي يجب أن تتجنب أي تحذيرات جدار الحماية، حيث يجب أن يكون أي حركة مرور على هذا العنوان من النظام المحلي.

عند اختيار ميناء حاول تجنب واحد المذكورة في قائمة منافذ معروفة جيدا. وبعد يجب أن تجعل المنفذ يستخدم بشكل مثالي قابل للتكوين في ملف أو عبر مفتاح سطر الأوامر في حالة تعارضات.

نصائح أخرى

نظرا لأن المسألة تنص على أنه يتم استخدام WebStart، فإن الحل الواضح هو استخدامه javax.jnlp.SingleInstanceService.

هذه الخدمة متوفرة في 1.5. لاحظ أن 1.5 هو حاليا في الوقت الحالي من خلال فترة نهاية نهاية الخدمة. الحصول على مع جافا SE 6!

أعتقد أن الفكرة الأفضل ستكون لاستخدام قفل الملفات (فكرة قديمة تماما :)). منذ Java 1.4 تم تقديم مكتبة I / O الجديدة، والتي تسمح بإغلاق الملفات.

بمجرد بدء تشغيل التطبيق، يحاول الحصول على قفل على ملف (أو إنشاءه إذا لم يكن موجودا)، عندما يخرج التطبيق القفل. إذا كان التطبيق لا يستطيع الحصول على قفل، إنه يستكشف.

المثال كيفية القيام تأمين الملف هو على سبيل المثال في مطوري Java almanac..

إذا كنت ترغب في استخدام ملف تأمين الملفات في تطبيق بدء تشغيل Java Web أو تطبيق صغير تحتاج إلى غناء التطبيق أو التطبيق الصغير.

نحن نفعل نفس الشيء في C ++ عن طريق إنشاء كائن Mutex Kernal ويبحث عنه عند البدء. المزايا هي نفسها مثل استخدام المقبس، أي متى يموت / حوادث / مخارج / خرافة، يتم تنظيف كائن Mutex من قبل النواة.

أنا لست مبرمج Java، لذلك أنا لست متأكدا مما إذا كنت تستطيع أن تفعل نفس النوع من الأشياء في جافا؟

يمكنك استخدام مكتبة junique. يوفر الدعم لتشغيل تطبيق Java مثيل واحد وهو مفتوح المصدر.

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

انظر أيضا إجابتي الكاملة في كيفية تنفيذ تطبيق Java مثيل واحد؟

لقد قمت بإنشاء فئة Applock Cross Platform.

http://rumatoest.blogspot.com/201/01/01/howto-run-only-single-java-application.html.

يستخدم تقنية قفل الملفات.

تحديث. في 2016-10-14 لقد قمت بإنشاء حزمة متوافقة مع Maven / Madle https://github.com/jneat/jneat. وأوضح ذلك هنا http://rumatoest.blogspot.com/0/06/synchronize-code-over-multiple-jvm.html.

يمكنك استخدام السجل، على الرغم من أن هذا يهزم هذا النصف بغرض استخدام لغة رفيعة المستوى مثل Java. على الأقل النظام الأساسي الخاص بك هو Windows = D

جرب جاني:

String appId = "com.example.win.run.main";
boolean alreadyRunning;
try {
    JUnique.acquireLock(appId);
    alreadyRunning = false;
} catch (AlreadyLockedException e) {
    alreadyRunning = true;
}
if (alreadyRunning) {
    Sysout("An Instance of this app is already running");
    System.exit(1);
}

لقد رأيت الكثير من هذه الأسئلة وكنت أتطلع إلى حل نفس المشكلة في طريقة مستقلة منصة لا تأخذ الفرصة للتصادم مع جدران الحماية أو الدخول إلى أشياء المقبس.

لذلك، إليك ما فعلته:

import java.io.File;
import java.io.IOException;

/**
 * This static class is in charge of file-locking the program
 * so no more than one instance can be run at the same time.
 * @author nirei
 */
public class SingleInstanceLock {

    private static final String LOCK_FILEPATH = System.getProperty("java.io.tmpdir") + File.separator + "lector.lock";
    private static final File lock = new File(LOCK_FILEPATH);
    private static boolean locked = false;

    private SingleInstanceLock() {}

    /**
     * Creates the lock file if it's not present and requests its deletion on
     * program termination or informs that the program is already running if
     * that's the case.
     * @return true - if the operation was succesful or if the program already has the lock.<br>
     * false - if the program is already running
     * @throws IOException if the lock file cannot be created.
     */
    public static boolean lock() throws IOException {
        if(locked) return true;

        if(lock.exists()) return false;

        lock.createNewFile();
        lock.deleteOnExit();
        locked = true;
        return true;
    }
}

باستخدام System.getProperty ("java.io.tmpdir") لمسار LockFile يتأكد من أنك ستخلق دائما قفلك في نفس المكان.

ثم، من برنامجك، يمكنك فقط استدعاء شيء مثل:

blah blah main(blah blah blah) {
    try() {
        if(!SingleInstanceLock.lock()) {
            System.out.println("The program is already running");
            System.exit(0);
        }
    } catch (IOException e) {
        System.err.println("Couldn't create lock file or w/e");
        System.exit(1);
    }
}

وهذا يفعل ذلك بالنسبة لي. الآن، إذا قتلت البرنامج، فلن يحذف ملف القفل ولكن يمكنك حل هذا عن طريق كتابة PID للبرنامج في LockFile وجعل طريقة القفل () تحقق مما إذا كانت هذه العملية قيد التشغيل بالفعل. هذا يترك كإحدى لأي شخص مهتم. :)

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top