1. 程式人生 > >清華大學《Java語言程式設計進階》公開課總結

清華大學《Java語言程式設計進階》公開課總結

點選檢視:原文
本文是清華大學許斌老師的公開課:Java語言程式設計進階 的課堂筆記,快速複習一下,時間有限,因此大量直接截圖。許斌老師宣告:沒有配套講義,建議參考書籍:周志明《深入理解java虛擬機器》。(JUC) java.utile.concurrency 部分參考原始碼和技術部落格。

第一章 執行緒(上)

1.0 導學

1539008813620

1539008859039

1.1 執行緒的基本概念

1539009969070

1539009984077

1539009143304

1539009203189

1539009430772

1539009574503

1539009665675

1.2 通過Thread類建立執行緒

1539009918717

1539406861072

1539406869998

1539406876613

1539406882916

1539406887715

1539406895994

1.3 執行緒的休眠

1539010059187

1539010375863

1539010405934

1539010618493

1539011791263

1539011800469

1539011806430

:執行緒休眠的原因就是讓其他執行緒有執行的機會

1.4 Thread類詳解

1539012104103

1539012342296

:執行緒啟動(即呼叫start方法)並不意味著執行緒馬上執行,執行緒是否執行取決於執行緒排程器。

1539012415734

1.5 通過Runnable介面建立執行緒

1539012516154

1539012651662

1539012759620

1539012814520

1539012944363

1539012958930

1539013125468

:Runnable介面中我們所實現的run方法就是我們這個執行緒想要執行的程式碼

1.6 執行緒內部的資料共享

同樣一個執行緒類,它可以例項化出很多執行緒。同樣一個執行緒,它們是可以共享它們的程式碼和資料,那也就是說當我們實現了Runnable介面的這個類,它所例項出來的物件的話,它去構造出的執行緒,它們之間是可以共享它們的程式碼和它們之間的一些資料的。

1539013882402

1539012958930

1539014130891

1539014260700

1539014850716

1539014878920

1539016663199

小結

1539016705556

第二章 執行緒(中)

2.0 導學

1539016795632

1539016830468

2.1 執行緒同步的思路

1539017054833

1539017181751

1539017224926

1539017381221

1539017485915

1539017568234

1539017702394

1539017744493

:那原因就是在於說這兩個執行緒的話,它們是同一優先順序,只不過是說這個producer先這個排在前面,所以的話從排程上,往往會排程它這個producer先執行,那它一執行呢就把這個票都生產完了,然後再等待著賣票的程式把它去賣掉,這是一種有意思的這個現象

1539017987439

2.2 執行緒同步的實現方式—Synchronization

1539018289399

1539018392108

1539018487545

1539018879503

:把這兩行程式碼變成一個(原子)操作,就是在執行過程中不可能被打散執行

1539019284302

:用synchronized後面大括號括起來其實是程式碼,實際上它把它變成一個原子操作,也就是說當我拿到這個物件t的鎖的時候,我這裡面的這些程式碼是肯定都會被執行的,不會說我執行某一句以後就被這個打斷,然後那個插入別的執行緒去執行去訪問這個物件t,所以這個是synchronized它的很重要的作用。

1539019370141

1539019483438

1539019531529

1539019552318

1539019688049

就像剛才我們那個例子:我們在這個售票執行緒裡面,每售出來票的時候,它就會休眠一毫秒,但休眠一毫秒的時候,它不會釋放出它所佔有的這個ticket物件的鎖的,它一直會持有,所以這是一個獨特的一個地方。

1539023144629

2.3 執行緒的等待與喚醒

1539071230986

1539071238290

:那現在wait notify notifyAll方法這三個方法都屬於object這個類的方法,也就意味著我們java當中所有的類它都有這個三個方法

1539071537462

:修改之後,相當於票箱大小為1,Tickets.size = 1。Tickets.put() 方法中的 notify() 與 Tickets.sell() 方法中的wait()一一對應,Tickets.put() 方法中的 wait() 與 Tickets.sell() 方法中的notify()一一對應。

