天天看點

Java SE 學習筆記 第十二記

2012-08-01

1、wait():Object定義的方法,不能被重寫。當一個線程調用該方法時,該線程必須擁有對象的鎖,是以wait()必須包含在synchronized方法或者代碼塊中才能保證調用wait方法是線程擁有一個對象的鎖。當線程調用wait方法後,線程會自動放棄對上鎖對象的鎖,并進入等待重新獲得鎖的狀态,重新獲得鎖後線程将從wait之後的代碼繼續運作。重新獲得鎖的方法由其它擁有該對象鎖的線程調用notify()方法。

2、notify():Object定義的方法,不能被重寫,與wait配套使用,同樣調用該方法的線程必須擁有該對象鎖,是以notify方法也必須在synchronized方法或代碼塊中調用。當一個線程調用notify方法後,将會喚醒因與目前對象擁有同個鎖,并調用wait方法進入等待的線程。如果存在多個wait線程,則會通過線程競争的方法選擇喚醒哪個線程。然而,并不是目前線程調用notify方法後就能立即喚醒被wait方法進入等待的線程,而是得等到向前線程結束或抛出異常而對上鎖對象解鎖後才能調用被wait進入等待的線程。

3、多個線程中,有一個對象的wait出現,就一定有該對象的notify出現,但是兩者在數量上可能不一緻。并且,wait方法前一般有一個條件判斷,當條件滿足時才調用wait。通常情況下,使用while包裝wait,讓每次線程被喚醒後都要再檢查一次條件是否滿足,因為在并發線程比較多的時候,線程被喚醒時,可能由于其它線程幹擾導緻條件改變,若不檢查容易出現并發錯誤。

4、Thread.sleep方法也能令線程暫停,并且能指定暫停多長時間。與wait不同的是,sleep方法暫停時不會釋放掉對象的鎖,并且當暫時時間過去後,線程能自動被喚醒(wait需要notify方法喚醒)。是以sleep線程被喚醒時已經擁有對象的鎖,是以才能繼續馬上繼續進行(wait喚醒後還要重新等待擷取到對象鎖才能繼續運作)。

5、由于wait和notify,線程對象多了wait阻塞狀态。當線程調用了wait方法後,線程便進入wait阻塞狀态,并進入等待池(wait pool),直到其他線程調用同鎖對象的notify方法,線程便進入上鎖阻塞狀态,也就是進入鎖池(look pool)。

6、線程組:一些線程的集合,一個線程被建立後不能再修改其隸屬的線程組,建立一個線程時若沒有指定線程組,則新線程與建立其的父線程隸屬于同一個線程組。線程組比較少用到。

7、對象的淺拷貝:當對一個對象進行淺拷貝後,拷貝出來的對象會提供一套新的對象成員變量來複制接收原對象的各個成員變量值。是以,如果是原對象的原生資料類型成員變量,則直接将值複制過來,但如果是對象引用類型變量,由于對象類型引用變量的值隻是個位址,是以複制過來的也是對象的對象成員位址,導緻淺拷貝後對象的對象成員變量指向原對象的對象成員。一旦原對象或新對象任何一方的對象成員内的成員變量值發生改變,将會互相影響。但是,如果是對原對象或新對象任何一方的對象成員賦予另一個對象引用值的話,由于不再指向同一個對象,是以原對象和新對象之間不再互相影響。

8、對象的深拷貝:在基于對象淺拷貝的基礎上,除了對象原生資料類型成員的複制方法一樣之外,對于對象成員,深拷貝是重新構造一個對象成員再将新對象成員的引用賦給新對象的對象成員變量。是以,深拷貝之後,原對象和新對象的對象成員變量都不指向同一個對象,它們之間互不影響。

