1. 程式人生 > >Java之web專案問答:Java基礎

Java之web專案問答:Java基礎

Java軟體開發工程師的專案經驗集錦:

1Java基礎

1.1 CollectionMap

(1)掌握CollectionMap的繼承體系。

(2)掌握ArrayList(陣列)LinkedList(連結串列)Vector(執行緒同步)Stack(繼承Vector先進後出的棧)PriorityQueue(優先順序堆的極大優先順序佇列)HashSetLinkedHashSet(連結串列+hash)TreeSet(Comparator比較器)HashMapLinkedHashMap(連結串列)TreeMap(Comparator比較器)WeakHashMap(

弱鍵à即沒用了就自動被GC回收)EnumMap(key不能為空,內部以陣列實現,效能更好)HashTable(執行緒同步)的特點和實現原理。

補充☆(3)掌握CopyOnWriteArrayListCopyOnWriteArraySetConcurrentHashMap的實現原理和適用場景。

CopyOnWrite容器即寫時複製的容器。通俗的理解是當我們往一個容器新增元素的時候,不直接往當前容器新增,而是先將當前容器進行Copy複製出一個新的容器,然後新的容器裡新增元素,新增完元素之後,再將原容器的引用指向新的容器。這樣做的好處是我們可以對CopyOnWrite容器進行併發的讀,而不需要加鎖

,因為當前容器不會新增任何元素。所以CopyOnWrite容器也是一種讀寫分離的思想,讀和寫不同的容器。

CopyOnWrite容器有很多優點,但是同時也存在兩個問題,即記憶體佔用問題和資料一致性問題。所以在開發的時候需要注意一下。

  記憶體佔用問題。因為CopyOnWrite的寫時複製機制,所以在進行寫操作的時候,記憶體裡會同時駐紮兩個物件的記憶體,舊的物件和新寫入的物件(注意:在複製的時候只是複製容器裡的引用,只是在寫的時候會建立新物件新增到新容器裡,而舊容器的物件還在使用,所以有兩份物件記憶體)。如果這些物件佔用的記憶體比較大,比如說200M左右,那麼再寫入100M資料進去,記憶體就會佔用

300M,那麼這個時候很有可能造成頻繁的Yong GCFull GC。之前我們系統中使用了一個服務由於每晚使用CopyOnWrite機制更新大物件,造成了每晚15秒的Full GC,應用響應時間也隨之變長。

  針對記憶體佔用問題,可以通過壓縮容器中的元素的方法來減少大物件的記憶體消耗,比如,如果元素全是10進位制的數字,可以考慮把它壓縮成36進位制或64進位制。或者不使用CopyOnWrite容器,而使用其他的併發容器,如ConcurrentHashMap

  資料一致性問題CopyOnWrite容器只能保證資料的最終一致性,不能保證資料的實時一致性。所以如果你希望寫入的的資料,馬上能讀到,請不要使用CopyOnWrite容器。

 

1.2 IO

掌握InputStreamOutputStreamReaderWriter的繼承體系。

 

IO流中的設計模式

1.IO中用到的介面卡模式

IO中,如將字串資料轉變成位元組資料儲存到檔案中,將位元組資料轉變成流資料等都用到了介面卡模式,下面以InputStreamReaderOutputStreamWriter類為例介紹介面卡模式。

 InputStreamReaderOutputStreamWriter類分別繼承了ReaderWriter介面,但要建立它們必須在建構函式中傳入一個InputStreamOutputStream的例項,InputStreamReaderOutputStreamWriter的作用也就是將InputStreamOutputStream適配到ReaderWriter

  InputStreamReader實現了Reader介面,並且持有了InputStream的引用,這是通過StreamDecoder類間接持有的,因為bytechar要經過編碼。

       這裡,介面卡就是InputStreamReader類,而源角色就是InputStream代表的例項物件,目標介面就是Reader類,OutputStreamWriter類也是類似的方式。

       IO中類似的還有,如StringReader將一個String類適配到Reader介面,ByteArrayInputStream介面卡將byte陣列適配到InputStream流處理介面。

2.IO中用到的裝飾模式

        裝飾模式就是對一個類進行裝飾,增強其方法行為,在裝飾模式中,作為原來的這個類使用者還不應該感受到裝飾前與裝飾後有什麼不同,否則就破壞了原有類的結構了,所以裝飾器模式要做到對被裝飾類的使用者透明,這是對裝飾器模式的一個要求。總之裝飾器設計模式就是對於原有功能的擴充套件