1539071636937

2.4 後臺程序

1539072724499

1539072801199

2.5 執行緒的生命週期與死鎖

1539076855969

1539076979258

:執行緒進入就緒狀態就是runnable state,即可執行狀態,但是並未開始執行,所以不是執行狀態(running state),是否執行取決於執行緒排程器是否排程它。(Runnable state isn’t running state)。

1539077334242

1539077435366

1539077461022

1539077569978

1539077751809

1539077820164

1539077847191

1539077924190

1539077981985

2.6 執行緒的排程

1539073197605

1539073339084

1539073553254

:可以通過這個使用這個yield的方法來去稍微改變一下它的這個執行過程,yield方法主要作用是把自己當前執行的執行緒暫停下來,把執行緒讓給同優先順序的執行緒執行,當如果這時候不存在同優先順序的執行緒,那還是繼續執行當前執行的執行緒。

1539073606722

1539075549275

1539075786770

1539075932520

1539075996274

1539076123946

1539076577555

:有交錯執行的這個過程,重要的原因:執行緒呼叫sleep方法,sleep方法是說我自己進入休眠,執行緒排程器有可能排程低優先順序的這個執行緒,也就是說對高優先順序的這個執行緒,如果要讓出自己的執行許可權的話,就要呼叫sleep方法,然後給其它低優先順序執行緒機會。如果高優先順序的執行緒,僅僅只是呼叫了yield方法,它並不能給我們低優先順序執行緒以執行的機會,它只給了它同優先順序的執行緒以執行的這個機會。

小結

1539076703328

第三章 執行緒(下)執行緒安全與鎖優化

3.0 導學

1539078195419

:它是想描述執行緒的安全,而最重要的是描述你的程式,甚至你是某個類它的執行緒安全的特性。

3.1 執行緒安全與執行緒相容與對立

1539092094328

1539092137232

1539092210369

1539093903103

1539093969693

向大家展示一下,一些java API中類,它在碰到這個執行緒操作的時候,有可能產生執行緒出錯的這個情況。

1539094981555

1539095091501

執行過程當中它不經常出錯,但是偶爾也會出錯,出現了陣列下標越界的錯誤。最重要的原因:剛才有兩個執行緒Thread remove,Thread print這兩個執行緒都在同時訪問一個數據:vector,其中一個執行緒的操作:刪除我們相量中的元素,另外一個執行緒的操作讀取我們相量中的元素。大家看到這其實這兩個操作:是有點互逆的 互斥的,那在這個讀寫向量的過程當中就可能產生錯誤,那從我們發現了這個執行的結果當中也發現了這一點。

1539095449832

1539095474977

1539095546295

3.2 執行緒的安全實現-互斥同步

1539099909957

1539100009472

1539100178410

1539100716303

1539100471798

3.3 執行緒的安全實現-非阻塞同步

1539101286254

1539101341800

1539101432019

1539101645384

那其實大家也可以這麼理解,也就是說我們對於這種執行緒安全,就是對我們這個訪問物件的執行緒安全的這種控制不是放到我們當前count這個類,它的increment方法來去實現的而是已經放到底下的叫 Atomiclnteger 這個類來實現了,所以你就可以直接去呼叫它的這個方法來去實現加1的這個功能,那整體上我們這個新的類,class Counter就是這個類通過用 Atomiclnteger 來改進這類,它也是執行緒安全的,整體上也是執行緒安全的,只不過說當你寫這個類的時候,你不需要考慮自己去加上synchronized這樣的同步互斥的這種實現方式,而是通過直接使用了Atomiclnteger這樣一個本身就是執行緒安全的這個類,就能夠保證你的整個這個程式碼達到執行緒安全的目的。

3.4 執行緒的安全實現-無同步方案

1539102939632

:Threadlocal是我們java當中的一個類,它是存在於java.lang這個預設這個包當中。

1539103649773

1539103656234