9、實作淺拷貝和深拷貝的方法:

    1)淺拷貝:Object類提供了clone()方法,其作用是進行淺拷貝,但由于其修飾符是protected,在外包中不可見,Java要求對需要進行拷貝的類要重寫這個clone方法,并且要實作接口Cloneable(Cloneable是一個辨別性接口,裡面沒有定義任何方法,隻是聲明而已,類似于serializable接口)和将方法聲明修飾符改為public(對外包可見)。在重寫的clone方法中要調用Object的方法(super.clone()),便可以進行淺拷貝。Object的clone淺拷貝的結果符合x.clone()!=x為true、x.clone().getClass()==x.getClass()為true、x.clone().equals(x)為true。

    2)深拷貝方法一:将需要深拷貝對象類在淺拷貝基礎上,重寫clone方法中調用super.clone()之後,調用每個對象成員的clone方法。是以,每個對象成員的類都要實作淺拷貝的方法,若對象成員又包含自己的對象成員,則它們也要編寫淺拷貝,以此類推。

    3)深拷貝方法二:利用對象序列化和反序列化。當一個對象包含多個對象成員時需要對每個對象成員都進行拷貝會很繁瑣,但是借助對象序列化和反序列化能夠複制對象和它對象鍊上的所有内容到流上,又能将所有對象資訊充流上讀回來的特點,可以間接的實作深拷貝。當然,前提是對象的每個對象成員都可以序列化。(序列化要點:實作Serializable接口,利用ObjectOutputstream和ObjectInputstream包裝流)。這種方法是最常用的深拷貝方法。

10、當類實作Serializable接口表明可序列化時,定義long靜态成員變量serialVersionUID的作用在于:當該類對象序列化後反序列化回來時,若此類的定義已經發生改變(删除了一些成員變量或者增加了一些成員變量),如果沒有定義這個serialVersionUID就會抛出Exception,無法進行序列化。而如果有定義serialVersionUID,反序列化若遇到類已經改變的情況,不會直接抛出Exception,而是查找類的serialVersionUID值是否相同,相同話就還是可以反序列化回來,對于被删除或者增加的成員将會以成員類型的預設屬性指派。可以說,serialVersionUID提供了對象向後相容的可能。

11、IP用于确定資料包需要送達的主機位置,端口用于确定資料包需要傳遞給主機上哪一個程式。端口使用一個16位數字表示,範圍0-65535。http協定預設使用80端口,使用者程式使用的端口最好選擇1024之後的端口。

12、在網絡分層模型中,對等層協定之間交換的資訊單元統稱為PDU,下層把上層的PDU當做本層PDU的資料部分封裝。

13、Java提供了對網絡程式設計的支援,與網絡程式設計相關的類包含在java.net包中。

14、URL:統一資源定位符的簡稱(Uniform Resource Locator),表示Internet上某一資源的位址,通過URL可以通路Internet上的各種網絡資源。使用URL進行網絡程式設計,不需要對協定本身有太多的了解,功能也比較弱,相對而言比較簡單。一個URL主要包括協定辨別符和資源名字兩個部分。

15、java.net.URL類:URL類對象用于封裝一個URL位址,并提供了相關URL操作方法。可以通過URL位址字元串直接建立URL對象,也可使用其它構造方法構造,如果構造失敗會抛出MalfformedURLException異常。使用getProtocol(擷取協定)、getHost(主機名)、getPort(端口)、getFile(檔案名)、getRef(URL錨點)等方法可以擷取URL對象相關屬性。

16、構造一個URL對象并不等于連接配接了URL指向的檔案,需要使用URL的openConnection()方法傳回一個URLConnection對象(可能引發IOException異常),獲得該URL的連接配接,再利用URLConnection對象的getInputStream()方法可以擷取該URL指向的檔案的輸入流,繼而通過對輸入流的操作可以擷取該URL指向的檔案。URL類也提供了openStream()方法可傳回URL對象指向檔案的InputStream輸入流,本質上是對以上兩個方法的綜合調用。

17、java.net.URLConnection類:通路遠端資源屬性的一般用途類。當建立了與遠端伺服器之間的連接配接後,可以在傳輸它到本地之前用URLConnection對象來檢察遠端對象的屬性,隻對HTTP協定的URL對象有意義。