IO中有許多不同的功能組合情況,這些不同的功能組合都是使用裝飾器模式實現的,下面以FilterInputStream為例介紹裝飾器模式的使用。

InputStream類就是以抽象元件存在的,而FileInputStream就是具體元件,它實現了抽象元件的所有介面,FilterInputStream類就是裝飾角色,它實現了InputStream類的所有介面,並持有InputStream的物件例項的引用,BufferedInputStream是具體的裝飾器實現者,這個裝飾器類的作用就是使得InputStream讀取的資料儲存在記憶體中,而提高讀取的效能。類似的還有LineNumberInputStream類,它的作用是提高按行讀取資料的功能。

 

總結

    這兩種設計模式看起來都是起到包裝一個類或物件的作用,但是使用它 們的目的卻不盡相同。介面卡模式主要在於將一個介面轉變成另一個介面它的目的是通過改變介面來達到重複使用的目的;而裝飾器模式不是要改變被裝飾物件的介面,而是保持原有的介面但是增強原有物件的功能,或改變原有物件的方法而提高效能

補充☆(3) 高效能的IO體系

首先得明白什麼是同步,非同步,阻塞,非阻塞.

1,同步和非同步是針對應用程式和核心的互動而言的

2,阻塞和非阻塞是針對於程序在訪問資料的時候,根據IO操作的就緒狀態來採取的不同方式

總結一句簡短的話,同步和非同步是目的,阻塞和非阻塞是實現方式。

名詞解釋 

同步 指的是使用者程序觸發IO操作並等待或者輪詢的去檢視IO操作是否就緒 自己上街買衣服,自己親自幹這件事,別的事幹不了。 
2) 非同步 非同步是指使用者程序觸發IO操作以後便開始做自己的事情,而當IO操作已經完成的時候會得到IO完成的通知(非同步的特點就是通知) 告訴朋友自己合適衣服的尺寸,大小,顏色,讓朋友委託去賣,然後自己可以去幹別的事。(使用非同步IO時,JavaIO讀寫委託給OS處理,需要將資料緩衝區地址和大小傳給OS 
3) 阻塞 所謂阻塞方式的意思是指, 當試圖對該檔案描述符進行讀寫時, 如果當時沒有東西可讀,或者暫時不可寫, 程式就進入等待 狀態, 直到有東西可讀或者可寫為止 去公交站充值,發現這個時候,充值員不在(可能上廁所去了),然後我們就在這裡等待,一直等到充值員回來為止。(當然現實社會,可不是這樣,但是在計算機裡確實如此。) 
4) 非阻塞 非阻塞狀態下, 如果沒有東西可讀, 或者不可寫, 讀寫函式馬上返回, 而不會等待 銀行裡取款辦業務時,領取一張小票,領取完後我們自己可以玩玩手機,或者與別人聊聊天,當輪我們時,銀行的喇叭會通知,這時候我們就可以去了。

同步阻塞IOJAVA BIO): 
    同步並阻塞,伺服器實現模式為一個連線一個執行緒,即客戶端有連線請求時伺服器端就需要啟動一個執行緒進行處理,如果這個連線不做任何事情會造成不必要的執行緒開銷,當然可以通過執行緒池機制改善。 
同步非阻塞IO(Java NIO)  同步非阻塞,伺服器實現模式為一個請求一個執行緒,即客戶端傳送的連線請求都會註冊到多路複用器上,多路複用器輪詢到連線有I/O請求時才啟動一個執行緒進行處理。使用者程序也需要時不時的詢問IO操作是否就緒,這就要求使用者程序不停的去詢問。 
非同步阻塞IOJava NIO):  
   此種方式下是指應用發起一個IO操作以後,不等待核心IO操作的完成,等核心完成IO操作以後會通知應用程式,這其實就是同步和非同步最關鍵的區別,同步必須等待或者主動的去詢問IO是否完成,那麼為什麼說是阻塞的呢?因為此時是通過select系統呼叫來完成的,而select函式本身的實現方式是阻塞的,而採用select函式有個好處就是它可以同時監聽多個檔案控制代碼(如果從UNP的角度看,select屬於同步操作。因為select之後,程序還需要讀寫資料),從而提高系統的併發性!  