這個 SequenceNumber 的例項,通過用 ThreadLocal 的這個方式也能夠保證這三個執行緒來訪問同一資料的時候,沒有產生錯誤。這也是為什麼說,可以通過這個 ThreadLocal 就來去達到這個同步,就是說安全的這個目的。也不一定非得加個synchronize,因為如果一旦加了synchronize的話,效能可能會受到影響,如果能通過類似 ThreadLocal 這樣這種執行緒的本地儲存的方式來達到我們這個對於資料訪問安全的控制化,那就能提高這個程式程式碼的效能。

3.5 鎖優化

1539104257575

1539104378267

1539104424027

1539104476304

作業系統的堆疊與資料結構中堆疊概念參考:

1539105602554

:由於細鎖太多,然後不斷切換執行緒的開銷反而降低了效能。

1539105752008

小結

1539105852330

  • 執行緒安全指的是我們的訪問物件無論被多少個執行緒進行訪問都能夠保證我們這物件訪問的正確性,那與之相關的這個概念是執行緒相容。
  • 執行緒相容是指我們的物件本身不是執行緒安全的,但是通過我們外部的同步控制能夠達到執行緒安全的目的.
  • 執行緒對立指的是我們的訪問物件,它本身不是執行緒安全,那我們外部即使加上了同步的控制也不能保證這個物件的這個正確性。
  • 我們還學習實現執行緒安全的幾種方式
    • 首先是互斥同步
    • 其次是非阻塞同步
    • 無同步方案
  • 最後我們還學習了鎖優化,那鎖優化的目標就是在我們不得不給我們的程式碼加鎖的情況下如何去提高鎖的效率,進而達到提升整個程式碼的效率的目標。

第四章 網路程式設計(上)

4.0 導學

1539244505401

1539244534446

1539244801576

4.1 URL物件

1539245451379

注:保留埠號是計算機系統進行網路互動需要的埠號,自己編寫程式不要去佔用這些保留埠號,具體保留埠號對應網路服務google一下。

1539245767019

1539245834109

1539245898509

1539245956762

1539245984052

1539246010514

1539246052077

4.2 URLConnection物件

1539246211340

1539246251876

1539246318190

4.3 Get請求與Post請求

1539246522880

1539246527495

1539246570432

1539246720288

1539246836812

1539246936840

4.4 Socket通訊原理

1539248246737

1539248277357

1539248323241

1539248356777

1539248563289

4.5 Socket通訊實現

1539249189011

1539249549584

1539249542348

accept這個方法屬於ServerSocket方法,這種方法我們稱之它為阻塞方法,就是說它是在那裡執行一直等著有客戶端來給它傳送Socket連線請求,如果沒有客戶端給我們的服務端傳送這個Socket連線請求accept就一直在那裡迴圈執行一直不返回,一直等到有客戶端的Socket發連線請求過來。那我們這服務端的 ServerSocket 這個物件的話它就會accept方法就會返回一個值,返回的是一個Socket物件,而這個Socket物件就是和我們客戶端的Socket物件進行對應的。

1539249811812

1539249848946

1539250143290

1539250150533

1539250156213

1539252104203

1539252110980

1539252121234

1539252126376

1539252147933

:那需要提醒大家注意是我們這個程式非常簡單,簡單到什麼程度呢?就是說聊天的時候,都是你說一句 我說一句如果一個想連續說兩句話的話可能現有這個機制還處理不過來,必須是一人一句,當然我們同學可以把這個程式再進一步改進使它更加的豐富。

小結

1539252275033

第五章 網路程式設計(下)

5.0 導學

1539254072310

5.1 Socket 多客戶端通訊實現

1539254198089

1539254477911

1539254535776

1539254560475

1539254578716

1539254484574

:先執行server執行緒,再執行client。

5.2 資料報通訊

1539267932034

1539267969444

1539268051255

1539268477916

1539268866026

1539268872283

1539268971931

one-liners.txt這個是構造了一個檔案輸入流,因為我們做了一個非常簡單的模擬,也就是說把一些股票資訊就寫到這個檔案裡面了,寫到這個檔案裡面了以後就是每次有客戶端發過來請求,說諮詢一下股票的價格的時候,我們就從這個檔案裡讀出某一股票的價格在返還給我們的客戶端。

