2010-03-29 6 views
84

में सिग्किल सिग्नल को गहन तरीके से कैसे संभालना है, जब प्रोग्राम को मारने का संकेत मिलता है तो आप साफ कैसे करते हैं?जावा

उदाहरण के लिए, एक ऐसा एप्लिकेशन है जो मैं कनेक्ट करता हूं जो किसी भी तृतीय पक्ष ऐप (मेरे ऐप) को finish कमांड लॉग आउट करते समय भेजने के लिए चाहता है। के साथ मेरा ऐप नष्ट होने पर finish कमांड भेजने के लिए सबसे अच्छा क्या कहना है?

संपादित करें 1: kill -9 को कैद नहीं किया जा सकता है। मुझे सुधारने के लिए धन्यवाद दोस्तों।

संपादित 2: मुझे लगता है कि जब एक कॉल बस को मारने के रूप में Ctrl-C में ही है इस मामले होगा

+30

'kill -9' का मतलब है:" बेगोन, फाउल प्रोसेस, आपके साथ दूर! ", जिस पर प्रक्रिया समाप्त हो जाएगी। तुरंत ही। – ZoogieZork

+7

अधिकांश * निक्स जिन्हें मैं जानता हूं, मार -9 को किसी भी प्रोग्राम द्वारा अवरुद्ध और सुन्दर तरीके से संभाला नहीं जा सकता है इससे कोई फर्क नहीं पड़ता कि यह किस भाषा में लिखा गया था। –

+1

@ बेगुई: अन्य लोगों ने टिप्पणी की और उत्तर दिया, * अगर * आपका अन * एक्स ओएस तत्काल मारता नहीं है * और सभी संसाधनों को फिर से प्राप्त करें * प्रोग्राम द्वारा * kill -9'ed * के रूप में उपयोग किया जाता है, ठीक है ... ओएस टूटा हुआ है। – SyntaxT3rr0r

उत्तर

94

रास्ता अन्यkill -9 की तुलना में एक shutdown हुक रजिस्टर करने के लिए किया जाएगा कुछ भी करने के लिए इस संभाल करने के लिए । यदि आप (SIGTERM) का उपयोग कर सकते हैं kill -15 शट डाउन हुक काम करेगा। (SIGINT) kill -2DOES प्रोग्राम को शटडाउन हुक से बाहर निकलने और चलाने के लिए कारण बनता है।

रजिस्टर्स एक नई आभासी मशीन शट डाउन हुक।

* The program exits normally, when the last non-daemon thread exits or 

जब बाहर निकलें (समतुल्य रूप, System.exit) विधि शुरू हो जाती है, या

* The virtual machine is terminated in response to a user 

बाधा:

जावा आभासी मशीन की घटनाओं के दो प्रकार के जवाब में बंद हो जाता है , जैसे कि टाइपिंग सी, या सिस्टम-वाइड इवेंट, जैसे उपयोगकर्ता लॉगऑफ या सिस्टम शट डाउन।

मैं पर OSX 10.6.3 निम्नलिखित परीक्षण कार्यक्रम की कोशिश की और kill -9 पर यह किया नहीं बंद हुक चलाने के लिए, नहीं सोचा था कि यह होगा। kill -15 पर यह DOES हर बार शटडाउन हुक चलाता है।

public class TestShutdownHook 
{ 
    public static void main(final String[] args) throws InterruptedException 
    { 
     Runtime.getRuntime().addShutdownHook(new Thread() 
     { 
      @Override 
      public void run() 
      { 
       System.out.println("Shutdown hook ran!"); 
      } 
     }); 

     while (true) 
     { 
      Thread.sleep(1000); 
     } 
    } 
} 

वहाँ किसी भी तरह से वास्तव में शान से किसी भी कार्यक्रम में एक kill -9 को संभालने के लिए नहीं है।

दुर्लभ परिस्थितियों आभासी मशीन गर्भपात हो सकता है, वह है, सफाई से बंद किए बिना चलना बंद में

