偷偷摘套内射激情视频,久久精品99国产国产精,中文字幕无线乱码人妻,中文在线中文a,性爽19p

高手支招 Java經(jīng)驗(yàn)分享(四)

開(kāi)發(fā) 后端
本篇文章是作者Ant_Yan在CSDN論壇上發(fā)布的自己對(duì)Java學(xué)習(xí)的一些經(jīng)驗(yàn)分享。這是他經(jīng)驗(yàn)分享的第四部分。

  不知不覺(jué)已經(jīng)寫(xiě)到第四篇了,第三篇講的是反射機(jī)制集合框架之類(lèi)的,這次打算講講自己對(duì)反序列化和多線(xiàn)程的理解。希望能對(duì)大家學(xué)習(xí)Java起到幫助:

  1.關(guān)于序列化和反序列化

  應(yīng)該大家都大概知道Java中序列化和反序列化的意思,序列化就是把一個(gè)Java對(duì)象轉(zhuǎn)換成二進(jìn)制進(jìn)行磁盤(pán)上傳輸或者網(wǎng)絡(luò)流的傳輸,反序列化的意思就是把這個(gè)接受到的二進(jìn)制流重新組裝成原來(lái)的對(duì)象逆過(guò)程。它們?cè)贘ava中分別是通過(guò)ObjectInputStream和 ObjectInputStream這兩個(gè)類(lèi)來(lái)實(shí)現(xiàn)的(以下分別用ois和oos來(lái)簡(jiǎn)稱(chēng))。

  oos的writeObject()方法用來(lái)執(zhí)行序列化的過(guò)程,ois的readObject()用來(lái)執(zhí)行反序列化的過(guò)程,在傳輸二進(jìn)制流之前,需要講這兩個(gè)高層流對(duì)象連接到同一個(gè)Channel上,這個(gè)Channel可以是磁盤(pán)文件,也可以是socket底層流。所以無(wú)論用哪種方式,底層流對(duì)象都是以構(gòu)造函數(shù)參數(shù)的形式傳遞進(jìn)oos和ois這兩個(gè)高層流,連接完畢了才可以進(jìn)行二進(jìn)制數(shù)據(jù)傳輸?shù)摹@樱?/p>

  可以是文件流通道:

  1. file = new File(“C:/data.dat”);  
  2. oos = new ObjectOutputStream(new FileOutputStream(file));  
  3. ois = new ObjectInputStream(new FileInputStream(file));    

  或者網(wǎng)絡(luò)流通道:

  1. oos = new ObjectOutputStream(socket.getOutputStream());  
  2. ois = new ObjectInputStream(socket.getInputStream()); 

  不知道大家是否注意到oos總是在ois之前定義,這里不希望大家誤解這個(gè)順序是固定的么?回答是否定的,那么有順序要求么?回答是肯定的。原則是什么呢?

  原則是互相對(duì)接的輸入/輸出流之間必須是output流先初始化然后再input流初始化,否則就會(huì)拋異常。大家肯定會(huì)問(wèn)為什么?只要稍微看一看這兩個(gè)類(lèi)的源代碼文件就大概知道了,output流的任務(wù)很簡(jiǎn)單,只要把對(duì)象轉(zhuǎn)換成二進(jìn)制往通道中寫(xiě)就可以了,但input流需要做很多準(zhǔn)備工作來(lái)接受并最終重組這個(gè)Object,所以O(shè)bjectInputStream的構(gòu)造函數(shù)中就需要用到output初始化發(fā)送過(guò)來(lái)的header信息,這個(gè)方法叫做 readStreamHeader(),它將會(huì)去讀兩個(gè)Short值用于決定用多大的緩存來(lái)存放通道發(fā)送過(guò)來(lái)的二進(jìn)制流,這個(gè)緩存的size因jre的版本不同是不一樣的。所以output如果不先初始化,input的構(gòu)造函數(shù)首先就無(wú)法正確運(yùn)行。

  對(duì)于上面兩個(gè)例子,第一個(gè)順序是嚴(yán)格的,第二個(gè)因?yàn)閛os和ois連接的已經(jīng)不是對(duì)方了,而是socket另外一端的流,需要嚴(yán)格按照另外一方對(duì)接的output流先于對(duì)接的input流打開(kāi)才能順利運(yùn)行。

  這個(gè)writeObject和readObject本身就是線(xiàn)程安全的,傳輸過(guò)程中是不允許被并發(fā)訪問(wèn)的。所以對(duì)象能一個(gè)一個(gè)接連不斷的傳過(guò)來(lái),有很多人在運(yùn)行的時(shí)候會(huì)碰到EOFException, 然后百思不得其解,去各種論壇問(wèn)解決方案。其實(shí)筆者這里想說(shuō),這個(gè)異常不是必須聲明的,也就是說(shuō)它雖然是異常,但其實(shí)是正常運(yùn)行結(jié)束的標(biāo)志。EOF表示讀到了文件尾,發(fā)送結(jié)束自然連接也就斷開(kāi)了。如果這影響到了你程序的正確性的話(huà),請(qǐng)各位靜下心來(lái)看看自己程序的業(yè)務(wù)邏輯,而不要把注意力狹隘的聚集在發(fā)送和接受的方法上。因?yàn)楣P者也被這樣的bug困擾了1整天,被很多論壇的帖子誤解了很多次最后得出的教訓(xùn)。如果在while循環(huán)中去readObject,本質(zhì)上是沒(méi)有問(wèn)題的,有對(duì)象數(shù)據(jù)來(lái)就會(huì)讀,沒(méi)有就自動(dòng)阻塞。那么拋出EOFException一定是因?yàn)檫B接斷了還在繼續(xù)read,什么原因?qū)е逻B接斷了呢?一定是業(yè)務(wù)邏輯哪里存在錯(cuò)誤,比如NullPoint、ClassCaseException、ArrayOutofBound,即使程序較大也沒(méi)關(guān)系,最多只要單步調(diào)適一次就能很快發(fā)現(xiàn)bug并且解決它。

  難怪一位程序大師說(shuō)過(guò):解決問(wèn)題90%靠經(jīng)驗(yàn),5%靠技術(shù),剩下5%靠運(yùn)氣!真是金玉良言,筆者大概查閱過(guò)不下30篇討論在while循環(huán)中使用 readObject拋出EOFExceptionde 的帖子,大家都盲目的去關(guān)注解釋這個(gè)名詞、反序列化的行為或反對(duì)這樣寫(xiě)而沒(méi)有一個(gè)人認(rèn)為EOF是正確的行為,它其實(shí)很老實(shí)的在做它的事情。為什么大家都忽略了真正出錯(cuò)誤的地方呢?兩個(gè)字,經(jīng)驗(yàn)!

  2.關(guān)于Java的多線(xiàn)程編程

  關(guān)于Java的線(xiàn)程,初學(xué)或者接觸不深的大概也能知道一些基本概念,同時(shí)又會(huì)很迷惑線(xiàn)程到底是怎么回事?如果有人認(rèn)為自己已經(jīng)懂了不妨來(lái)回答下面的問(wèn)題:

  a. A對(duì)象實(shí)現(xiàn)Runnable接口,A.start()運(yùn)行后所謂的線(xiàn)程對(duì)象是誰(shuí)?是A么?

  b. 線(xiàn)程的wait()、notify()方法到底是做什么時(shí)候用的,什么時(shí)候用?

  c. 為什么線(xiàn)程的suspend方法會(huì)被標(biāo)注過(guò)時(shí),不推薦再使用,線(xiàn)程還能掛起么?

  d. 為了同步我們會(huì)對(duì)線(xiàn)程方法聲明Synchronized來(lái)加鎖在對(duì)象上,那么如果父類(lèi)的f()方法加了Synchronized,子類(lèi)重寫(xiě)f()方法必須也加Synchronized么?如果子類(lèi)的f()方法重寫(xiě)時(shí)聲明Synchronized并調(diào)用super.f(),那么子類(lèi)對(duì)象上到底有幾把鎖呢?會(huì)因?yàn)楦?jìng)爭(zhēng)產(chǎn)生死鎖么?

  呵呵,各位能回答上來(lái)幾道呢?如果這些都能答上來(lái),說(shuō)明對(duì)線(xiàn)程的概念還是滿(mǎn)清晰的,雖說(shuō)還遠(yuǎn)遠(yuǎn)不能算精通。筆者這里一一做回答,礙于篇幅的原因,筆者盡量說(shuō)得簡(jiǎn)介一點(diǎn),如果大家有疑惑的歡迎一起討論。

  首先第一點(diǎn),線(xiàn)程跟對(duì)象完全是兩回事,雖然我們也常說(shuō)線(xiàn)程對(duì)象。但當(dāng)你用run()和start()來(lái)啟動(dòng)一個(gè)線(xiàn)程之后,線(xiàn)程其實(shí)跟這個(gè)繼承了 Thread或?qū)崿F(xiàn)了Runnable的對(duì)象已經(jīng)沒(méi)有關(guān)系了,對(duì)象只能算內(nèi)存中可用資源而對(duì)象的方法只能算內(nèi)存正文區(qū)可以執(zhí)行的代碼段而已。既然是資源和代碼段,另外一個(gè)線(xiàn)程當(dāng)然也可以去訪問(wèn),main函數(shù)執(zhí)行就至少會(huì)啟動(dòng)兩個(gè)線(xiàn)程,一個(gè)我們稱(chēng)之為主線(xiàn)程,還一個(gè)是垃圾收集器的線(xiàn)程,主線(xiàn)程結(jié)束就意味著程序結(jié)束,可垃圾收集器線(xiàn)程很可能正在工作。

  第二點(diǎn),wait()和sleep()類(lèi)似,都是讓線(xiàn)程處于阻塞狀態(tài)暫停一段時(shí)間,不同之處在于wait會(huì)釋放當(dāng)前線(xiàn)程占有的所有的鎖,而 sleep不會(huì)。我們知道獲得鎖的唯一方法是進(jìn)入了Synchronized保護(hù)代碼段,所以大家會(huì)發(fā)現(xiàn)只有Synchronized方法中才會(huì)出現(xiàn) wait,直接寫(xiě)會(huì)給警告沒(méi)有獲得當(dāng)前對(duì)象的鎖。所以notify跟wait配合使用,notify會(huì)重新把鎖還給阻塞的線(xiàn)程重而使其繼續(xù)執(zhí)行,當(dāng)有多個(gè)對(duì)象wait了,notify不能確定喚醒哪一個(gè),必經(jīng)鎖只有一把,所以一般用notifyAll()來(lái)讓它們自己根據(jù)優(yōu)先級(jí)等競(jìng)爭(zhēng)那唯一的一把鎖,競(jìng)爭(zhēng)到的線(xiàn)程執(zhí)行,其他線(xiàn)程只要繼續(xù)wait。

  從前Java允許在一個(gè)線(xiàn)程之外把線(xiàn)程掛起,即調(diào)用suspend方法,這樣的操作是極不安全的。根據(jù)面向?qū)ο蟮乃枷朊總€(gè)對(duì)象必須對(duì)自己的行為負(fù)責(zé),而對(duì)自己的權(quán)力進(jìn)行封裝。如果任何外步對(duì)象都能使線(xiàn)程被掛起而阻塞的話(huà),程序往往會(huì)出現(xiàn)混亂導(dǎo)致崩潰,所以這樣的方法自然是被斃掉了啦。

  最后一個(gè)問(wèn)題比較有意思,首先回答的是子類(lèi)重寫(xiě)f()方法可以加Synchronized也可以不加,如果加了而且還內(nèi)部調(diào)用了super.f ()的話(huà)理論上是應(yīng)該對(duì)同一對(duì)象加兩把鎖的,因?yàn)槊看握{(diào)用Synchronized方法都要加一把,調(diào)用子類(lèi)的f首先就加了一把,進(jìn)入方法內(nèi)部調(diào)用父類(lèi)的 f又要加一把,加兩把不是互斥的么?那么調(diào)父類(lèi)f加鎖不就必須永遠(yuǎn)等待已經(jīng)加的鎖釋放而造成死鎖么?實(shí)際上是不會(huì)的,這個(gè)機(jī)制叫重進(jìn)入,當(dāng)父類(lèi)的f方法試圖在本對(duì)象上再加一把鎖的時(shí)候,因?yàn)楫?dāng)前線(xiàn)程擁有這個(gè)對(duì)象的鎖,也可以理解為開(kāi)啟它的鑰匙,所以同一個(gè)線(xiàn)程在同一對(duì)象上還沒(méi)釋放之前加第二次鎖是不會(huì)出問(wèn)題的,這個(gè)鎖其實(shí)根本就沒(méi)有加,它有了鑰匙,不管加幾把還是可以進(jìn)入鎖保護(hù)的代碼段,暢通無(wú)阻,所以叫重進(jìn)入,我們可以簡(jiǎn)單認(rèn)為第二把鎖沒(méi)有加上去。

  總而言之,Synchronized的本質(zhì)是不讓其他線(xiàn)程在同一對(duì)象上再加一把鎖。