1539270238283

1539270248439

1539270313592

1539270333292

1539270367641

那剛才這個程式當中客戶端服務端各一個程式,客戶端和服務端之間的通訊是通過資料報這個Socket來進行通訊的然後整個過程就非常類似於,我們人類進行平信這個通訊方式,也就是說客戶端通過構造一個DatagramPacket這個物件向它寫一封信,然後通過DatagramSocket的send方法把它發出去了,服務端收到了這封來信以後,通過這個來信知道了客戶端的地址和埠號,然後服務端它自己也寫一封信,說白了寫信就是構造一個DatagramPacket物件,寫好了以後,通過DatagramSocket的這個物件的send方法,把這個信再發出去又發還給客戶端,所以這個資料報包總結起來就非常類似於我們人類寫平信的這個過程。

5.3 使用資料報進行廣播通訊

1539271072535

1539271612788

1539271626548

1539271671371

1539271676934

1539271843572

1539271849995

5.4 網路聊天程式

1539279041381

那整個這個佈局其實大家採用一個BorderLayout就可以達到你的目標,那就是在BorderLayout的center中間那區域先放一個滾動面板,然後接著再放一個TextArea,然後在它的南部區域,我們先放一個Panel,緊接著再放一個TextView文字輸入區域,然後接著再放一個Button而且TextView和Button的話都是按照FlowLayout這種放置規則。

大家需要這個寫的事件響應是什麼呢?其實首先最重要的是說我們能夠接收這個在文字區域,就是最下面這個文字區域這個輸入的文字,我們可以給TextView這個元件來註冊一個監聽器,當我們這個一回車就在TextView裡面一輸入字元一回車的時候,它產生的是一個ActionEvent,所以我們可以給TextView註冊一個EventListener。那TextView旁邊的話,是一個按鈕傳送,其實發送的話它所對應的這個事件處理也是ActionEvent,所以在這個例子當中我們只需要寫一個事件處理類然後都分別這個授權來去處理TextView和我們按鈕的這麼這個事件處理就可以完成獲得我們這個文字的這麼一個過程以及把它傳送的一個過程。那在這裡面怎麼去獲得內容呢?TextView裡面有個一個getText的方法,那我們只要在我們的ActionPerform方法裡面去通過TextView的getText來獲得它的內容然後來決定一個是往外發送同時把它顯示到當前我們的這個介面上面。

1539280107792

1539280120139

1539280125626

1539280132480

1539280143416

1539280148860

1539280153459

1539280162757

1539280172673

1539280181412

1539280189503

1539280194806

小結

1539279964634

第六章 java虛擬機器

6.0 導學

1539106278412

6.1 Java虛擬機器概念

1539152742070

1539152824180

1539152930663

1539152984208

1539153141326

6.2 Java虛擬機器記憶體劃分

1539158818149

1539160258794

1539160296855

本地方法(native method)它不一定是拿Java語言來編寫的方法,Java虛擬機器是會執行在不同的作業系統和硬體上面,那在本身Java虛擬機器的內部實現的時候,也會有一部分程式碼是執行的是原生代碼非Java這個程式碼,包括你們自己寫程式的時候,也可以比如用C或C加加,寫一段程式,最後把它嵌入到Java程式碼當中這也是可以的。這個本地方法棧主要是用來執行本地方法,它同樣有可能會丟擲異常,那所謂的丟擲異常的種類也和虛擬機器棧一樣,而我們的虛擬機器棧它的對應的功能主要是用來執行我們的Java方法。

1539160957650

1539161076357

6.3 Java虛擬機器類載入機制

1539161252058

比較舊的一些這個程式語言的經驗,當我們編譯完了以後可能還要做連結然後再執行,Java它有一個這個大的特點就是在程式執行過程當中來進行這個類的載入和連線,這樣的話就保證了,它這個一個程式執行的這個流暢和靈活性。

1539161369363

1539161595199

1539161500327

1539161553038

