清華大學《Java語言程式設計進階》公開課總結
點選檢視:原文
本文是清華大學許斌老師的公開課:Java語言程式設計進階 的課堂筆記,快速複習一下,時間有限,因此大量直接截圖。許斌老師宣告:沒有配套講義,建議參考書籍:周志明《深入理解java虛擬機器》。(JUC) java.utile.concurrency 部分參考原始碼和技術部落格。
第一章 執行緒(上)
1.0 導學
1.1 執行緒的基本概念
1.2 通過Thread類建立執行緒
1.3 執行緒的休眠
注:執行緒休眠的原因就是讓其他執行緒有執行的機會
1.4 Thread類詳解
注:執行緒啟動(即呼叫start方法)並不意味著執行緒馬上執行,執行緒是否執行取決於執行緒排程器。
1.5 通過Runnable介面建立執行緒
注:Runnable介面中我們所實現的run方法就是我們這個執行緒想要執行的程式碼
1.6 執行緒內部的資料共享
同樣一個執行緒類,它可以例項化出很多執行緒。同樣一個執行緒,它們是可以共享它們的程式碼和資料,那也就是說當我們實現了Runnable介面的這個類,它所例項出來的物件的話,它去構造出的執行緒,它們之間是可以共享它們的程式碼和它們之間的一些資料的。
小結
第二章 執行緒(中)
2.0 導學
2.1 執行緒同步的思路
注:那原因就是在於說這兩個執行緒的話,它們是同一優先順序,只不過是說這個producer先這個排在前面,所以的話從排程上,往往會排程它這個producer先執行,那它一執行呢就把這個票都生產完了,然後再等待著賣票的程式把它去賣掉,這是一種有意思的這個現象
2.2 執行緒同步的實現方式—Synchronization
注:把這兩行程式碼變成一個(原子)操作,就是在執行過程中不可能被打散執行
注:用synchronized後面大括號括起來其實是程式碼,實際上它把它變成一個原子操作,也就是說當我拿到這個物件t的鎖的時候,我這裡面的這些程式碼是肯定都會被執行的,不會說我執行某一句以後就被這個打斷,然後那個插入別的執行緒去執行去訪問這個物件t,所以這個是synchronized它的很重要的作用。
就像剛才我們那個例子:我們在這個售票執行緒裡面,每售出來票的時候,它就會休眠一毫秒,但休眠一毫秒的時候,它不會釋放出它所佔有的這個ticket物件的鎖的,它一直會持有,所以這是一個獨特的一個地方。
2.3 執行緒的等待與喚醒
注:那現在wait notify notifyAll方法這三個方法都屬於object這個類的方法,也就意味著我們java當中所有的類它都有這個三個方法
注:修改之後,相當於票箱大小為1,Tickets.size = 1。Tickets.put() 方法中的 notify() 與 Tickets.sell() 方法中的wait()一一對應,Tickets.put() 方法中的 wait() 與 Tickets.sell() 方法中的notify()一一對應。
2.4 後臺程序
2.5 執行緒的生命週期與死鎖
注:執行緒進入就緒狀態就是runnable state,即可執行狀態,但是並未開始執行,所以不是執行狀態(running state),是否執行取決於執行緒排程器是否排程它。(Runnable state isn’t running state)。
2.6 執行緒的排程
注:可以通過這個使用這個yield的方法來去稍微改變一下它的這個執行過程,yield方法主要作用是把自己當前執行的執行緒暫停下來,把執行緒讓給同優先順序的執行緒執行,當如果這時候不存在同優先順序的執行緒,那還是繼續執行當前執行的執行緒。
注:有交錯執行的這個過程,重要的原因:執行緒呼叫sleep方法,sleep方法是說我自己進入休眠,執行緒排程器有可能排程低優先順序的這個執行緒,也就是說對高優先順序的這個執行緒,如果要讓出自己的執行許可權的話,就要呼叫sleep方法,然後給其它低優先順序執行緒機會。如果高優先順序的執行緒,僅僅只是呼叫了yield方法,它並不能給我們低優先順序執行緒以執行的機會,它只給了它同優先順序的執行緒以執行的這個機會。
小結
第三章 執行緒(下)執行緒安全與鎖優化
3.0 導學
注:它是想描述執行緒的安全,而最重要的是描述你的程式,甚至你是某個類它的執行緒安全的特性。
3.1 執行緒安全與執行緒相容與對立
向大家展示一下,一些java API中類,它在碰到這個執行緒操作的時候,有可能產生執行緒出錯的這個情況。
執行過程當中它不經常出錯,但是偶爾也會出錯,出現了陣列下標越界的錯誤。最重要的原因:剛才有兩個執行緒Thread remove,Thread print這兩個執行緒都在同時訪問一個數據:vector,其中一個執行緒的操作:刪除我們相量中的元素,另外一個執行緒的操作讀取我們相量中的元素。大家看到這其實這兩個操作:是有點互逆的 互斥的,那在這個讀寫向量的過程當中就可能產生錯誤,那從我們發現了這個執行的結果當中也發現了這一點。
3.2 執行緒的安全實現-互斥同步
3.3 執行緒的安全實現-非阻塞同步
那其實大家也可以這麼理解,也就是說我們對於這種執行緒安全,就是對我們這個訪問物件的執行緒安全的這種控制不是放到我們當前count這個類,它的increment方法來去實現的而是已經放到底下的叫 Atomiclnteger 這個類來實現了,所以你就可以直接去呼叫它的這個方法來去實現加1的這個功能,那整體上我們這個新的類,class Counter就是這個類通過用 Atomiclnteger 來改進這類,它也是執行緒安全的,整體上也是執行緒安全的,只不過說當你寫這個類的時候,你不需要考慮自己去加上synchronized這樣的同步互斥的這種實現方式,而是通過直接使用了Atomiclnteger這樣一個本身就是執行緒安全的這個類,就能夠保證你的整個這個程式碼達到執行緒安全的目的。
3.4 執行緒的安全實現-無同步方案
注:Threadlocal是我們java當中的一個類,它是存在於java.lang這個預設這個包當中。
這個 SequenceNumber 的例項,通過用 ThreadLocal 的這個方式也能夠保證這三個執行緒來訪問同一資料的時候,沒有產生錯誤。這也是為什麼說,可以通過這個 ThreadLocal 就來去達到這個同步,就是說安全的這個目的。也不一定非得加個synchronize,因為如果一旦加了synchronize的話,效能可能會受到影響,如果能通過類似 ThreadLocal 這樣這種執行緒的本地儲存的方式來達到我們這個對於資料訪問安全的控制化,那就能提高這個程式程式碼的效能。
3.5 鎖優化
作業系統的堆疊與資料結構中堆疊概念參考:
注:由於細鎖太多,然後不斷切換執行緒的開銷反而降低了效能。
小結
- 執行緒安全指的是我們的訪問物件無論被多少個執行緒進行訪問都能夠保證我們這物件訪問的正確性,那與之相關的這個概念是執行緒相容。
- 執行緒相容是指我們的物件本身不是執行緒安全的,但是通過我們外部的同步控制能夠達到執行緒安全的目的.
- 執行緒對立指的是我們的訪問物件,它本身不是執行緒安全,那我們外部即使加上了同步的控制也不能保證這個物件的這個正確性。
- 我們還學習實現執行緒安全的幾種方式
- 首先是互斥同步
- 其次是非阻塞同步
- 無同步方案
- 最後我們還學習了鎖優化,那鎖優化的目標就是在我們不得不給我們的程式碼加鎖的情況下如何去提高鎖的效率,進而達到提升整個程式碼的效率的目標。
第四章 網路程式設計(上)
4.0 導學
4.1 URL物件
注:保留埠號是計算機系統進行網路互動需要的埠號,自己編寫程式不要去佔用這些保留埠號,具體保留埠號對應網路服務google一下。
4.2 URLConnection物件
4.3 Get請求與Post請求
4.4 Socket通訊原理
4.5 Socket通訊實現
accept這個方法屬於ServerSocket方法,這種方法我們稱之它為阻塞方法,就是說它是在那裡執行一直等著有客戶端來給它傳送Socket連線請求,如果沒有客戶端給我們的服務端傳送這個Socket連線請求accept就一直在那裡迴圈執行一直不返回,一直等到有客戶端的Socket發連線請求過來。那我們這服務端的 ServerSocket 這個物件的話它就會accept方法就會返回一個值,返回的是一個Socket物件,而這個Socket物件就是和我們客戶端的Socket物件進行對應的。
注:那需要提醒大家注意是我們這個程式非常簡單,簡單到什麼程度呢?就是說聊天的時候,都是你說一句 我說一句如果一個想連續說兩句話的話可能現有這個機制還處理不過來,必須是一人一句,當然我們同學可以把這個程式再進一步改進使它更加的豐富。
小結
第五章 網路程式設計(下)
5.0 導學
5.1 Socket 多客戶端通訊實現
注:先執行server執行緒,再執行client。
5.2 資料報通訊
one-liners.txt這個是構造了一個檔案輸入流,因為我們做了一個非常簡單的模擬,也就是說把一些股票資訊就寫到這個檔案裡面了,寫到這個檔案裡面了以後就是每次有客戶端發過來請求,說諮詢一下股票的價格的時候,我們就從這個檔案裡讀出某一股票的價格在返還給我們的客戶端。
那剛才這個程式當中客戶端服務端各一個程式,客戶端和服務端之間的通訊是通過資料報這個Socket來進行通訊的然後整個過程就非常類似於,我們人類進行平信這個通訊方式,也就是說客戶端通過構造一個DatagramPacket這個物件向它寫一封信,然後通過DatagramSocket的send方法把它發出去了,服務端收到了這封來信以後,通過這個來信知道了客戶端的地址和埠號,然後服務端它自己也寫一封信,說白了寫信就是構造一個DatagramPacket物件,寫好了以後,通過DatagramSocket的這個物件的send方法,把這個信再發出去又發還給客戶端,所以這個資料報包總結起來就非常類似於我們人類寫平信的這個過程。
5.3 使用資料報進行廣播通訊
5.4 網路聊天程式
那整個這個佈局其實大家採用一個BorderLayout就可以達到你的目標,那就是在BorderLayout的center中間那區域先放一個滾動面板,然後接著再放一個TextArea,然後在它的南部區域,我們先放一個Panel,緊接著再放一個TextView文字輸入區域,然後接著再放一個Button而且TextView和Button的話都是按照FlowLayout這種放置規則。
大家需要這個寫的事件響應是什麼呢?其實首先最重要的是說我們能夠接收這個在文字區域,就是最下面這個文字區域這個輸入的文字,我們可以給TextView這個元件來註冊一個監聽器,當我們這個一回車就在TextView裡面一輸入字元一回車的時候,它產生的是一個ActionEvent,所以我們可以給TextView註冊一個EventListener。那TextView旁邊的話,是一個按鈕傳送,其實發送的話它所對應的這個事件處理也是ActionEvent,所以在這個例子當中我們只需要寫一個事件處理類然後都分別這個授權來去處理TextView和我們按鈕的這麼這個事件處理就可以完成獲得我們這個文字的這麼一個過程以及把它傳送的一個過程。那在這裡面怎麼去獲得內容呢?TextView裡面有個一個getText的方法,那我們只要在我們的ActionPerform方法裡面去通過TextView的getText來獲得它的內容然後來決定一個是往外發送同時把它顯示到當前我們的這個介面上面。
小結
第六章 java虛擬機器
6.0 導學
6.1 Java虛擬機器概念
6.2 Java虛擬機器記憶體劃分
本地方法(native method)它不一定是拿Java語言來編寫的方法,Java虛擬機器是會執行在不同的作業系統和硬體上面,那在本身Java虛擬機器的內部實現的時候,也會有一部分程式碼是執行的是原生代碼非Java這個程式碼,包括你們自己寫程式的時候,也可以比如用C或C加加,寫一段程式,最後把它嵌入到Java程式碼當中這也是可以的。這個本地方法棧主要是用來執行本地方法,它同樣有可能會丟擲異常,那所謂的丟擲異常的種類也和虛擬機器棧一樣,而我們的虛擬機器棧它的對應的功能主要是用來執行我們的Java方法。
6.3 Java虛擬機器類載入機制
比較舊的一些這個程式語言的經驗,當我們編譯完了以後可能還要做連結然後再執行,Java它有一個這個大的特點就是在程式執行過程當中來進行這個類的載入和連線,這樣的話就保證了,它這個一個程式執行的這個流暢和靈活性。
6.4 判斷物件是否存活演算法及物件引用
通過sf.get方法可以獲取到這個物件,當然當這個物件被標誌為需要回收的物件時,它就會返回的是空,所以說軟引用主要使用者來實現類似快取的功能,在記憶體足夠的情況下,我們可以直接通過軟引用來取值而不需要從繁忙的真實來源去查詢資料提升速度,那當記憶體不足的時候就會自動刪除這部分的快取資料,然後從真正的資料來源當中去查詢這些資料。
6.5 分代垃圾回收
注
- 將引用物件設定為空,這種方式來去釋放記憶體的話,應該沒什麼大問題,但如果我們用system gt方法去釋放記憶體的話會大大的影響我們的系統性能。
- 不可達含義:不用了,沒有引用鏈指向。看英文:unavailable 就明白了,沒有引用指向它們而且畢竟不屬於空閒區,當然就不可使用。
6.6 典型的垃圾收集演算法
6.7典型的垃圾收集器
今天介紹這幾種垃圾收集器一般說來它會影響到程式執行效能,尤其是當想編一些對效率要求非常高的Java程式的時候,比如說伺服器端的Java程式的時候,有時候你會比較顧及Java虛擬機器的垃圾回收效率是不是足夠那個幫助你的程式的執行,那據我所知國內外都有一些大公司在他們的伺服器端性質當中重新改寫了一些關於Java虛擬機器的裡面的垃圾回收的機制。
就舉一個例子來說:雙十一淘寶它的這個系統肯定就會承受著極大的這個使用者購買商品的點選的壓力,淘寶實際上它的很多後臺系統拿是拿Java寫的,所以為了提高這個Java在伺服器端的這種工作效率,那我聽說他們也是對於一些垃圾回收的這些機制進行了改進。在一些效能要求特別高的情況下的話,可能我們在伺服器端會對這些Java虛擬機器以及相應它的一些區域性做一些改進。
第七章 深入集合collection
7.0 導學
7.1 集合框架與ArrayList
7.2 LinkedList
7.3 HashMap與HashTable
可以看到這個HashMap底層陣列的長度它總是2的N次方,這就是為了保證陣列的使用率最高,儘可能的減少這個碰撞現象的產生,當HashMap中的元素越來越多的時候,這個雜湊衝撞的衝突的可能性也就越來越高,因為陣列的長度是固定的。那為了提高這查詢的效率就要對這個HashMap的陣列進行擴容容量變為原來的兩倍,這時候,原陣列當中的資料必須重新計算它在新陣列當中的位置,並且放進去,那這個過程呢就非常耗時。當HashMap中的元素個數超過陣列大小(取個名字叫lot fat),就會進行陣列的擴容,這個(lot fat)的預設值為0.75。那這個是一個非常消耗效能的操作所以如果我們已經預知這個HashMap當中元素的個數,那麼就能夠有效的提高HashMap的效能,所以這也是一個HashMap它的一個獨特的地方。
7.4 TreeMap與LinkedHashMap
所以說它和之前的那個HashMap的區別就是:HashMap裡面的資料結構第一級結構是一個數組,第二級結構是一個