【編輯推薦】

  1. 新手入門(mén):學(xué)習(xí)Java的一點(diǎn)經(jīng)驗(yàn)心得
  2. 61條Java面向?qū)ο笤O(shè)計(jì)的經(jīng)驗(yàn)原則
  3. 經(jīng)驗(yàn)分享:我的JavaEE學(xué)習(xí)道路
  4. Java對(duì)象類(lèi)型轉(zhuǎn)換的四個(gè)經(jīng)驗(yàn)
責(zé)任編輯:韓亞珊 來(lái)源: CSDN
相關(guān)推薦

2011-03-31 13:52:22

Java

2011-03-31 16:26:28

Java

2011-03-31 13:32:13

Java

2011-03-31 13:56:24

Java

2011-03-31 14:49:35

2011-03-31 15:36:02

Java

2011-03-31 16:44:43

Java

2011-03-31 16:49:40

Java

2011-04-07 13:18:00

管理軟件項(xiàng)目項(xiàng)目

2009-10-29 16:57:05

Oracle傳輸表空間

2018-06-19 08:12:55

2014-05-28 10:55:11

Windows XP安全補(bǔ)丁

2010-07-21 14:05:31

2011-06-22 15:04:28

JAVA

2010-08-18 14:19:01

無(wú)線(xiàn)路由器

2009-09-28 10:52:00

CCNA考試經(jīng)驗(yàn)CCNA

2009-12-07 11:11:46

PHP顯示圖片

2009-12-16 16:37:59

Ruby on Rai

2009-12-25 09:44:52

WPF窗口設(shè)置

2009-10-15 10:59:00

CCNA經(jīng)驗(yàn)分享CCNA
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)