। ऐसा तब होता है जब वर्चुअल मशीन को बाहरी रूप से समाप्त किया जाता है, उदाहरण के लिए यूनिक्स पर सिगकिल सिग्नल के साथ या माइक्रोसॉफ्ट विंडोज पर टर्मिनेट प्रोसेस कॉल।

एक kill -9 को संभालने के लिए केवल वास्तविक विकल्प अपने मुख्य कार्यक्रम चले जाओ या एक आवरण स्क्रिप्ट का उपयोग करने के लिए एक और द्रष्टा कार्यक्रम घड़ी है। आप इसके साथ एक शेल स्क्रिप्ट के साथ ऐसा कर सकते हैं जिसने ps कमांड को सूची में अपने प्रोग्राम की तलाश में मतदान किया और जब गायब हो गया तो तदनुसार कार्य करें।

#!/bin/bash 

java TestShutdownHook 
wait 
# notify your other app that you quit 
echo "TestShutdownHook quit" 
7

आप Runtime.getRuntime().addShutdownHook(...) उपयोग कर सकते हैं, लेकिन आप की गारंटी नहीं हो सकता है कि यह किसी भी मामले में बुलाया जाएगा।

+5

लेकिन हत्या -9 के मामले में यह लगभग निश्चित रूप से नहीं चलेगा। –

12

कुछ JVMs में अपने स्वयं के संकेतों को संभालने के तरीके हैं - उदाहरण के लिए this article about the HotSpot JVM देखें।

सूर्य आंतरिक sun.misc.Signal.handle(Signal, SignalHandler) विधि का उपयोग करके फोन आप भी एक संकेत हैंडलर रजिस्टर करने में सक्षम हैं, लेकिन शायद INT या TERM तरह संकेतों के लिए नहीं के रूप में वे JVM द्वारा किया जाता है।

किसी भी सिग्नल को संभालने में सक्षम होने के लिए आपको जेवीएम से बाहर और ऑपरेटिंग सिस्टम क्षेत्र में कूदना होगा।

असामान्य समाप्ति का पता लगाने के लिए मैं आम तौर पर क्या करता हूं, मेरी जेवीएम को पर्ल स्क्रिप्ट के अंदर लॉन्च करना है, लेकिन स्क्रिप्ट waitpid सिस्टम कॉल का उपयोग करके JVM के लिए प्रतीक्षा करें।

मुझे तब भी सूचित किया जाता है जब भी JVM बाहर निकलता है, और यह क्यों निकलता है, और आवश्यक कार्रवाई कर सकता है।

+0

ध्यान दें कि * 'sun.misc. सिग्नल 'के साथ' INT' और 'TERM' को कैप्चर कर सकते हैं, लेकिन आप' QUIT' को संभाल नहीं सकते हैं क्योंकि JVM इसे डिबगिंग के लिए सुरक्षित रखता है, न ही' किल 'क्योंकि ओएस समाप्त हो जाएगा तुरंत JVM। या तो संभालने का प्रयास करने से 'अवैध अवैध अपवाद' बढ़ाया जाएगा। – dimo414

4

मैं उम्मीद होती है कि JVM शान से व्यवधान आवेदन द्वारा बनाई (thread.interrupt()) चल रहे सभी धागे, कम से कम संकेत SIGINT (kill -2) और SIGTERM (kill -15) के लिए।

इस तरह, सिग्नल उन्हें अग्रेषित किया जाएगा, standard ways में एक शानदार थ्रेड रद्दीकरण और संसाधन अंतिम रूप देने की इजाजत दी जाएगी।