1539161763782

1539161758041

1539161925586

1539161967122

6.4 判斷物件是否存活演算法及物件引用

1539162253019

1539163215077

1539162910083

1539162974202

1539163015403

1539163248799

通過sf.get方法可以獲取到這個物件,當然當這個物件被標誌為需要回收的物件時,它就會返回的是空,所以說軟引用主要使用者來實現類似快取的功能,在記憶體足夠的情況下,我們可以直接通過軟引用來取值而不需要從繁忙的真實來源去查詢資料提升速度,那當記憶體不足的時候就會自動刪除這部分的快取資料,然後從真正的資料來源當中去查詢這些資料。

1539163344947

1539163385453

6.5 分代垃圾回收

1539163621558

  1. 將引用物件設定為空,這種方式來去釋放記憶體的話,應該沒什麼大問題,但如果我們用system gt方法去釋放記憶體的話會大大的影響我們的系統性能。
  2. 不可達含義:不用了,沒有引用鏈指向。看英文:unavailable 就明白了,沒有引用指向它們而且畢竟不屬於空閒區,當然就不可使用。

1539163888139

1539164010609

6.6 典型的垃圾收集演算法

1539164393543

1539164434403

1539164514978

1539164585155

1539164642112

1539164730132

1539164819538

1539165861048

6.7典型的垃圾收集器

1539166829998

1539166851653

1539166911602

1539166985009

1539167023486

今天介紹這幾種垃圾收集器一般說來它會影響到程式執行效能,尤其是當想編一些對效率要求非常高的Java程式的時候,比如說伺服器端的Java程式的時候,有時候你會比較顧及Java虛擬機器的垃圾回收效率是不是足夠那個幫助你的程式的執行,那據我所知國內外都有一些大公司在他們的伺服器端性質當中重新改寫了一些關於Java虛擬機器的裡面的垃圾回收的機制。

就舉一個例子來說:雙十一淘寶它的這個系統肯定就會承受著極大的這個使用者購買商品的點選的壓力,淘寶實際上它的很多後臺系統拿是拿Java寫的,所以為了提高這個Java在伺服器端的這種工作效率,那我聽說他們也是對於一些垃圾回收的這些機制進行了改進。在一些效能要求特別高的情況下的話,可能我們在伺服器端會對這些Java虛擬機器以及相應它的一些區域性做一些改進

第七章 深入集合collection

7.0 導學

1539167756540

7.1 集合框架與ArrayList

1539167879951

1539172675709

1539172739041

1539172833305

1539173020388

1539173539375

1539173752342

7.2 LinkedList

1539174547853

1539174562202

1539174689397

1539174707566

1539175102241

1539175158234

1539175293680

1539175387312

1539175494926

7.3 HashMap與HashTable

1539175639852

1539175684847

1539176066589

1539176310007

1539176528691

1539176623549

可以看到這個HashMap底層陣列的長度它總是2的N次方,這就是為了保證陣列的使用率最高,儘可能的減少這個碰撞現象的產生,當HashMap中的元素越來越多的時候,這個雜湊衝撞的衝突的可能性也就越來越高,因為陣列的長度是固定的。那為了提高這查詢的效率就要對這個HashMap的陣列進行擴容容量變為原來的兩倍,這時候,原陣列當中的資料必須重新計算它在新陣列當中的位置,並且放進去,那這個過程呢就非常耗時。當HashMap中的元素個數超過陣列大小(取個名字叫lot fat),就會進行陣列的擴容,這個(lot fat)的預設值為0.75。那這個是一個非常消耗效能的操作所以如果我們已經預知這個HashMap當中元素的個數,那麼就能夠有效的提高HashMap的效能,所以這也是一個HashMap它的一個獨特的地方。

1539177101407

1539177164867

7.4 TreeMap與LinkedHashMap

1539178600822

1539178636271

1539178843148

1539178868002

1539178948012

1539179258434

所以說它和之前的那個HashMap的區別就是:HashMap裡面的資料結構第一級結構是一個數組,第二級結構是一個