訊號簡介
訊號是在軟體層次上對中斷機制的一種類比,在原理上,一個進程收到一個訊號與處理器收到一個插斷要求可以說是一樣的。
通俗來講,訊號就是進程間的一種非同步通訊機制。
典型的例子:
kill -s SIGKILL pid (即kill -9 pid) 立即殺死指定pid的進程。
在上面這個例子中,SIGKILL就是往pid進程發送的訊號。
平台相關性
訊號具有平台相關性,不同平台下能使用的訊號種類是有差異的。
在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
訊號選擇
為了不干擾正常訊號的運作,又能類比Java非同步通知,我們需要先選定一種特殊的訊號。
通過查看訊號列表上的描述,發現 SIGUSR1 和 SIGUSR2 是允許使用者自訂的訊號。
那麼選擇它們,理論上就不會影響正常功能了。
這裡我選用了USR2作為傳遞訊號。原因是USR1有可能已被其他APP佔用。
執行個體代碼
import sun.misc.Signal;import sun.misc.SignalHandler;/** * Java Signal Test * @author Ken Wu * */@SuppressWarnings("restriction")public class TestSignal implements SignalHandler { private void signalCallback(Signal sn) { System.out.println(sn.getName() + "is recevied."); } @Override public void handle(Signal signalName) { signalCallback(signalName); } public static void main(String[] args) throws InterruptedException { TestSignal testSignalHandler = new TestSignal(); // install signals Signal sig = new Signal("USR2"); Signal.handle(sig, testSignalHandler); Thread.sleep(15000); }}Sun為我們提供了2個方便安裝和替換訊號處理器的工具類。
sun.misc.Signal
sun.misc.SignalHandler
將上面的代碼編譯後,運行,會暫停15秒,此時,是你給java進程發送訊號最佳時機。
發送訊號前,需要先通過 ps 或 jps 擷取java的進程id,然後運行
kill -s SIGUSR2 pid
如果在java的stdout 看到 SIGUSR2 is recevied 字樣,說明訊號被成功送達了。
在Java編程中使用訊號的實際收益訊號作為最原始的進程間非同步通訊手段,有著諸多局限性的,比如不能傳遞上下文,訊號隨時都可能被佔用導致衝突,不具備擴充性等,所以對功能性需求來說,使用它收益甚微。
當然,訊號也不是一無是處,除了用作簡單的非同步通知外,還可以利用它的進程事件通知功能。
在Java裡有一個典型例子,就是 ShutdownHook。