http://wangym.iteye.com/blog/733693
TimYang在博文《降低應用latency方法談》 中提到對Java方法進行Profiling,在某些場景更傾向于采用純Java工具類的方法,比如通過給進程發Signals來實現,以求動態地打開或關閉Profiler。
?
感覺這個思路不錯,以下是一個大致實例:
?
SignalTest.java
?
Java代碼 ?
? ? ?? package ?signal;???? import ?java.util.Observable;??import ?java.util.Observer;??import ?sun.misc.Signal;??import ?sun.misc.SignalHandler;???? ? ? ? ?? public ?class ?SignalTest?implements ?Observer?{???? ????? ? ?? ????public ?static ?void ?main(String[]?args)?{?? ?? ????????new ?SignalTest().go();?? ????}?? ?? ????private ?void ?go()?{?? ?? ????????try ?{?? ?? ????????????HandlerTest?sh?=?new ?HandlerTest();?? ????????????sh.addObserver(this );?? ????????????sh.handleSignal("HUP" );?? ????????????sh.handleSignal("BUS" );?? ????????????System.out.println("Sleeping?for?60?seconds:?hit?me?with?signals!" );?? ????????????Thread.sleep(60000 );?? ?? ????????}?catch ?(Throwable?x)?{?? ?? ????????????x.printStackTrace();?? ????????}?? ????}?? ?? ????? ? ?? ????@Override ?? ????public ?void ?update(Observable?arg0,?Object?arg1)?{?? ?? ????????System.out.println("Received?signal:?" ?+?arg1);?? ????}?? ?? ????? ? ?? ????class ?HandlerTest?extends ?Observable?implements ?SignalHandler?{?? ?? ????????@Override ?? ????????public ?void ?handle(Signal?signal)?{?? ?? ????????????setChanged();?? ????????????notifyObservers(signal);?? ????????}?? ?? ????????? ? ? ? ?? ????????public ?void ?handleSignal(String?signalName)?throws ?IllegalArgumentException?{?? ?? ????????????try ?{?? ?? ????????????????Signal.handle(new ?Signal(signalName),?this );?? ?? ????????????}?catch ?(IllegalArgumentException?x)?{?? ?? ????????????????throw ?x;?? ?? ????????????}?catch ?(Throwable?x)?{?? ?? ????????????????throw ?new ?IllegalArgumentException("Signal?unsupported:?" +signalName,?x);?? ????????????}?? ????????}?? ????}?? ?? }??
/*** */
package signal;import java.util.Observable;
import java.util.Observer;
import sun.misc.Signal;
import sun.misc.SignalHandler;/*** @author xuanyin* */
public class SignalTest implements Observer {/*** @param args*/public static void main(String[] args) {new SignalTest().go();}private void go() {try {HandlerTest sh = new HandlerTest();sh.addObserver(this);sh.handleSignal("HUP");sh.handleSignal("BUS");System.out.println("Sleeping for 60 seconds: hit me with signals!");Thread.sleep(60000);} catch (Throwable x) {x.printStackTrace();}}/*** */@Overridepublic void update(Observable arg0, Object arg1) {System.out.println("Received signal: " + arg1);}/*** HandlerTest Class*/class HandlerTest extends Observable implements SignalHandler {@Overridepublic void handle(Signal signal) {setChanged();notifyObservers(signal);}/*** * @param signalName* @throws IllegalArgumentException*/public void handleSignal(String signalName) throws IllegalArgumentException {try {Signal.handle(new Signal(signalName), this);} catch (IllegalArgumentException x) {throw x;} catch (Throwable x) {throw new IllegalArgumentException("Signal unsupported: "+signalName, x);}}}}
?
首先運行執行上述程序,然后查看其系統進程號。
如,若是4089,則在終端中執行kill -s BUS 4089
Java程序輸出:Received signal: SIGBUS
?
信號具有平臺相關性,不同平臺下能使用的信號種類是有差異的。
?
Linux下支持的信號:
SEGV, ILL, FPE, BUS, SYS, CPU, FSZ, ABRT, INT, TERM, HUP, USR1, USR2, QUIT, BREAK, TRAP, PIPE
Windows下支持的信號:
SEGV, ILL, FPE, ABRT, INT, TERM, BREAK
?
不足之處歡迎大家留言指正:)
======================
http://blog.csdn.net/raintungli/article/details/7310141
在java 中調用Signal的方法handle可以去注冊一個信號的處理函數,方法的如下:
[java] view plaincopyprint?
?public ?static ?synchronized ?SignalHandler?handle(Signal?sig,??? ????????????????????????????SignalHandler?handler)?{?? ....?? }??
public static synchronized SignalHandler handle(Signal sig, SignalHandler handler) {
....
}
比如常用的addShutdownHook鉤子函數里,就是在?Terminator.setup();的時候將Shutdown.exit 的函數注冊到了信號SHUTDOWN1_SIGNAL(SIGHUP), SHUTDOWN2_SIGNAL(SIGINT), SHUTDOWN3_SIGNAL(SIGTERM)中,當線程接受到信號時,通過調用函數Shutdown.exit的調用hook中的鉤子函數。
在筆者的文章(java 中關于信號的處理在linux下的實現)也提到jdk如何處理信號的,那么調用handle里是不是直接就把這個方法注冊進了信號處理呢?
請注意,handle是一個java的方法,而注冊信號函數是c的代碼,顯然不能簡單的將java的方法直接提供給c調用,其次信號處理函數是在內核態中處理,安全性和執行時間的長短將影響到內核的信號調度。
先看java源碼,如下面所示
[java] view plaincopyprint?
?public ?static ?synchronized ?SignalHandler?handle(Signal?sig,??? ????????????????????????SignalHandler?handler)??? throws ?IllegalArgumentException?{??long ?newH?=?(handler?instanceof ?NativeSignalHandler)???????????????????((NativeSignalHandler)handler).getHandler()?:?2 ;?? long ?oldH?=?handle0(sig.number,?newH);??if ?(oldH?==?-1 )?{??????throw ?new ?IllegalArgumentException?? ????("Signal?already?used?by?VM:?" ?+?sig);?? }?? signals.put(new ?Integer(sig.number),?sig);?? synchronized ?(handlers)?{??????SignalHandler?oldHandler?=?(SignalHandler)handlers.get(sig);?? ????handlers.remove(sig);?? ????if ?(newH?==?2 )?{?? ????????handlers.put(sig,?handler);??????????? ????}?? ????if ?(oldH?==?0 )?{?? ????????return ?SignalHandler.SIG_DFL;?? ????}?else ?if ?(oldH?==?1 )?{?? ????????return ?SignalHandler.SIG_IGN;?? ????}?else ?if ?(oldH?==?2 )?{?? ????????return ?oldHandler;?? ????}?else ?{?? ????????return ?new ?NativeSignalHandler(oldH);?? ????}?? }?? ???}??
public static synchronized SignalHandler handle(Signal sig, SignalHandler handler) throws IllegalArgumentException {long newH = (handler instanceof NativeSignalHandler) ? ((NativeSignalHandler)handler).getHandler() : 2;long oldH = handle0(sig.number, newH);if (oldH == -1) {throw new IllegalArgumentException("Signal already used by VM: " + sig);}signals.put(new Integer(sig.number), sig);synchronized (handlers) {SignalHandler oldHandler = (SignalHandler)handlers.get(sig);handlers.remove(sig);if (newH == 2) {handlers.put(sig, handler); }if (oldH == 0) {return SignalHandler.SIG_DFL;} else if (oldH == 1) {return SignalHandler.SIG_IGN;} else if (oldH == 2) {return oldHandler;} else {return new NativeSignalHandler(oldH);}}}
在native code hand0里并沒有將handle的方法傳進去,只是傳了一個整型值。
在c++代碼中hand0里調用了函數?JVM_RegisterSignal,具體來看一下這個函數的實現
[cpp] view plaincopyprint?
JVM_ENTRY_NO_ENV(void *,?JVM_RegisterSignal(jint?sig,?void *?handler))?? ???? ???? ??void *?newHandler?=?handler?==?(void ?*)2?? ?????????????????????os::user_handler()?? ???????????????????:?handler;?? ??switch ?(sig)?{?? ?????? ????case ?INTERRUPT_SIGNAL:?? ????case ?SIGFPE:?? ????case ?SIGILL:?? ????case ?SIGSEGV:?? ?? ????? ? ? ?? ????case ?BREAK_SIGNAL:?? ??????return ?(void ?*)-1;?? ?? ????? ? ? ? ? ? ? ? ?? ?? ????case ?SHUTDOWN1_SIGNAL:?? ????case ?SHUTDOWN2_SIGNAL:?? ????case ?SHUTDOWN3_SIGNAL:?? ??????if ?(ReduceSignalUsage)?return ?(void *)-1;?? ??????if ?(os::Linux::is_sig_ignored(sig))?return ?(void *)1;?? ??}?? ?? ??void *?oldHandler?=?os::signal(sig,?newHandler);?? ??if ?(oldHandler?==?os::user_handler())?{?? ??????return ?(void ?*)2;?? ??}?else ?{?? ??????return ?oldHandler;?? ??}?? JVM_END??
JVM_ENTRY_NO_ENV(void*, JVM_RegisterSignal(jint sig, void* handler))// Copied from classic vm// signals_md.c 1.4 98/08/23void* newHandler = handler == (void *)2? os::user_handler(): handler;switch (sig) {/* The following are already used by the VM. */case INTERRUPT_SIGNAL:case SIGFPE:case SIGILL:case SIGSEGV:/* The following signal is used by the VM to dump thread stacks unlessReduceSignalUsage is set, in which case the user is allowed to sethis own _native_ handler for this signal; thus, in either case,we do not allow JVM_RegisterSignal to change the handler. */case BREAK_SIGNAL:return (void *)-1;/* The following signals are used for Shutdown Hooks support. However, ifReduceSignalUsage (-Xrs) is set, Shutdown Hooks must be invoked viaSystem.exit(), Java is not allowed to use these signals, and the theuser is allowed to set his own _native_ handler for these signals andinvoke System.exit() as needed. Terminator.setup() is avoidingregistration of these signals when -Xrs is present.- If the HUP signal is ignored (from the nohup) command, then Javais not allowed to use this signal.*/case SHUTDOWN1_SIGNAL:case SHUTDOWN2_SIGNAL:case SHUTDOWN3_SIGNAL:if (ReduceSignalUsage) return (void*)-1;if (os::Linux::is_sig_ignored(sig)) return (void*)1;}void* oldHandler = os::signal(sig, newHandler);if (oldHandler == os::user_handler()) {return (void *)2;} else {return oldHandler;}
JVM_END
[cpp] view plaincopyprint?
void *?newHandler?=?handler?==?(void ?*)2???????????????????????os::user_handler()?? ???????????????????:?handler;??
void* newHandler = handler == (void *)2? os::user_handler(): handler;
因為傳進的值是2,那么真正在c++里的信號處理函數實際上os::user_handler(),同時jvm也保護了幾個信號,不允許外部改變信號的處理函數。
一切豁然開朗,筆者的博客(java 中關于信號的處理在linux下的實現)已經提到過這個函數,通過os:signal_notify 去通知signal dispatcher 線程的 os::signal_wait,也就是接受到信號的線程通過信號函數notify到處理信號的線程(signal dispatcher ),最后由該線程做后續的事情。
具體來看signal dispatcher 的thread entry
[cpp] view plaincopyprint?
static ?void ?signal_thread_entry(JavaThread*?thread ,?TRAPS)?{????????....?? ??????default :?{?? ?????????? ????????HandleMark?hm(THREAD);?? ????????klassOop?k?=?SystemDictionary::resolve_or_null(vmSymbolHandles::sun_misc_Signal(),?THREAD);?? ????????KlassHandle?klass?(THREAD,?k);?? ????????if ?(klass.not_null())?{?? ??????????JavaValue?result(T_VOID);?? ??????????JavaCallArguments?args;?? ??????????args.push_int(sig);?? ??????????JavaCalls::call_static(?? ????????????&result,?? ????????????klass,?? ????????????vmSymbolHandles::dispatch_name(),?? ????????????vmSymbolHandles::int_void_signature(),?? ????????????&args,?? ????????????THREAD?? ??????????);?? ????????}?? ????????....?? }??
static void signal_thread_entry(JavaThread* thread, TRAPS) {....default: {// Dispatch the signal to javaHandleMark hm(THREAD);klassOop k = SystemDictionary::resolve_or_null(vmSymbolHandles::sun_misc_Signal(), THREAD);KlassHandle klass (THREAD, k);if (klass.not_null()) {JavaValue result(T_VOID);JavaCallArguments args;args.push_int(sig);JavaCalls::call_static(&result,klass,vmSymbolHandles::dispatch_name(),vmSymbolHandles::int_void_signature(),&args,THREAD);}....
}
也就是在jvm的c++源碼中,反調用了java的方法,也就是signal.java中的dispatch(int number),方法dispatch中才是真正的調用了在文章開頭提到的注冊到Signal的方法handle。
dispatch方法中仍然起了一個新的線程去處理handle,這樣就不會block?signal dispatcher 線程。
總結
以上是生活随笔 為你收集整理的Java Signal实例 的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔 網站內容還不錯,歡迎將生活随笔 推薦給好友。