Java AIO(NIO.2))非同步非阻塞IO:  
   在此種模式下,使用者程序只需要發起一個IO操作然後立即返回,等IO操作真正的完成以後,應用程式會得到IO操作完成的通知,此時使用者程序只需要對資料進行處理就好了,不需要進行實際的IO讀寫操作,因為真正的IO讀取或者寫入操作已經由核心完成了。

 

1.3 異常

掌握Throwable繼承體系。

Java異常體系:

Throwable(異常和錯誤的頂層父類)

  |----- Error:錯誤類。表示的是程式在執行過程中出現的錯誤。錯誤的發生都屬於系統級別。(JVM是執行作業系統上,JVM操作記憶體是需要藉助作業系統,如果內在發生錯誤,會由作業系統反饋給JVM)

             通常在程式中發生錯誤的原因是因為程式在書寫時存在問題,而JVM執行有問題的程式碼就會引發記憶體出錯。解決錯誤的方案:修改原始碼

  |----- Exception:異常類。程式在執行過程中,出現了異常現象:陣列越界、型別轉換異常等。通常在程式中如果發生了異常,是有專門針對異常處理的方案(處理方案是由開發人員自己制定)

                 程式中異常的發生通常是因為程式在操作資料時引發的,解決異常的方案是:宣告、捕獲

                 (學習以Exception為主,開發也主要以Exception為主)

            提示:宣告最終還需要使用捕獲來處理異常

異常類的分類:

執行時異常:RuntimeException 

 

編譯時異常:Exception

異常的處理

宣告:其實就是程式中遇到異常時,自己不處理,交給其它程式處理

關鍵字:throws

捕獲:其實就是在程式中遇到異常時,不會交給其它程式處理,自己處理

關鍵字:try 、catch、finally

注意:1,在使用throw丟擲異常程式碼的後面,不能書寫任意程式碼。

      2,如果使用try...catch...finally結構的,catch中丟擲異常後面如果有其他語句,執行時先執行finally語句再去執行catch中的其他語句

      3try..catch..catch結構中必須按照子類到父類的順序寫

 

 

1.4 多執行緒

(1) 掌握Executors可以建立的三種執行緒池的特點及適用範圍。

1.繼承Thread類,重寫父類run()方法

2.實現runnable介面

3.使用ExecutorServiceCallableFuture實現有返回結果的多執行緒(JDK5.0以後)

(2) 多執行緒同步機制。

在需要同步的方法的方法簽名中加入synchronized關鍵字。

使用synchronized塊對需要進行同步的程式碼段進行同步。

使用JDK 5中提供的java.util.concurrent.lock包中的Lock物件。

一段synchronized的程式碼被一個執行緒執行之前,他要先拿到執行這段程式碼的許可權,在 java裡邊就是拿到某個同步物件的鎖(一個物件只有一把鎖); 如果這個時候同步物件的鎖被其他執行緒拿走了,他(這個執行緒)就只能等了(執行緒阻塞在鎖池 等待佇列中)。 取到鎖後,他就開始執行同步程式碼(被synchronized修飾的程式碼);執行緒執行完同步程式碼後馬上就把鎖還給同步物件,其他在鎖池中 等待的某個執行緒就可以拿到鎖執行同步程式碼了。這樣就保證了同步程式碼在統一時刻只有一個執行緒在執行。

(3)執行緒的幾種可用狀態。

執行緒在執行過程中,可以處於下面幾種狀態:

就緒(Runnable):執行緒準備執行,不一定立馬就能開始執行

執行中(Running)程序正在執行執行緒的程式碼。

等待中(Waiting):執行緒處於阻塞的狀態,等待外部的處理結束。

睡眠中(Sleeping):執行緒被強制睡眠

I/O阻塞(Blocked on I/O)等待I/O操作完成

同步阻塞(Blocked on Synchronization)等待獲取鎖

死亡(Dead)執行緒完成了執行

(4)什麼是死鎖(deadlock)

兩個程序都在等待對方執行完畢才能繼續往下執行的時候就發生了死鎖。結果就是兩個程序都陷入了無限的等待中

(5)如何確保N個執行緒可以訪問N個資源同時又不導致死鎖?

使用多執行緒的時候,一種非常簡單的避免死鎖的方式就是:指定獲取鎖的順序,並強制執行緒按照指定的順序獲取鎖。因此,如果所有的執行緒都是以同樣的順序加鎖和釋放鎖,就不會出現死鎖了。