天天看點

karaf指令行挂起反思

1 問題複述

開發中遇到一個問題,在敲一個指令行的時候,karaf控制台給挂起了,日志沒有異常,通過ssh遠端連接配接還是可以通路控制台,但是簡單的回溯了一下代碼,仔細一看,好像沒有問題,後來仔細跟蹤了以下指令行調用邏輯,在某個io操作中,使用了一個異常捕獲,然後在期望結果未給出的時候捕獲所有異常并死循環等待,所有結果傳回,把邏輯簡要歸納以下,這也是我後來自己的一個測試代碼,如下所示:

if (debugstr != null) {
            long i=1;
            while(true) {
                try {
                    i++;
                    sleep(100);
                    out.println("sleep time index:" + i);
                } catch (Exception e) {
                    out.println(e);
                }
            }
           

是否初看代碼覺得邏輯很清晰呢,隻是簡簡單單捕獲了一下所有異常,能出多少事呢,或者這麼簡單的代碼有什麼有問題很好定位的,可是當我們在實際開發中,把異常捕獲裡面的子產品換成十幾個方法,幾千行代碼,或許問題就沒那麼好定位了,也不會簡簡單單覺得就是幾行代碼的問題。代碼中包含的錯誤可能,真的很難發現,假如日志加的不全,甚至影響到整個互動系統。甚至你的ctrl+c、ctrl+d都搞不定,隻有重新開機或者殺死程序,然後選擇軟體重新開始,可是這樣真的好嗎?

2 回溯1:為什麼ctrl+c、ctrl+d搞不定?

2.1 ctrl+c、ctrl+d、ctrl+d是什麼?

Ctrl+c和ctrl+z都是中斷指令,但是他們的作用卻不一樣.

  • Ctrl+c是強制中斷程式的執行。發送 SIGINT 信号給前台程序組中的所有程序,強制終止程式的執行;

    在java運作過程中,例如上面例子的指令行執行,鍵盤上敲入ctrl+c,實際上是給控制台觸發了java.lang.InterruptedException的異常,但是不好意思被捕獲到了,然後繼續循環,是以使用者退不出去,隻能選擇繼續執行。

  • Ctrl+d :一個特殊的二進制值,表示 EOF,作用相當于在終端中輸入exit後回車;

    上述代碼的程式,敲入ctrl+d,你的控制台的其他線程大概能退出來了,但是這個你死循環的代碼,并沒有退出,如果同樣的代碼關系到多個io,這些線程相當于你都搞不定了,因為你無法控制回收。

  • Ctrl+z發送 SIGTSTP 信号給前台程序組中的所有程序,常用于挂起一個程序,而并非結束程序,使用者可以使用使用fg/bg操作恢複執行前台或背景的程序。fg指令在前台恢複執行被挂起的程序,此時可以使用ctrl-z再次挂起該程序,bg指令在背景恢複執行被挂起的程序,而此時将無法使用ctrl-z再次挂起該程序;可以将一個正在前台執行的指令放到背景,并且處于暫停狀态,不可執行;
    為了進一步弄清楚程序是否退出,打開了jvisualvm jdk線程分析工具,進一步了解,發現上述這個代碼,讓ctrl+c,ctrl+d同時失效,隻是ctrl+z雖然能退出繼續操作控制台,但是想要重新去掉這個已知死循環的線程,也隻能作業系統級别的使用程序指令殺死程序重新開始,簡而言之,jdk級别這個線程我們已經無法掌握。
    ​ 正常界面

[外鍊圖檔轉存失敗,源站可能有防盜鍊機制,建議将圖檔儲存下來直接上傳(img-wjAuWnLP-1570753425455)(/home/fwd/os/01-log/1024-承載網指令行問題分析/pic/01-正常.png)]

​ ctrl+d後程序顯示

[外鍊圖檔轉存失敗,源站可能有防盜鍊機制,建議将圖檔儲存下來直接上傳(img-H7cyEe7r-1570753425457)(/home/fwd/os/01-log/1024-承載網指令行問題分析/pic/ctrl_d.png)]

​ ctrl+z後程序顯示

[外鍊圖檔轉存失敗,源站可能有防盜鍊機制,建議将圖檔儲存下來直接上傳(img-sz31U5yZ-1570753425458)(/home/fwd/os/01-log/1024-承載網指令行問題分析/pic/01-ctrl_z.png)]

3 回溯2:java 異常你真的會用嗎?

java異常捕獲機制,從接觸io後,初使用它的一刻,真的發現了相對于c語言獨特的魅力,捕獲一個異常,然後做出相應的處理,比起c語言裡面因為異常簡單的程序就崩掉确實提供了太多的友善, 系統的穩定性得到了大幅提升。但是也正是因為這個機制的存在,有些程式猿開始犯起了懶:

  • 使用異常去控制正常的流程:

如果你的功能是正常的流程,隻是不想非空判斷去捕捉空指針異常,這時機不是一個好的選擇,這些事情if else就能搞定,使用異常捕獲機制太大才小用了,而且影響效率;

  • 不分異常,盲目使用捕捉所有異常:

這是初級程式猿經常犯的一個錯,因為他們不了解異常,不知道jdk通常有哪些異常,然後又為了保證穩定性,保證自己的代碼不受到任何幹擾,所有簡單的一個catch Excetpion ,捕獲所有異常,看似沒有問題,空指針也捕獲了,io錯誤也捕獲,看似最優,但是實際上也堵死了自己能選擇的退出的路,例如上面的問題。

4 回溯3:我們的設計?

我們的設計帶來哪些感悟呢,我覺得問題雖小,但是作為一個剛剛邁過初級的程式小丁,我覺得确實有很深的驚醒意味,我們能做的事情還有更多:

  1. 程式設計規範:大部分程式設計規範大概都強調過異常的捕獲,不要試圖捕獲所有,一定要在一開始就貫徹執行。
  2. 完善的異常機制設計:我們在設計一個項目的時候,其實一開始除了正常的功能分析和拆解,也更應該留一個點精力給異常,想清楚會存在哪些異常:
    • 哪些是需要程式if else判斷去避免的?
    • 哪些什麼類型是需要我們統一捕獲去做一些糾正處理的?
    • 哪些異常無法描述,我們自己建構異常類,抛出相應異常,在一個統一子產品位置去處理?
    • 如果涉及到上下層互動,你的異常是否需要統一的錯誤碼?讓你的調用者或者使用者能及時感覺異常?
    有了這些思考,一個系統才能有更好的人機互動性和穩定性,這是我們在設計支出絕對要花時間去考慮。
    正常功能分析、擴充性、異常功能分析,這三點任何項目都要在設計的時候就想清楚,不給自己留隐患,系統的思維分析這些問題;

5. 學習之路?

我們平時認為簡單的東西,實際上是不簡單的,例如文字裡面提到的ctrl+c,我們真的懂他的内部原理嗎?懂他與jdk 運作空間的互動嗎?對于大部分看中當下未深入研究的人,可能未必?但是它卻真正影響了我們代碼。簡單的東西實際上不簡單?能從簡單的事情裡面去學習,也能收貨許多隐藏其後的心血。

還有一個點就是,設計通常是一個從簡單到複雜,再從複雜到簡單的過程,其實最後大道至簡,一個好的産品呈現在我們面前的時候肯定是簡單易用的?但是簡單的背後是什麼?更值得我們學習!

大道至簡,簡單背後的不簡單,更值得我們去反思,那個從簡單到複雜再回歸簡單的過程,正是進步的源泉!

繼續閱讀