<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    posts - 38, comments - 2, trackbacks - 0, articles - 0
      BlogJava :: 首頁 :: 新隨筆 :: 聯系 :: 聚合  :: 管理

    你覺得自己是一個Java專家嗎?是否肯定自己已經全面掌握了Java的異常處理機制?在下面這段代碼中,你能夠迅速找出異常處理的六個問題嗎? 

    1 OutputStreamWriter out = ... 
    2 java.sql.Connection conn = ... 
    3 try { // ⑸ 
    4  Statement stat = conn.createStatement(); 
    5  ResultSet rs = stat.executeQuery( 
    6   "select uid, name from user"); 
    7  while (rs.next()) 
    8  { 
    9   out.println("ID:" + rs.getString("uid") // ⑹ 
    10    ",姓名:" + rs.getString("name")); 
    11  } 
    12  conn.close(); // ⑶ 
    13  out.close(); 
    14 } 
    15 catch(Exception ex) // ⑵ 
    16 { 
    17  ex.printStackTrace(); //⑴,⑷ 
    18 }


      作為一個Java程序員,你至少應該能夠找出兩個問題。但是,如果你不能找出全部六個問題,請繼續閱讀本文。 

    本文討論的不是Java異常處理的一般性原則,因為這些原則已經被大多數人熟知。我們要做的是分析各種可稱為“反例”(anti-pattern)的違背優秀編碼規范的常見壞習慣,幫助讀者熟悉這些典型的反面例子,從而能夠在實際工作中敏銳地察覺和避免這些問題。 

    反例之一:丟棄異常 

    代碼:15行-18行。 

    這段代碼捕獲了異常卻不作任何處理,可以算得上Java編程中的殺手。從問題出現的頻繁程度和禍害程度來看,它也許可以和C/C++程序的一個惡名遠播的問題相提并論??不檢查緩沖區是否已滿。如果你看到了這種丟棄(而不是拋出)異常的情況,可以百分之九十九地肯定代碼存在問題(在極少數情況下,這段代碼有存在的理由,但最好加上完整的注釋,以免引起別人誤解)。 

    這段代碼的錯誤在于,異常(幾乎)總是意味著某些事情不對勁了,或者說至少發生了某些不尋常的事情,我們不應該對程序發出的求救信號保持沉默和無動于衷。調用一下printStackTrace算不上“處理異常”。不錯,調用printStackTrace對調試程序有幫助,但程序調試階段結束之后,printStackTrace就不應再在異常處理模塊中擔負主要責任了。 

    丟棄異常的情形非常普遍。打開JDK的ThreadDeath類的文檔,可以看到下面這段說明:“特別地,雖然出現ThreadDeath是一種‘正常的情形’,但ThreadDeath類是Error而不是Exception的子類,因為許多應用會捕獲所有的Exception然后丟棄它不再理睬。”這段話的意思是,雖然ThreadDeath代表的是一種普通的問題,但鑒于許多應用會試圖捕獲所有異常然后不予以適當的處理,所以JDK把ThreadDeath定義成了Error的子類,因為Error類代表的是一般的應用不應該去捕獲的嚴重問題。可見,丟棄異常這一壞習慣是如此常見,它甚至已經影響到了Java本身的設計。 

    那么,應該怎樣改正呢?主要有四個選擇: 

    1、處理異常。針對該異常采取一些行動,例如修正問題、提醒某個人或進行其他一些處理,要根據具體的情形確定應該采取的動作。再次說明,調用printStackTrace算不上已經“處理好了異常”。 

    2、重新拋出異常。處理異常的代碼在分析異常之后,認為自己不能處理它,重新拋出異常也不失為一種選擇。 

    3、把該異常轉換成另一種異常。大多數情況下,這是指把一個低級的異常轉換成應用級的異常(其含義更容易被用戶了解的異常)。 

    4、不要捕獲異常。 

    結論一:既然捕獲了異常,就要對它進行適當的處理。不要捕獲異常之后又把它丟棄,不予理睬。 

    反例之二:不指定具體的異常 

    代碼:15行。 

    許多時候人們會被這樣一種“美妙的”想法吸引:用一個catch語句捕獲所有的異常。最常見的情形就是使用catch(Exception ex)語句。但實際上,在絕大多數情況下,這種做法不值得提倡。為什么呢? 

    要理解其原因,我們必須回顧一下catch語句的用途。catch語句表示我們預期會出現某種異常,而且希望能夠處理該異常。異常類的作用就是告訴Java編譯器我們想要處理的是哪一種異常。由于絕大多數異常都直接或間接從java.lang.Exception派生,catch(Exception ex)就相當于說我們想要處理幾乎所有的異常。 

    再來看看前面的代碼例子。我們真正想要捕獲的異常是什么呢?最明顯的一個是SQLException,這是JDBC操作中常見的異常。另一個可能的異常是IOException,因為它要操作OutputStreamWriter。顯然,在同一個catch塊中處理這兩種截然不同的異常是不合適的。如果用兩個catch塊分別捕獲SQLException和IOException就要好多了。這就是說,catch語句應當盡量指定具體的異常類型,而不應該指定涵蓋范圍太廣的Exception類。 

    另一方面,除了這兩個特定的異常,還有其他許多異常也可能出現。例如,如果由于某種原因,executeQuery返回了null,該怎么辦?答案是讓它們繼續拋出,即不必捕獲也不必處理。實際上,我們不能也不應該去捕獲可能出現的所有異常,程序的其他地方還有捕獲異常的機會??直至最后由JVM處理。 

    結論二:在catch語句中盡可能指定具體的異常類型,必要時使用多個catch。不要試圖處理所有可能出現的異常。 

    反例之三:占用資源不釋放 

    代碼:3行-14行。 

    異常改變了程序正常的執行流程。這個道理雖然簡單,卻常常被人們忽視。如果程序用到了文件、Socket、JDBC連接之類的資源,即使遇到了異常,也要正確釋放占用的資源。為此,Java提供了一個簡化這類操作的關鍵詞finally。 

    finally是樣好東西:不管是否出現了異常,Finally保證在try/catch/finally塊結束之前,執行清理任務的代碼總是有機會執行。遺憾的是有些人卻不習慣使用finally。 

    當然,編寫finally塊應當多加小心,特別是要注意在finally塊之內拋出的異常??這是執行清理任務的最后機會,盡量不要再有難以處理的錯誤。 

    結論三:保證所有資源都被正確釋放。充分運用finally關鍵詞。

    反例之四:不說明異常的詳細信息 

      代碼:3行-18行。 

    仔細觀察這段代碼:如果循環內部出現了異常,會發生什么事情?我們可以得到足夠的信息判斷循環內部出錯的原因嗎?不能。我們只能知道當前正在處理的類發生了某種錯誤,但卻不能獲得任何信息判斷導致當前錯誤的原因。 

    printStackTrace的堆棧跟蹤功能顯示出程序運行到當前類的執行流程,但只提供了一些最基本的信息,未能說明實際導致錯誤的原因,同時也不易解讀。 

    因此,在出現異常時,最好能夠提供一些文字信息,例如當前正在執行的類、方法和其他狀態信息,包括以一種更適合閱讀的方式整理和組織printStackTrace提供的信息。 

    結論四:在異常處理模塊中提供適量的錯誤原因信息,組織錯誤信息使其易于理解和閱讀。 

    反例之五:過于龐大的try塊 

    代碼:3行-14行。 

    經常可以看到有人把大量的代碼放入單個try塊,實際上這不是好習慣。這種現象之所以常見,原因就在于有些人圖省事,不愿花時間分析一大塊代碼中哪幾行代碼會拋出異常、異常的具體類型是什么。把大量的語句裝入單個巨大的try塊就象是出門旅游時把所有日常用品塞入一個大箱子,雖然東西是帶上了,但要找出來可不容易。 

    一些新手常常把大量的代碼放入單個try塊,然后再在catch語句中聲明Exception,而不是分離各個可能出現異常的段落并分別捕獲其異常。這種做法為分析程序拋出異常的原因帶來了困難,因為一大段代碼中有太多的地方可能拋出Exception。 

    結論五:盡量減小try塊的體積。 

    反例之六:輸出數據不完整 

    代碼:7行-11行。 

    不完整的數據是Java程序的隱形殺手。仔細觀察這段代碼,考慮一下如果循環的中間拋出了異常,會發生什么事情。循環的執行當然是要被打斷的,其次,catch塊會執行??就這些,再也沒有其他動作了。已經輸出的數據怎么辦?使用這些數據的人或設備將收到一份不完整的(因而也是錯誤的)數據,卻得不到任何有關這份數據是否完整的提示。對于有些系統來說,數據不完整可能比系統停止運行帶來更大的損失。 

    較為理想的處置辦法是向輸出設備寫一些信息,聲明數據的不完整性;另一種可能有效的辦法是,先緩沖要輸出的數據,準備好全部數據之后再一次性輸出。 

    結論六:全面考慮可能出現的異常以及這些異常對執行流程的影響。 

    改寫后的代碼 

    根據上面的討論,下面給出改寫后的代碼。也許有人會說它稍微有點?嗦,但是它有了比較完備的異常處理機制。 

    OutputStreamWriter out = ... 
    java.sql.Connection conn = ... 
    try { 
    Statement stat = conn.createStatement(); 
    ResultSet rs = stat.executeQuery( 
    "select uid, name from user"); 
    while (rs.next()) 

    out.println("ID:" + rs.getString("uid") + ",姓名: " + rs.getString("name")); 


    catch(SQLException sqlex) 

    out.println("警告:數據不完整"); 
    throw new ApplicationException("讀取數據時出現SQL錯誤", sqlex); 

    catch(IOException ioex) 

    throw new ApplicationException("寫入數據時出現IO錯誤", ioex); 

    finally 

    if (conn != null) { 
    try { 
    conn.close(); 

    catch(SQLException sqlex2) 

    System.err(this.getClass().getName() + ".mymethod - 不能關閉數據庫連接: " + sqlex2.toString()); 



    if (out != null) { 
    try { 
    out.close(); 

    catch(IOException ioex2) 

    System.err(this.getClass().getName() + ".mymethod - 不能關閉輸出文件" + ioex2.toString()); 


    }

      本文的結論不是放之四海皆準的教條,有時常識和經驗才是最好的老師。如果你對自己的做法沒有百分之百的信心,務必加上詳細、全面的注釋。 

    另一方面,不要笑話這些錯誤,不妨問問你自己是否真地徹底擺脫了這些壞習慣。即使最有經驗的程序員偶爾也會誤入歧途,原因很簡單,因為它們確確實實帶來了“方便”。所有這些反例都可以看作Java編程世界的惡魔,它們美麗動人,無孔不入,時刻誘惑著你。也許有人會認為這些都屬于雞皮蒜毛的小事,不足掛齒,但請記住:勿以惡小而為之,勿以善小而不為。






    ------------------------------------------------------------------下面是一些java異常集-------------------------------------------------------------------------------------------

    算術異常類:ArithmeticExecption

    空指針異常類:NullPointerException

    類型強制轉換異常:ClassCastException

    數組負下標異常:NegativeArrayException

    數組下標越界異常:ArrayIndexOutOfBoundsException

    違背安全原則異常:SecturityException

    文件已結束異常:EOFException

    文件未找到異常:FileNotFoundException

    字符串轉換為數字異常:NumberFormatException


    操作數據庫異常:SQLException


    輸入輸出異常:IOException


    方法未找到異常:NoSuchMethodException

    java.lang.AbstractMethodError

    抽象方法錯誤。當應用試圖調用抽象方法時拋出。

    java.lang.AssertionError

    斷言錯。用來指示一個斷言失敗的情況。

    java.lang.ClassCircularityError

    類循環依賴錯誤。在初始化一個類時,若檢測到類之間循環依賴則拋出該異常。

    java.lang.ClassFormatError

    類格式錯誤。當Java虛擬機試圖從一個文件中讀取Java類,而檢測到該文件的內容不符合類的有效格式時拋出。

    java.lang.Error

    錯誤。是所有錯誤的基類,用于標識嚴重的程序運行問題。這些問題通常描述一些不應被應用程序捕獲的反常情況。

    java.lang.ExceptionInInitializerError

    初始化程序錯誤。當執行一個類的靜態初始化程序的過程中,發生了異常時拋出。靜態初始化程序是指直接包含于類中的static語句段。

    java.lang.IllegalAccessError

    違法訪問錯誤。當一個應用試圖訪問、修改某個類的域(Field)或者調用其方法,但是又違反域或方法的可見性聲明,則拋出該異常。

    java.lang.IncompatibleClassChangeError

    不兼容的類變化錯誤。當正在執行的方法所依賴的類定義發生了不兼容的改變時,拋出該異常。一般在修改了應用中的某些類的聲明定義而沒有對整個應用重新編譯而直接運行的情況下,容易引發該錯誤。

    java.lang.InstantiationError

    實例化錯誤。當一個應用試圖通過Java的new操作符構造一個抽象類或者接口時拋出該異常.

    java.lang.InternalError

    內部錯誤。用于指示Java虛擬機發生了內部錯誤。

    java.lang.LinkageError

    鏈接錯誤。該錯誤及其所有子類指示某個類依賴于另外一些類,在該類編譯之后,被依賴的類改變了其類定義而沒有重新編譯所有的類,進而引發錯誤的情況。

    java.lang.NoClassDefFoundError

    未找到類定義錯誤。當Java虛擬機或者類裝載器試圖實例化某個類,而找不到該類的定義時拋出該錯誤。

    java.lang.NoSuchFieldError

    域不存在錯誤。當應用試圖訪問或者修改某類的某個域,而該類的定義中沒有該域的定義時拋出該錯誤。

    java.lang.NoSuchMethodError

    方法不存在錯誤。當應用試圖調用某類的某個方法,而該類的定義中沒有該方法的定義時拋出該錯誤。

    java.lang.OutOfMemoryError

    內存不足錯誤。當可用內存不足以讓Java虛擬機分配給一個對象時拋出該錯誤。

    java.lang.StackOverflowError

    堆棧溢出錯誤。當一個應用遞歸調用的層次太深而導致堆棧溢出時拋出該錯誤。

    java.lang.ThreadDeath

    線程結束。當調用Thread類的stop方法時拋出該錯誤,用于指示線程結束。

    java.lang.UnknownError

    未知錯誤。用于指示Java虛擬機發生了未知嚴重錯誤的情況。

    java.lang.UnsatisfiedLinkError

    未滿足的鏈接錯誤。當Java虛擬機未找到某個類的聲明為native方法的本機語言定義時拋出。

    java.lang.UnsupportedClassVersionError

    不支持的類版本錯誤。當Java虛擬機試圖從讀取某個類文件,但是發現該文件的主、次版本號不被當前Java虛擬機支持的時候,拋出該錯誤。

    java.lang.VerifyError

    驗證錯誤。當驗證器檢測到某個類文件中存在內部不兼容或者安全問題時拋出該錯誤。

    java.lang.VirtualMachineError

    虛擬機錯誤。用于指示虛擬機被破壞或者繼續執行操作所需的資源不足的情況。


    java.lang.ArithmeticException

    算術條件異常。譬如:整數除零等。

    java.lang.ArrayIndexOutOfBoundsException

    數組索引越界異常。當對數組的索引值為負數或大于等于數組大小時拋出。

    java.lang.ArrayStoreException

    數組存儲異常。當向數組中存放非數組聲明類型對象時拋出。

    java.lang.ClassCastException

    類造型異常。假設有類A和B(A不是B的父類或子類),O是A的實例,那么當強制將O構造為類B的實例時拋出該異常。該異常經常被稱為強制類型轉換異常。

    java.lang.ClassNotFoundException

    找不到類異常。當應用試圖根據字符串形式的類名構造類,而在遍歷CLASSPAH之后找不到對應名稱的class文件時,拋出該異常。

    java.lang.CloneNotSupportedException

    不支持克隆異常。當沒有實現Cloneable接口或者不支持克隆方法時,調用其clone()方法則拋出該異常。

    java.lang.EnumConstantNotPresentException

    枚舉常量不存在異常。當應用試圖通過名稱和枚舉類型訪問一個枚舉對象,但該枚舉對象并不包含常量時,拋出該異常。

    java.lang.Exception

    根異常。用以描述應用程序希望捕獲的情況。

    java.lang.IllegalAccessException

    違法的訪問異常。當應用試圖通過反射方式創建某個類的實例、訪問該類屬性、調用該類方法,而當時又無法訪問類的、屬性的、方法的或構造方法的定義時拋出該異常。

    java.lang.IllegalMonitorStateException

    違法的監控狀態異常。當某個線程試圖等待一個自己并不擁有的對象(O)的監控器或者通知其他線程等待該對象(O)的監控器時,拋出該異常。

    java.lang.IllegalStateException

    違法的狀態異常。當在Java環境和應用尚未處于某個方法的合法調用狀態,而調用了該方法時,拋出該異常。

    java.lang.IllegalThreadStateException

    違法的線程狀態異常。當縣城尚未處于某個方法的合法調用狀態,而調用了該方法時,拋出異常。

    java.lang.IndexOutOfBoundsException

    索引越界異常。當訪問某個序列的索引值小于0或大于等于序列大小時,拋出該異常。

    java.lang.InstantiationException

    實例化異常。當試圖通過newInstance()方法創建某個類的實例,而該類是一個抽象類或接口時,拋出該異常。

    java.lang.InterruptedException

    被中止異常。當某個線程處于長時間的等待、休眠或其他暫停狀態,而此時其他的線程通過Thread的interrupt方法終止該線程時拋出該異常。

    java.lang.NegativeArraySizeException

    數組大小為負值異常。當使用負數大小值創建數組時拋出該異常。

    java.lang.NoSuchFieldException

    屬性不存在異常。當訪問某個類的不存在的屬性時拋出該異常。

    java.lang.NoSuchMethodException

    方法不存在異常。當訪問某個類的不存在的方法時拋出該異常。

    java.lang.NullPointerException

    空指針異常。當應用試圖在要求使用對象的地方使用了null時,拋出該異常。譬如:調用null對象的實例方法、訪問null對象的屬性、計算null對象的長度、使用throw語句拋出null等等。

    java.lang.NumberFormatException

    數字格式異常。當試圖將一個String轉換為指定的數字類型,而該字符串確不滿足數字類型要求的格式時,拋出該異常。

    java.lang.RuntimeException

    運行時異常。是所有Java虛擬機正常操作期間可以被拋出的異常的父類。

    java.lang.SecurityException

    安全異常。由安全管理器拋出,用于指示違反安全情況的異常。

    java.lang.StringIndexOutOfBoundsException

    字符串索引越界異常。當使用索引值訪問某個字符串中的字符,而該索引值小于0或大于等于序列大小時,拋出該異常。

    java.lang.TypeNotPresentException

    類型不存在異常。當應用試圖以某個類型名稱的字符串表達方式訪問該類型,但是根據給定的名稱又找不到該類型是拋出該異常。該異常與ClassNotFoundException的區別在于該異常是unchecked(不被檢查)異常,而ClassNotFoundException是checked(被檢查)異常。

    java.lang.UnsupportedOperationException

    不支持的方法異常。指明請求的方法不被支持情況的異常。

    異常
    javax.servlet.jsp.JspException: Cannot retrieve mapping for action /Login (/Login是你的action名字)  

    可能原因
    action沒有再struts-config.xml 中定義,或沒有找到匹配的action,例如在JSP文件中使用 <html:form action="Login.do".將表單提交給Login.do處理,如果出現上述異常,請查看struts-config.xml中的定義部分,有時可能是打錯了字符或者是某些不符合規則,可以使用strutsconsole工具來檢查。
    -----------------------------------------------------------------------------------------------------------------
    異常
    org.apache.jasper.JasperException: Cannot retrieve definition for form bean null

    可能原因      
           
    這個異常是因為Struts根據struts-config.xml中的mapping沒有找到action期望的form bean。大部分的情況可能是因為在form-bean中設置的name屬性和action中設置的name屬性不匹配所致。換句話說,action和form都應該各自有一個name屬性,并且要精確匹配,包括大小寫。這個錯誤當沒有name屬性和action關聯時也會發生,如果沒有在action中指定name屬性,那么就沒有name屬性和action相關聯。當然當action制作某些控制時,譬如根據參數值跳轉到相應的jsp頁面,而不是處理表單數據,這是就不用name屬性,這也是action的使用方法之一。
    -----------------------------------------------------------------------------------------------------------------
    異常
    No action instance for path /xxxx could be created

    可能原因
    特別提示:因為有很多中情況會導致這個錯誤的發生,所以推薦大家調高你的web服務器的日志/調試級別,這樣可以從更多的信息中看到潛在的、在試圖創建action類時發生的錯誤,這個action類你已經在struts-config.xml中設置了關聯(即添加了<action>標簽)。

    在struts-config.xml中通過action標簽的class屬性指定的action類不能被找到有很多種原因,例如:定位編譯后的.class文件失敗。Failure to place compiled .class file for the action in the classpath (在web開發中,class的的位置在r WEB-INF/classes,所以你的action class必須要在這個目錄下。例如你的action類位于WEB-INF/classes/action/Login.class,那么在struts-config.xml中設置action的屬性type時就是action.Login).
    拼寫錯誤,這個也時有發生,并且不易找到,特別注意第一個字母的大小寫和包的名稱。 
    -----------------------------------------------------------------------------------------------------------------
    異常
    javax.servlet.jsp.JspException: No getter method for property username of bean org.apache.struts.taglib.html.BEAN

    可能原因
    沒有位form bean中的某個變量定義getter 方法

    這個錯誤主要發生在表單提交的FormBean中,用struts標記<html:text property=”username”>時,在FormBean中必須有一個getUsername()方法。注意字母“U”。
    -----------------------------------------------------------------------------------------------------------------
    異常
    java.lang.NoClassDefFoundError: org/apache/struts/action/ActionForm

    可能原因
    這個錯誤主要發生在在classpath中找不到相應的Java .class文件。如果這個錯誤發生在web應用程序的運行時,主要是因為指定的class文件不在web server的classpath中(/WEB-INF/classes 和 /WEB-INF/lib)。在上面的錯誤中,原因是找不到ActionForm類。
    -----------------------------------------------------------------------------------------------------------------
    異常
    javax.servlet.jsp.JspException: Exception creating bean of class org.apache.struts.action.ActionForm: {1}

    可能原因
    Instantiating Struts-provided ActionForm class directly instead of instantiating a class derived off ActionForm. This mightoccur implicitly if you specify that a form-bean is this Struts ActionForm class rather than specifying a child of this classfor the form-bean.

    Not associating an ActionForm-descended class with an action can also lead to this error.
    -----------------------------------------------------------------------------------------------------------------
    異常
    javax.servlet.jsp.JspException: Cannot find ActionMappings or ActionFormBeans collection

    可能原因
    不是標識Struts actionServlet的<servlet>標記就是映射.do擴展名的<sevlet-mapping>標記或者兩者都沒有在web.xml中聲明。

    在struts-config.xml中的打字或者拼寫錯誤也可導致這個異常的發生。例如缺少一個標記的關閉符號/>。最好使用struts console工具檢查一下。

    另外,load-on-startup必須在web.xml中聲明,這要么是一個空標記,要么指定一個數值,這個數值用來表servlet運行的優先級,數值越大優先級越低。

    還有一個和使用load-on-startup有關的是使用Struts預編譯JSP文件時也可能導致這個異常。
    -----------------------------------------------------------------------------------------------------------------
    異常
    java.lang.NullPointerException at org.apache.struts.util.RequestUtils.forwardURL(RequestUtils.java:1223)

    可能原因
    在struts-config.xml中的forward元素缺少path屬性。例如應該是如下形式:
    <forward name="userhome" path="/user/userhome.jsp"/>
    -----------------------------------------------------------------------------------------------------------------
    異常
    javax.servlet.jsp.JspException: Cannot find bean org.apache.struts.taglib.html.BEAN in any scope

    Probable Causes
    試圖在Struts的form標記外使用form的子元素。這常常發生在你在</html:form>后面使用Struts的html標記。另外要注意可能你不經意使用的無主體的標記,如<html:form … />,這樣web 服務器解析時就當作一個無主體的標記,隨后使用的所有<html>標記都被認為是在這個標記之外的,如又使用了<html:text property=”id”>還有就是在使用taglib引入HTML標記庫時,你使用的prefix的值不是html。
    -----------------------------------------------------------------------------------------------------------------
    異常
    javax.servlet.jsp.JspException: Missing message for key xx.xx.xx

    Probable Causes
    這個key的值對沒有在資源文件ApplicationResources.properties中定義。如果你使用eclipse時經常碰到這樣的情況,當項目重新編譯時,eclipse會自動將classes目錄下的資源文件刪除。

    資源文件ApplicationResources.properties 不在classpath中應將資源文件放到 WEB-INF/classes 目錄下,當然要在struts-config.xml中定義)
    -----------------------------------------------------------------------------------------------------------------
    異常
    Cannot find message resources under key org.apache.struts.action.MESSAGE

    可能原因
    很顯然,這個錯誤是發生在使用資源文件時,而Struts沒有找到資源文件。

    Implicitly trying to use message resources that are not available (such as using empty html:options tag instead of specifyingthe options in its body -- this assumes options are specified in ApplicationResources.properties file)

    XML parser issues -- too many, too few, incorrect/incompatible versions
    -----------------------------------------------------------------------------------------------------------------
    異常
    Strange and seemingly random characters in HTML and on screen, but not in original JSP or servlet.

    可能原因
    混和使用Struts的html:form標記和標準的HTML標記不正確。

    使用的編碼樣式在本頁中不支持。
    -----------------------------------------------------------------------------------------------------------------
    異常
    "Document contained no data" in Netscape

    No data rendered (completely empty) page in Microsoft Internet Explorer

    可能原因
    使用一個Action的派生類而沒有實現perform()方法或execute()方法。在Struts1.0中實現的是perform()方法,在Struts1.1中實現的是execute()方法,但Struts1.1向后兼容perform()方法。但你使用Struts1.1創建一個Action的派生類,并且實現了execute()方法,而你在Struts1.0中運行的話,就會得到"Document contained nodata" error message in Netscape or a completely empty (no HTML whatsoever) page rendered in Microsoft Internet Explorer.”的錯誤信息。

    ---------------------------------------------------------------------------------------------------------------------------
    異常
    ServletException: BeanUtils.populate
    解決方案
    在用Struts上傳文件時,遇到了javax.servlet.ServletException: BeanUtils.populate異常。
    我的ActionServlet并沒有用到BeanUtils這些工具類。后來仔細檢查代碼發現是在jsp文件里的form忘了加enctype=&quot;multipart/form-data&quot; 了。所以寫程序遇到錯誤或異常應該從多方面考慮問題存在的可能性,想到系統提示信息以外的東西。
    ----------------------------------------------------------------------------------------------------------------------------
    1. 定義Action后, 如果指定了name, 那么必須要定義一個與它同名的FormBean才能進行form映射.2. 如果定義Action后, 提交頁面時出現 "No input attribute for mapping path..." 錯誤, 則需要在其input屬性中定義轉向的頁面.3. 如果插入新的數據時出現 "Batch update row count wrong:..." 錯誤, 則說明XXX.hbm.xml中指定的key的類型為原始類型(int, long),因為這種類型會自動分配值, 而這個值往往會讓系統認為已經存在該記錄, 正確的方法是使用java.lang.Integer或java.lang.Long對象.4. 如果插入數據時出現 "argument type mismatch" 錯誤, 可能是你使用了Date等特殊對象, 因為struts不能自動從String型轉換成Date型,所以, 你需要在Action中手動把String型轉換成Date型.5. Hibernate中, Query的iterator()比list()方法快很多.6. 如果出現 "equal symbol expected" 錯誤, 說明你的strtus標簽中包含另一個標簽或者變量, 例如:
    <html:select property="test" onchange="<%=test%>"/>
    或者
    <html:hidden property="test" value="<bean:write name="t" property="p"/>"/>
    這樣的情況... 
    ---------------------------------------------------------------------------------------------------------------------------
    錯誤:Exception in thread "main" org.hibernate.exception.SQLGrammarException: Could not execute JDBC batch update原因與解決:      因為Hibernate Tools(或者Eclipse本身的Database Explorer)生成*.hbn.xml工具中包含有catalog="***"(*表示數據庫名稱)這樣的屬性,將該屬性刪除就可以了
    ---------------------------------------------------------------------------------------------------------------------------
    錯誤:org.hibernate.ObjectDeletedException: deleted object would be re-saved by cascade (remove deleted object from associations)
    原因與解決:
    方法1 刪除Set方的cascade
    方法2 解決關聯關系后,再刪除
    方法3 在many-to-one方增加cascade 但值不能是none
    最后一招:
    檢查一下hashCode equals是否使用了id作為唯一標示的選項了;我用uuid.hex時是沒有問題的;但是用了native,就不行了,怎么辦?刪除啊!
    ----------------------------------------------------------------------------------------------------------------------------
    問題:今天用Tomcat 5.5.12,發現原來很好用的系統不能用了,反復測試發現頁面中不能包含 taglib,否則會出現以下提示:HTTP Status 500 -type Exception reportMessage description The server encountered an internal error () that prevented it from fulfilling this request.exceptionorg.apache.jasper.JasperException: /index.jsp(1,1) Unable to read TLD "META-INF/tlds/struts-bean.tld" from JAR file"file:*****/WEB-INF/lib/struts.jar":原因:更新了工程用的lib文件夾下的jar,發布時也發布了servlet.jar和jsp-api.jar。解決:把jsp-api.jar刪除就解決這個問題了。-----------------------------------------------------------------------------------------------------------------------------
    錯誤: java.lang.NullPointerException
    原因: 發現 dao 實例、 manage 實例等需要注入的東西沒有被注入(俗稱空指針異常)解決:這個時候,你應該查看日志文件;默認是應用服務器的 log 文件,比如 Tomcat 就是 [Tomcat 安裝目錄 ]/logs ;你會發現提示你:可能是:org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'sf' defined in ServletContextresource [/WEB-INF/applicationContext.xml]: Initialization of bean failed; nested exception isorg.hibernate.HibernateException: could not configure from URL: file:src/hibernate.cfg.xmlorg.hibernate.HibernateException: could not configure from URL: file:src/hibernate.cfg.xml……………………….Caused by: java.io.FileNotFoundException: src\hibernate.cfg.xml可能是:org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'sessionFactory' defined inServletContext resource [/WEB-INF/applicationContext.xml]: Initialization of bean failed; nested exception isorg.hibernate.MappingException: Resource: com/mcc/coupon/model/UserRole.hbm.xml not foundorg.hibernate.MappingException: Resource: com/mcc/coupon/model/UserRole.hbm.xml not found然后你就知道原因是因為配置文件的解析出了錯誤,這個通過 Web 頁面是看不出來的。更多的是持久化影射文件出的錯誤;導致了沒有被解析;當然你需要的功能就無法使用了。
    ----------------------------------------------------------------------------------------------------------------------------
    錯誤:StandardWrapperValve[action]: Servlet.service() for servlet action threw exception
    javax.servlet.jsp.JspException: Cannot retrieve mapping for action /settlementTypeManage
    或者:      type Status report      message Servlet action is not available      description The requested resource (Servlet action is not available) is not available.
    原因: 同 上
    ----------------------------------------------------------------------------------------------------------------------------
    錯誤StandardWrapperValve[jsp]: Servlet.service() for servlet jsp threw exceptionjava.lang.ClassNotFoundException: org.apache.struts.taglib.bean.CookieTei界面錯誤具體描述:
    org.apache.jasper.JasperException: Failed to load or instantiate TagExtraInfo class: org.apache.struts.taglib.bean.CookieTei
          原因與解決:    <方案一>你的“html:”開頭的標簽沒有放在一個<html:form>中       <方案二>重新啟動你的應用服務器,自動就沒有這個問題

    posted @ 2009-08-10 10:32 AntiquMan 閱讀(448) | 評論 (1)編輯 收藏

         1.JDK.這個不必說(我的是1.6.0_03)
    2.改變安裝文件權限。在終端中用cd命令把當前目錄轉移到jdk-6u3--i586-rpm.bin所在目錄,用ls -l命令查看文件權限,如果是可執行x(eXecute)則不需要更改,否則用命令 chmod 755 jdk-6u3--i586-rpm.bin,使自解壓包文件可執行
    3.安裝。在終端輸入。/jdk-6u3-Linux-i586-rpm.bin,按提示一步步執行即可。
    4.更改環境變量。剛才安裝的版本默認在/usr/Java/jdk1.6.0_03,我們把它加到環境變量。用cd命令轉移到etc目錄,輸入gedit profile,在profile在后三行
    #
    # End of /etc/profile
    #
    上面添加如下文本:
    export JAVA_HOME=/usr/java/jdk1.6.0_03
    export CLASSPATH=.:$JAVA_HOME/jre/lib:$JAVA_HOME/lib/tools.jar
    export JRE_HOME=$JAVA_HOME/jre
    5.重新啟動系統,在終端輸入java -version,顯示內容:
    java version "1.6.0_03"
    (TM) SE Runtime Environment (build 1.6.0_03-b05)
    HotSpot(TM) Client VM (build 1.6.0_03-b05, mixed mode, sharing)
    說明環境變量設置成功。

    posted @ 2009-08-10 10:22 AntiquMan 閱讀(185) | 評論 (0)編輯 收藏

    基本演示了線程池和隊列的應用

      public class WorkQueue { 
       

       private final int nThreads;//線程池的大小 
       private final PoolWorker[] threads;//用數組實現線程池 
       private final LinkedList queue;//任務隊列 

      public WorkQueue(int nThreads){ 
         this.nThreads = nThreads; 
         queue = new LinkedList(); 
         threads = new PoolWorker[nThreads]; 

          for (int i=0; i<nThreads;i++){

             threads[i] = new PoolWorker(); 
             threads[i].start();//啟動所有工作線程 
          } 
      } 

      public void execute(Runnable r) {//
    任務 
        synchronized(queue) { 
                queue.addLast(r); 
                queue.notify(); 
        } 
      } 

      private class PoolWorker extends Thread {//工作線程類 
            public void run() { 
                   Runnable r; 
                   while (true) { 
                        synchronized(queue) { 
                          while (queue.isEmpty()) {//如果任務隊列中沒有任務,等待 
                            try{ 
                              queue.wait(); 
                            }catch (InterruptedException ignored){} 
                          }    
                           r = (Runnable) queue.removeFirst();//有任務時,取出任務 
                       } 
                       try { 
                           r.run();//執行任務 
                       }catch (RuntimeException e) { 
                          // You might want to log something here 
                      } 
                  } 
          } 
       } 


     public static void main(String args[]){ 
          WorkQueue wq=new WorkQueue(10);//10個工作線程 
          Mytask r[]=new Mytask[20];//20個任務 
       
          for(int i=0;i<20;i++){ 
               r[i]=new Mytask(); 
               wq.execute(r[i]); 
          }       
     } 

    class Mytask implements Runnable{//任務接口 
             public void run(){ 
                  String name=Thread.currentThread().getName(); 
                  try{ 
                      Thread.sleep(100);//模擬任務執行的時間 
                  }catch(InterruptedException e){} 
                  System.out.println(name+" executed OK"); 
             } 
      } 

    posted @ 2009-08-03 18:18 AntiquMan 閱讀(200) | 評論 (0)編輯 收藏

    上周在優化預警分析的工作中,發現由于分頁功能需要提供總條數 ,項目組內的普遍做法是進行兩次sql查詢,一次用count(*)獲得總條數,一次獲取真正的展現數據。其實oracle提供了olap函數對此進行優化,可通過偽列:count(*) over()獲得當前sql的總條數。

        比如:select t.*,count(*) over() from dual 會返回總條數為1。
     
        olap函數主要用于統計分析,熟練掌握能很好的提高sql執行效率。
            count(*) over() 具體功能描述如下:
           對一組內發生的事情進行累積計數,如果指定*或一些非空常數,count將對所有行計數,如果指定一個表達式,count返回表達式非空賦值的計數,當有相同值出現時,這些相等的值都會被納入被計算的值;可以使用DISTINCT來記錄去掉一組中完全相同的數據后出現的行數。
    SAMPLE:下面例子中計算每個員工在按薪水排序中當前行附近薪水在[n-50,n+150]之間的行數,n表示當前行的薪水
           例如,Philtanker的薪水2200,排在他之前的行中薪水大于等于2200-50的有1行,排在他之后的行中薪水小于等于2200+150的行沒有,所以count計數值cnt3為2(包括自己當前行);cnt2值相當于小于等于當前行的SALARY值的所有行數
    sql如下:

     SELECT last_name, salary, COUNT(*) OVER () AS cnt1,
               COUNT(*) OVER (ORDER BY salary) AS cnt2,
               COUNT(*) OVER (ORDER BY salary RANGE BETWEEN 50 PRECEDING AND 150 FOLLOWING) AS cnt3 FROM employees;

    結果如下 :

    LAST_NAME  SALARY  CNT2   CNT2  CNT3
    Olson          2100 107 1 3
    Markle 2200 107 3 2
    Philtanker 2200 107 3 2
    Landry 2400 107 5 8
    Gee 2400 107 5 8
    Colmenares 2500 107 11 10
    Patel 2500 107 10 10

    posted @ 2009-08-03 18:11 AntiquMan 閱讀(322) | 評論 (0)編輯 收藏

    Code
     
    01.//Copyright © 2009. Http://L4cd.Net All Rights Reserved.
    02.package net.L4cd.display
    03.{
    04.    import flash.events.Event;
    05.    import flash.events.TextEvent;
    06.    import flash.text.TextField;
    07.    import flash.utils.ByteArray;
    08.  
    09.    /**
    10.     * 擴展TextField類,中文以2字符長度計算
    11.     *
    12.     * @author L4cd.Net
    13.     * @playerversion Flash player 9
    14.     * @langversion 3.0
    15.     * @version 2009-06-16
    16.     */
    17.    public class TextFieldExt extends TextField
    18.    {
    19.        private var _maxChars:int = -1;
    20.        public function TextFieldExt()
    21.        {
    22.            super();
    23.              
    24.        }
    25.        override public function get maxChars():int
    26.        {
    27.            return _maxChars;
    28.        }
    29.        override public function set maxChars(value:int):void
    30.        {
    31.            _maxChars = value;
    32.            if(maxChars<0)
    33.            {
    34.                removeEventListener(TextEvent.TEXT_INPUT,input);      
    35.            }else
    36.            {
    37.                addEventListener(TextEvent.TEXT_INPUT,input);
    38.                text = getTextByCharLength(text,maxChars);
    39.            }
    40.        }
    41.        override public function get length():int
    42.        {
    43.            return getCharLength(text);
    44.        }
    45.        private function input(e:TextEvent):void
    46.        {
    47.            //攔截并阻止textinput事件,手動處理內容輸入
    48.            var textField:TextField = e.currentTarget as TextField;
    49.            var temp:String = getTextByCharLength(e.text,maxChars - getCharLength(text) + getCharLength(selectedText));
    50.            var index:int = selectionBeginIndex;
    51.            replaceText(selectionBeginIndex,selectionEndIndex,temp);
    52.            setSelection(index+temp.length,index+temp.length);
    53.            dispatchEvent(new Event(Event.CHANGE,true));
    54.            e.preventDefault();
    55.        }
    56.        /**
    57.         * 獲取字符長度,一個中文算2長度
    58.         * @param txt
    59.         * @return 返回長度值
    60.         */    
    61.        private function getCharLength(txt:String):int
    62.        {
    63.            var byte:ByteArray = new ByteArray();
    64.            byte.writeMultiByte(txt,"gb2312");
    65.            byte.position = 0;
    66.            return byte.bytesAvailable;
    67.        }
    68.        /**
    69.         * 截取指定長度的文本內容,一個中文算2長度
    70.         * @param txt 需要截取的文本
    71.         * @param length 需要截取的長度
    72.         * @return 截取后的內容
    73.         */    
    74.        private function getTextByCharLength(txt:String,length:int):String
    75.        {
    76.            if(length<1)return "";
    77.            var byte:ByteArray = new ByteArray();
    78.            byte.writeMultiByte(txt,"gb2312");
    79.            byte.position = 0;
    80.            return byte.readMultiByte(Math.min(length,byte.bytesAvailable),"gb2312");
    81.        }
    82.    }
    83.}




    調用方法和普通TextField無異
    1.import net.L4cd.display.TextFieldExt
    2.var ext:TextFieldExt = new TextFieldExt();
    3.ext.maxChars = 15;
    4.addChild(ext);





    一般的輸入,粘貼等操作均沒問題..
    直接對text進行賦值沒有進行限制 (原來的TextField也沒限制)..
    如需限制~可以調用一次maxChars = maxChars即可..

    posted @ 2009-07-03 14:47 AntiquMan 閱讀(515) | 評論 (0)編輯 收藏

    一、同步問題提出
     
    線程的同步是為了防止多個線程訪問一個數據對象時,對數據造成的破壞。
    例如:兩個線程ThreadA、ThreadB都操作同一個對象Foo對象,并修改Foo對象上的數據。
     
    public class Foo {
        private int x = 100;

        public int getX() {
            return x;
        }

        public int fix(int y) {
            x = x - y;
            return x;
        }
    }
     
    public class MyRunnable implements Runnable {
        private Foo foo = new Foo();

        public static void main(String[] args) {
            MyRunnable r = new MyRunnable();
            Thread ta = new Thread(r, "Thread-A");
            Thread tb = new Thread(r, "Thread-B");
            ta.start();
            tb.start();
        }

        public void run() {
            for (int i = 0; i < 3; i++) {
                this.fix(30);
                try {
                    Thread.sleep(1);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName() + " : 當前foo對象的x值= " + foo.getX());
            }
        }

        public int fix(int y) {
            return foo.fix(y);
        }
    }
     
    運行結果:
    Thread-A : 當前foo對象的x值= 40
    Thread-B : 當前foo對象的x值= 40
    Thread-B : 當前foo對象的x值= -20
    Thread-A : 當前foo對象的x值= -50
    Thread-A : 當前foo對象的x值= -80
    Thread-B : 當前foo對象的x值= -80

    Process finished with exit code 0
     
    從結果發現,這樣的輸出值明顯是不合理的。原因是兩個線程不加控制的訪問Foo對象并修改其數據所致。
     
    如果要保持結果的合理性,只需要達到一個目的,就是將對Foo的訪問加以限制,每次只能有一個線程在訪問。這樣就能保證Foo對象中數據的合理性了。
     
    在具體的Java代碼中需要完成一下兩個操作:
    把競爭訪問的資源類Foo變量x標識為private;
    同步哪些修改變量的代碼,使用synchronized關鍵字同步方法或代碼。
     
    二、同步和鎖定
     
    1、鎖的原理
     
    Java中每個對象都有一個內置鎖
     
    當程序運行到非靜態的synchronized同步方法上時,自動獲得與正在執行代碼類的當前實例(this實例)有關的鎖。獲得一個對象的鎖也稱為獲取鎖、鎖定對象、在對象上鎖定或在對象上同步。
     
    當程序運行到synchronized同步方法或代碼塊時才該對象鎖才起作用。
     
    一個對象只有一個鎖。所以,如果一個線程獲得該鎖,就沒有其他線程可以獲得鎖,直到第一個線程釋放(或返回)鎖。這也意味著任何其他線程都不能進入該對象上的synchronized方法或代碼塊,直到該鎖被釋放。
     
    釋放鎖是指持鎖線程退出了synchronized同步方法或代碼塊。
     
    關于鎖和同步,有一下幾個要點:
    1)、只能同步方法,而不能同步變量和類;
    2)、每個對象只有一個鎖;當提到同步時,應該清楚在什么上同步?也就是說,在哪個對象上同步?
    3)、不必同步類中所有的方法,類可以同時擁有同步和非同步方法。
    4)、如果兩個線程要執行一個類中的synchronized方法,并且兩個線程使用相同的實例來調用方法,那么一次只能有一個線程能夠執行方法,另一個需要等待,直到鎖被釋放。也就是說:如果一個線程在對象上獲得一個鎖,就沒有任何其他線程可以進入(該對象的)類中的任何一個同步方法。
    5)、如果線程擁有同步和非同步方法,則非同步方法可以被多個線程自由訪問而不受鎖的限制。

    6)、線程睡眠時,它所持的任何鎖都不會釋放。

    7)、線程可以獲得多個鎖。比如,在一個對象的同步方法里面調用另外一個對象的同步方法,則獲取了兩個對象的同步鎖。
    8)、同步損害并發性,應該盡可能縮小同步范圍。同步不但可以同步整個方法,還可以同步方法中一部分代碼塊。
    9)、在使用同步代碼塊時候,應該指定在哪個對象上同步,也就是說要獲取哪個對象的鎖。例如:
        public int fix(int y) {
            synchronized (this) {
                x = x - y;
            }
            return x;
        }
     
    當然,同步方法也可以改寫為非同步方法,但功能完全一樣的,例如:
        public synchronized int getX() {
            return x++;
        }
        public int getX() {
            synchronized (this) {
                return x;
            }
        }
    效果是完全一樣的。
     
    三、靜態方法同步
     
    要同步靜態方法,需要一個用于整個類對象的鎖,這個對象是就是這個類(XXX.class)。
    例如:
    public static synchronized int setName(String name){
          Xxx.name = name;
    }
    等價于
    public static int setName(String name){
          synchronized(Xxx.class){
                Xxx.name = name;
          }
    }

     
    四、如果線程不能不能獲得鎖會怎么樣
     
    如果線程試圖進入同步方法,而其鎖已經被占用,則線程在該對象上被阻塞。實質上,線程進入該對象的的一種池中,必須在哪里等待,直到其鎖被釋放,該線程再次變為可運行或運行為止。
     
    當考慮阻塞時,一定要注意哪個對象正被用于鎖定:
    1、調用同一個對象中非靜態同步方法的線程將彼此阻塞。如果是不同對象,則每個線程有自己的對象的鎖,線程間彼此互不干預。
     
    2、調用同一個類中的靜態同步方法的線程將彼此阻塞,它們都是鎖定在相同的Class對象上。
     
    3、靜態同步方法和非靜態同步方法將永遠不會彼此阻塞,因為靜態方法鎖定在Class對象上,非靜態方法鎖定在該類的對象上。
     
    4、對于同步代碼塊,要看清楚什么對象已經用于鎖定(synchronized后面括號的內容)。在同一個對象上進行同步的線程將彼此阻塞,在不同對象上鎖定的線程將永遠不會彼此阻塞。
     
    五、何時需要同步
     
    在多個線程同時訪問互斥(可交換)數據時,應該同步以保護數據,確保兩個線程不會同時修改更改它。
     
    對于非靜態字段中可更改的數據,通常使用非靜態方法訪問。
    對于靜態字段中可更改的數據,通常使用靜態方法訪問。
     
    如果需要在非靜態方法中使用靜態字段,或者在靜態字段中調用非靜態方法,問題將變得非常復雜。已經超出SJCP考試范圍了。
     
    六、線程安全類
     
    當一個類已經很好的同步以保護它的數據時,這個類就稱為“線程安全的”。
     
    即使是線程安全類,也應該特別小心,因為操作的線程是間仍然不一定安全。
     
    舉個形象的例子,比如一個集合是線程安全的,有兩個線程在操作同一個集合對象,當第一個線程查詢集合非空后,刪除集合中所有元素的時候。第二個線程也來執行與第一個線程相同的操作,也許在第一個線程查詢后,第二個線程也查詢出集合非空,但是當第一個執行清除后,第二個再執行刪除顯然是不對的,因為此時集合已經為空了。
    看個代碼:
     
    public class NameList {
        private List nameList = Collections.synchronizedList(new LinkedList());

        public void add(String name) {
            nameList.add(name);
        }

        public String removeFirst() {
            if (nameList.size() > 0) {
                return (String) nameList.remove(0);
            } else {
                return null;
            }
        }
    }
     
    public class Test {
        public static void main(String[] args) {
            final NameList nl = new NameList();
            nl.add("aaa");
            class NameDropper extends Thread{
                public void run(){
                    String name = nl.removeFirst();
                    System.out.println(name);
                }
            }

            Thread t1 = new NameDropper();
            Thread t2 = new NameDropper();
            t1.start();
            t2.start();
        }
    }
     
    雖然集合對象
        private List nameList = Collections.synchronizedList(new LinkedList());
    是同步的,但是程序還不是線程安全的。
    出現這種事件的原因是,上例中一個線程操作列表過程中無法阻止另外一個線程對列表的其他操作。
     
    解決上面問題的辦法是,在操作集合對象的NameList上面做一個同步。改寫后的代碼如下:
    public class NameList {
        private List nameList = Collections.synchronizedList(new LinkedList());

        public synchronized void add(String name) {
            nameList.add(name);
        }

        public synchronized String removeFirst() {
            if (nameList.size() > 0) {
                return (String) nameList.remove(0);
            } else {
                return null;
            }
        }
    }
     
    這樣,當一個線程訪問其中一個同步方法時,其他線程只有等待。
     
    七、線程死鎖
     
    死鎖對Java程序來說,是很復雜的,也很難發現問題。當兩個線程被阻塞,每個線程在等待另一個線程時就發生死鎖。
     
    還是看一個比較直觀的死鎖例子:
     
    public class DeadlockRisk {
        private static class Resource {
            public int value;
        }

        private Resource resourceA = new Resource();
        private Resource resourceB = new Resource();

        public int read() {
            synchronized (resourceA) {
                synchronized (resourceB) {
                    return resourceB.value + resourceA.value;
                }
            }
        }

        public void write(int a, int b) {
            synchronized (resourceB) {
                synchronized (resourceA) {
                    resourceA.value = a;
                    resourceB.value = b;
                }
            }
        }
    }
     
    假設read()方法由一個線程啟動,write()方法由另外一個線程啟動。讀線程將擁有resourceA鎖,寫線程將擁有resourceB鎖,兩者都堅持等待的話就出現死鎖。
     
    實際上,上面這個例子發生死鎖的概率很小。因為在代碼內的某個點,CPU必須從讀線程切換到寫線程,所以,死鎖基本上不能發生。
     
    但是,無論代碼中發生死鎖的概率有多小,一旦發生死鎖,程序就死掉。有一些設計方法能幫助避免死鎖,包括始終按照預定義的順序獲取鎖這一策略。已經超出SCJP的考試范圍。
     
    八、線程同步小結
     
    1、線程同步的目的是為了保護多個線程反問一個資源時對資源的破壞。
    2、線程同步方法是通過鎖來實現,每個對象都有切僅有一個鎖,這個鎖與一個特定的對象關聯,線程一旦獲取了對象鎖,其他訪問該對象的線程就無法再訪問該對象的其他非同步方法。
    3、對于靜態同步方法,鎖是針對這個類的,鎖對象是該類的Class對象。靜態和非靜態方法的鎖互不干預。一個線程獲得鎖,當在一個同步方法中訪問另外對象上的同步方法時,會獲取這兩個對象鎖。
    4、對于同步,要時刻清醒在哪個對象上同步,這是關鍵。
    5、編寫線程安全的類,需要時刻注意對多個線程競爭訪問資源的邏輯和安全做出正確的判斷,對“原子”操作做出分析,并保證原子操作期間別的線程無法訪問競爭資源。
    6、當多個線程等待一個對象鎖時,沒有獲取到鎖的線程將發生阻塞。
    7、死鎖是線程間相互等待鎖鎖造成的,在實際中發生的概率非常的小。真讓你寫個死鎖程序,不一定好使,呵呵。但是,一旦程序發生死鎖,程序將死掉。

    posted @ 2009-07-03 14:45 AntiquMan 閱讀(145) | 評論 (0)編輯 收藏

    1.基本結構
    CREATE OR REPLACE PROCEDURE 存儲過程名字
    (
        參數1 IN NUMBER,
        參數2 IN NUMBER
    ) IS
    變量1 INTEGER :=0;
    變量2 DATE;
    BEGIN

    END 存儲過程名字

    2.SELECT INTO STATEMENT
      將select查詢的結果存入到變量中,可以同時將多個列存儲多個變量中,必須有一條
      記錄,否則拋出異常(如果沒有記錄拋出NO_DATA_FOUND)
      例子:
      BEGIN
      SELECT col1,col2 into 變量1,變量2 FROM typestruct where xxx;
      EXCEPTION
      WHEN NO_DATA_FOUND THEN
          xxxx;
      END;
      ...

    3.IF 判斷
      IF V_TEST=1 THEN
        BEGIN
           do something
        END;
      END IF;

    4.while 循環
      WHILE V_TEST=1 LOOP
      BEGIN
     XXXX
      END;
      END LOOP;

    5.變量賦值
      V_TEST := 123;

    6.用for in 使用cursor
      ...
      IS
      CURSOR cur IS SELECT * FROM xxx;
      BEGIN
     FOR cur_result in cur LOOP
      BEGIN
       V_SUM :=cur_result.列名1+cur_result.列名2
      END;
     END LOOP;
      END;

    7.帶參數的cursor
      CURSOR C_USER(C_ID NUMBER) IS SELECT NAME FROM USER WHERE TYPEID=C_ID;
      OPEN C_USER(變量值);
      LOOP
     FETCH C_USER INTO V_NAME;
     EXIT FETCH C_USER%NOTFOUND;
        do something
      END LOOP;
      CLOSE C_USER;

    8.用pl/sql developer debug
      連接數據庫后建立一個Test WINDOW
      在窗口輸入調用SP的代碼,F9開始debug,CTRL+N單步調試

     

    關于oracle存儲過程的若干問題備忘
    1.在oracle中,數據表別名不能加as,如:

    select a.appname from appinfo a;-- 正確
    select a.appname from appinfo as a;-- 錯誤
     也許,是怕和oracle中的存儲過程中的關鍵字as沖突的問題吧

    2.在存儲過程中,select某一字段時,后面必須緊跟into,如果select整個記錄,利用游標的話就另當別論了。

      select af.keynode into kn from APPFOUNDATION af where af.appid=aid and af.foundationid=fid;-- 有into,正確編譯
      select af.keynode from APPFOUNDATION af where af.appid=aid and af.foundationid=fid;-- 沒有into,編譯報錯,提示:Compilation
      Error: PLS-00428: an INTO clause is expected in this SELECT statement


    3.在利用select...into...語法時,必須先確保數據庫中有該條記錄,否則會報出"no data found"異常。

       可以在該語法之前,先利用select count(*) from 查看數據庫中是否存在該記錄,如果存在,再利用select...into...

    4.在存儲過程中,別名不能和字段名稱相同,否則雖然編譯可以通過,但在運行階段會報錯

     select keynode into kn from APPFOUNDATION where appid=aid and foundationid=fid;-- 正確運行
    select af.keynode into kn from APPFOUNDATION af where af.appid=appid and af.foundationid=foundationid;-- 運行階段報錯,提示
    ORA-01422:exact fetch returns more than requested number of rows
    5.在存儲過程中,關于出現null的問題

    假設有一個表A,定義如下:
    create table A(
    id varchar2(50) primary key not null,
    vcount number(8) not null,
    bid varchar2(50) not null -- 外鍵
    );如果在存儲過程中,使用如下語句:
    select sum(vcount) into fcount from A where bid='xxxxxx';如果A表中不存在bid="xxxxxx"的記錄,則fcount=null(即使fcount定義時設置了默認值,如:fcount number(8):=0依然無效,fcount還是會變成null),這樣以后使用fcount時就可能有問題,所以在這里最好先判斷一下:
    if fcount is null then
        fcount:=0;
    end if;這樣就一切ok了。

    6.Hibernate調用oracle存儲過程

            this.pnumberManager.getHibernateTemplate().execute(
                    new HibernateCallback() ...{
                        public Object doInHibernate(Session session)
                                throws HibernateException, SQLException ...{
                            CallableStatement cs = session
                                    .connection()
                                    .prepareCall("{call modifyapppnumber_remain(?)}");
                            cs.setString(1, foundationid);
                            cs.execute();
                            return null;
                        }
                    });
     

     

    posted @ 2009-07-01 16:17 AntiquMan 閱讀(250) | 評論 (0)編輯 收藏

    Name:EuViN
    Key:BZ9T4P-LBQRP-CGQPJ-7PDGR-N9ZKC-8ECXN-9999

    posted @ 2009-06-27 11:55 AntiquMan 閱讀(122) | 評論 (0)編輯 收藏


     <mx:DateField x="46" y="299" yearNavigationEnabled="true"
              dayNames="[日,一,二,三,四,五,六]" monthNames="[一月,二月,三月,四月,五月,六月,七月,八月,九月,十,      十一月,十二月]" formatString="YYYY-MM-DD"/>

    posted @ 2009-06-16 19:28 AntiquMan 閱讀(298) | 評論 (0)編輯 收藏

    String類是ActionScript中描述字符串的類. 該類提供了處理字符串的屬性與方法. 可以使用String()方法將各種類型的對象轉換為Sring.

     

    String是AS中文本的基礎.一個字符串由零個或零個以上的字符組成.AS支持Unicode和ASCII兩種文本編碼格式.String可以通過直接賦值和new關鍵字兩種方式創建.由單引號或雙引號表示,必要的時候應使用轉義字符’/’.

     

    Public Properties

     

    length:int

     

    返回該String的長度.

     

    Public Methods

     

    String(val:String): 構造函數,新建一個String.

    charAt(index:Number=0):Number: 返回在某個inidex的字符

    charCodeAt(index:Number=0):Number 返回某個index的字符對應的Unicode字符碼

    concat(..args):Stirng: 連接兩個字符串.

    fromCharCode(charCodes):String 將某Unicode字符碼轉換為String

    indexOf(): 從左向右找到的第一個目標的index

    lastIndexOf(): 從左向右最后一個…也就是從右向左第一個.

    localeCompare(): 判斷連個字符串是否完全相同, 若返回值為0,則表示相同,其他值表示不同

    replace:替換

    search(): 從左向右第一個目標的index

    slice(): 返回連個index之間的String

    split(): 使用間隔符,將String分割為多個String,并放入數組中.

    subStr(): 從某index開始向后的特定數目內返回的String

    subString(): 類似slice();

    Flex代碼
    1. public function init():void {   
    2.  var s:String = "liguoliang";   
    3.  var s1:String = ".com";   
    4.  var s2:String = "liguoliang";   
    5.  trace("s的長度: " + s.length);   
    6.  trace("第0個字符: " + s.charAt(0));   
    7.  trace("s連接s1: " + s.concat(s1));   
    8.  trace("65對應的char: " + String.fromCharCode(65));   
    9.  trace("第一個l的位置" + s.indexOf("l"));   
    10.  trace("從index為2的字符開始向右找到的第一個l的index: " + s.indexOf("l",1));   
    11.  trace("從右向做找到的第一個l的index: " + s.lastIndexOf("l"));   
    12.  trace(s.localeCompare(s2)); //如果返回值為零,則表示兩個字符串完全相同, 如果返回值非零,則表示不同.   
    13.  trace("將li替換為s2: "+ s.replace("li", s2) + "  " + s);   
    14.  trace("從左向右搜索到的第一個L: " + s.search("l"));   
    15.  trace("子字符串: " + s.slice(01)); //不包括最后一個...如果參數為空,則置為-1.兩參數都為空時,取全部   
    16.  trace("子字符串:從index為0開始,取兩個字符 " + s.substr(02));//也不包括最后一個...   
    17.  trace("子字符串: " + s.substring(01));   
    18.  trace(s.split("i")); //返回l,guol,ang,若將最大值限制為2,則表示數組中進放入2個返回l,guol   
    19. }  

     

    字符串大小寫轉換:flexstr.toLowerCase(); flexstr.toUpperCase();

    其他對象轉換為String.在默認情況下,所有的AS對象都可以轉換為String類型.每一個類都有一個toString方法.

    通過toString可以將對象轉換為String.

    posted @ 2009-06-11 14:14 AntiquMan 閱讀(2267) | 評論 (0)編輯 收藏

    僅列出標題
    共4頁: 上一頁 1 2 3 4 下一頁 
    主站蜘蛛池模板: 国产亚洲精彩视频| 国产精品视_精品国产免费 | 精品国产免费人成网站| 亚洲综合色婷婷在线观看| 91亚洲国产成人精品下载| 亚洲熟妇av一区二区三区| 亚洲Aⅴ无码一区二区二三区软件 亚洲AⅤ视频一区二区三区 | 久久99精品免费视频| 老司机午夜在线视频免费| 亚洲色成人网站WWW永久四虎| 亚洲精品免费视频| 国产亚洲一区二区三区在线| 亚洲精品WWW久久久久久| 国产午夜免费秋霞影院| 成人午夜大片免费7777| 国产1024精品视频专区免费| 精品久久8x国产免费观看| 一级做a爰全过程免费视频| 久草免费福利视频| 免费一级毛片在线播放视频| 国产成年无码久久久免费| 国产精品视频全国免费观看| 羞羞视频在线观看免费| 美女被暴羞羞免费视频| 精品视频免费在线| 怡红院亚洲红怡院在线观看| 亚洲第一se情网站| 羞羞视频免费观看| 午夜在线免费视频 | 四虎成人免费大片在线| 国产成人免费高清激情视频| 久久综合AV免费观看| 成人免费一区二区三区在线观看| 在线看片免费不卡人成视频| 日韩免费a级毛片无码a∨| 最近中文字幕免费mv视频8| 免费看大黄高清网站视频在线| 午夜色a大片在线观看免费| 女人18毛片免费观看| 四虎永久免费地址在线网站| 亚洲国产一级在线观看|