लेकिन इस मामले (कम से कम मेरी JVM कार्यान्वयन में नहीं है:।। Java(TM) SE Runtime Environment (build 1.8.0_25-b17), Java HotSpot(TM) 64-Bit Server VM (build 25.25-b02, mixed mode)

के रूप में अन्य उपयोगकर्ताओं ने टिप्पणी की, बंद हुक के उपयोग अनिवार्य लगता है

तो, मैं कैसे करना है इसे संभाल लेंगे?

सबसे पहले, मुझे सभी कार्यक्रमों में इसकी परवाह नहीं है, केवल उन जगहों पर जहां मैं उपयोगकर्ता रद्दीकरण और अप्रत्याशित सिरों का ट्रैक रखना चाहता हूं। उदाहरण के लिए, कल्पना करें कि आपका जावा प्रोग्राम एक प्रक्रिया आदमी है दूसरे द्वारा वृद्ध आप अलग-अलग करना चाहते हैं कि इसे प्रबंधक प्रक्रिया से SIGTERM) को बंद कर दिया गया है या शट डाउन हुआ है (स्टार्टअप पर स्वचालित रूप से नौकरी को फिर से लॉन्च करने के लिए)।

आधार के आधार पर, मैं हमेशा अपने लंबे समय से चलने वाले थ्रेड को बाधित स्थिति के बारे में जागरूक करता हूं और InterruptedException फेंक देता हूं यदि वे बाधित होते हैं। यह डेवलपर द्वारा नियंत्रित तरीके से निष्पादन अंतिम रूप को सक्षम बनाता है (मानक अवरोधन संचालन के समान परिणाम भी उत्पन्न करता है)। फिर, थ्रेड स्टैक के शीर्ष स्तर पर, InterruptedException कैप्चर किया गया है और उचित क्लीन-अप किया गया है। इन धागे को एक बाधा अनुरोध का जवाब देने के लिए जाना जाता है। उच्च cohesion डिजाइन।

तो, इन मामलों में, मैं एक बंद हुक, करता है कि मैं क्या सोचता JVM डिफ़ॉल्ट रूप से करना चाहिए जोड़ें: बीच में सभी गैर डेमॉन अपने आवेदन के द्वारा बनाई गई धागे है कि अभी भी चल रहे हैं:

Runtime.getRuntime().addShutdownHook(new Thread() { 
    @Override 
    public void run() { 
     System.out.println("Interrupting threads"); 
     Set<Thread> runningThreads = Thread.getAllStackTraces().keySet(); 
     for (Thread th : runningThreads) { 
      if (th != Thread.currentThread() 
       && !th.isDaemon() 
       && th.getClass().getName().startsWith("org.brutusin")) { 
       System.out.println("Interrupting '" + th.getClass() + "' termination"); 
       th.interrupt(); 
      } 
     } 
     for (Thread th : runningThreads) { 
      try { 
       if (th != Thread.currentThread() 
       && !th.isDaemon() 
       && th.isInterrupted()) { 
        System.out.println("Waiting '" + th.getName() + "' termination"); 
        th.join(); 
       } 
      } catch (InterruptedException ex) { 
       System.out.println("Shutdown interrupted"); 
      } 
     } 
     System.out.println("Shutdown finished"); 
    } 
}); 

जिथब पर पूर्ण परीक्षण आवेदन: https://github.com/idelvall/kill-test

0

हत्या -9 पर प्रतिक्रिया करने का एक तरीका है: यह एक अलग प्रक्रिया है जो प्रक्रिया को मॉनीटर करता है और यदि आवश्यक हो तो इसे साफ कर लेता है। इसमें शायद आईपीसी शामिल होगा और यह काफी काम करेगा, और आप एक ही समय में दोनों प्रक्रियाओं को मार कर इसे ओवरराइड कर सकते हैं। मुझे लगता है कि ज्यादातर मामलों में यह परेशानी के लायक नहीं होगा।

जो कोई भी -9 के साथ प्रक्रिया को मारता है उसे सैद्धांतिक रूप से पता होना चाहिए कि वह क्या कर रहा है और यह चीजों को एक असंगत स्थिति में छोड़ सकता है।