疏漏總結(五)

1、線程池的最大核心線程數的意義

  1. 提交一個新的任務到線程池中首先線程池會判斷基本線程池(corePoolSize)是否已滿?沒滿的話會創建一個工作線程來執行任務。滿了進入下個流程;其次線程池判斷工作隊列(workQueue)是否已滿?沒滿的話將新提交的任務存儲在工作隊列裏面,滿了進入下個流程;最後線程池判斷整個線程池(maxmumPoolSize)是否已滿?沒滿的話創建一個新的工作線程來執行任務,滿了則交給飽和策略來處理這個任務;如果線程池中的線程數量大於corePoolSize時如果某線程空閒時間超過keepAliveTime,線程會被終止,直至線程池中的線程數目不大於corePoolSize;如果允許爲核心池中的線程設置存活時間那麼核心池中的線程空閒時間超過keepAliveTime線程會被終止。
  2. 飽和策略
    Abort策略:默認策略,新任務提交時直接拋出未檢查的異常RejectedExecutionException該異常可由調用者捕獲。
    CallerRuns策略:爲調節機制既不拋棄任務也不拋出異常,而是將某些任務回退到調用者。不會在線程池的線程中執行新的任務,而是在調用exector的線程中運行新的任務。
    Discard策略:新提交的任務被拋棄。

2、線程池的狀態

在這裏插入圖片描述
RUNNING
1、狀態說明:線程池處在RUNNING狀態時,能夠接收新任務,以及對已添加的任務進行處理。
2、狀態切換:線程池的初始化狀態是RUNNING。換句話說,線程池被一旦被創建,就處於RUNNING狀態,並且線程池中的任務數爲0!

SHUTDOWN
1、狀態說明:線程池處在SHUTDOWN狀態時,不接收新任務,但能處理已添加的任務。
2、狀態切換:調用線程池的shutdown()接口時,線程池由RUNNING -> SHUTDOWN。

STOP
1、狀態說明:線程池處在STOP狀態時,不接收新任務,不處理已添加的任務,並且會中斷正在處理的任務。
2、 狀態切換:調用線程池的shutdownNow()接口時,線程池由(RUNNING or SHUTDOWN ) -> STOP。

TIDYING
1、狀態說明:當所有的任務已終止,ctl記錄的”任務數量”爲0,線程池會變爲TIDYING狀態。當線程池變爲TIDYING狀態時,會執行鉤子函數terminated()。terminated()在ThreadPoolExecutor類中是空的,若用戶想在線程池變爲TIDYING時,進行相應的處理;可以通過重載terminated()函數來實現。
2、狀態切換:當線程池在SHUTDOWN狀態下,阻塞隊列爲空並且線程池中執行的任務也爲空時,就會由 SHUTDOWN -> TIDYING。
線程池在STOP狀態下,線程池中執行的任務爲空時,就會由STOP -> TIDYING。

TERMINATED
1、狀態說明:線程池徹底終止,就變成TERMINATED狀態。
2、狀態切換:線程池處在TIDYING狀態時,執行完terminated()之後,就會由 TIDYING -> TERMINATED。

3、http 1.1版本新特性

  1. 持久連接: 在HTTP1.1之前,無論什麼時候瀏覽器連接一個web服務器,當請求資源被髮送之後,連接就被服務器端關閉了。隨着互聯網進一步發展,請求的服務器資源種類越來越多,資源的越來越大,所以當一個頁面被請求的時候,瀏覽器需要下載頁面所引用的資源。如果加入頁面和所引用的資源使用不同的連接來下載的話,進程將會非常慢。HTTP1.1就是爲了解決這個問題,使用持久連接的時候,服務器並不關閉連接。這種情況下,頁面和所引用的資源使用同一個連接來下載,考慮到建立和接觸http連接的寶貴時間的話,這樣就節約了大量的時間。
  2. 塊編碼:建立持續連接的結果就是,同一個連接,服務器端可以從不同的資源發送字節流,客戶端可以使用發送多個請求。這樣發送端必須爲每個請求或者響應發送內容長度的頭部,以便知道收方如何解析這些字節。在content-length頭部不知道的情況下,在HTTP1.0中,服務器可以省略content-length頭部,並保持寫入連接,當寫入完成的時候,它將簡單的關閉連接。客戶端將會保持讀取狀態,直到讀取到-1,表示達到文件的尾部。在HTTP1.1中,使用一個特別的頭transfer-encoding來表示有多少塊形式的字節流將會被髮送。對於每塊來說,在數據之前,長度(十六進制)後邊跟着CR/LF將被髮送。整個事務通過一個零長度塊來標識。0\r\n標識這個事務的結束。
  3. 狀態100(持續狀態)的使用:在發送請求之前,HTTP 1.1客戶端可以發送Expect: 100-continue頭部到服務器,並等待服務器的確認。。這個一般發生在當客戶端需要發送一份長的請求內容而未能確保服務器願意接受它的時候。如果你 發送一份長的請求內容僅僅發現服務器拒絕了它,那將是一種浪費來的。當接受到Expect: 100-continue頭部的時候,假如樂意或者可以處理請求的話,服務器響應100-continue頭部,後邊跟着兩對CRLF字符。 HTTP/1.1 100 Continue。

4、何時需要rehash

單線程的ReHash

  • 用key mod一下表的大小(就是數組的長度)
  • 最上面的old hash表,其中Hash表的size=2,key=3,7,5在mod 2之後都衝突在table[1]這裏面
  • 接下來三個步驟是Hash表熱size成4,然後所有的<key, value>重新rehash過程

在這裏插入圖片描述
併發下的ReHash
1、假設現在有兩個線程,使用紅色和淺藍色標記一下:

do{
    Entry<K,V> next = e.next;// <--假設線程一執行到這裏就被調度掛起了
    inti = indexFor(e.hash, newCapacity);
    e.next = newTable[i];
    newTable[i] = e;
    e = next;
}while (e != null);

線程二執行完畢後,觀看下面例子:
在這裏插入圖片描述
注意因爲Thread1的e指向key(3),next指向key(7),其在線程二rehash後指向線程二重組的鏈表。

2、線程一被調用回來執行

  • 先執行new Table[i]=e;
  • 然後是e=next,導致e指向key(7)
  • 下一次循環的next=e.next導致next指向key(3)
    在這裏插入圖片描述
    3、線程一繼續執行
    把key(7)摘下來,放到newTable[i]的第一個,然後把e和next往下移
    在這裏插入圖片描述
    4、環形鏈表出現
    e.next = newTable[i] 導致 key(3).next 指向了 key(7)
    注意:此時的key(7).next 已經指向了key(3), 環形鏈表就這樣出現
    在這裏插入圖片描述
    如果這時線程一調用到HashTable.get(11)就會出現——Infinite Loop。

5、Full GC觸發條件

  1. System.gc()的調用
  2. 老年代空間不足
  3. 永久代空間不足
  4. CMS GC時出現promotion failed和concurrent mode failure
  5. 堆中分配很大的對象

6、何種場景需要自定義類加載器

  1. 修改類加載方式:類的加載模型並非強制,除Bootstrap外,其它的加載並非一定要引入,或者根據實際情況在某個時間點進行按需動態加載。
  2. 擴展加載源:比如從數據庫、網絡,甚至是電視機機頂盒進行加載。
  3. 防止源碼泄露。java代碼容易被編譯和篡改,可以進行編譯加密。那麼類加載器也需要自定義,還原加密的字節碼。
  4. 隔離加載類:在某些框架內進行中間件與應用的模塊隔離,把類加載到不同的環境。比如,某容器框架通過自定義類加載器確保應用中依賴的jar包不會影響到中間件運行時使用的jar包。(jar包之間的衝突的消除)

實現方法:繼承ClassLoader,重寫findClass()方法,調用defineClass()方法。

7、分段和分頁區別

1、目的
頁是信息的物理單位,分頁是爲實現離散分配方式,以消減內存的外零頭,提高內存的利用率。或者說分頁是處於系統管理的需要而不是用戶需要。

段是信息的邏輯單位,它含有一組其意義相對完整的信息。分段的目的是爲了更好地滿足用戶的需要。

2、長度
頁的大小固定而且由系統決定,由系統把邏輯地址劃分爲頁號和頁內地址兩部分,是由機器硬件實現的,因而在系統中只能有一種大小的頁面。

段的長度不固定,決定於用戶所編寫的程序,通常由編譯程序在對程序進行編譯時,根據信息的性質來劃分。

3、地址空間
頁的地址空間是一維的,即單一的線形地址空間,程序員只要利用一個記憶符就可以表示一個地址。

作業地址空間是二維的,程序員在標識一個地址時,既需要給出段名,又需給出段內地址。

4、碎片
分頁有內部碎片無外部碎片

分段有外部碎片無內部碎片

5、絕對地址
處理器使用頁號和偏移量計算絕對地址

處理器使用段號和偏移量計算絕對地址

6、管理方式
對於分頁,操作系統必須爲每個進程維護一個頁表,以說明每個頁對應的的頁框。當進程運行時,它的所有頁都必須在內存中,除非使用覆蓋技術或虛擬技術,另外操作系統需要維護一個空閒頁框列表。

對於分段,操作系統必須爲每個進程維護一個段表,以說明每個段的加載地址和長度。當進程運行時,它的所有短都必須在內存中,除非使用覆蓋技術或虛擬技術,另外操作系統需要維護一個內存中的空閒的空洞列表。

特別的當使用虛擬技術時候把一頁或一段寫入內存時候可能需要把一頁或幾個段寫入磁盤。

7、共享和動態鏈接
分頁不容易實現,分段容易實現。

8、最左前綴原則

MySQL中的索引可以以一定順序引用多列這種索引叫作聯合索引。如User表的name和city加聯合索引就是(name,city),而最左前綴原則指的是,如果查詢的時候查詢條件精確匹配索引的左邊連續一列或幾列,則此列就可以被用到。如下:

select * from user where name=xx and city=xx ; //可以命中索引
select * from user where name=xx ; // 可以命中索引
select * from user where city=xx ; // 無法命中索引            

注意查詢的時候如果兩個條件都用上了,但是順序不同,如 city= xx and name =xx,那麼現在的查詢引擎會自動優化爲匹配聯合索引的順序,這樣是能夠命中索引的。

由於最左前綴原則,在創建聯合索引時,索引字段的順序需要考慮字段值去重之後的個數,較多的放前面。ORDER BY子句也遵循此規則。

9、G1

此垃圾收集器適用於新生代和老年代,和其他老年代垃圾收集器相比有如下的特點:

  • 併發和並行:使用多個CPU來減少stop-the-world停止時間,多線程是併發執行的;
  • 分代收集:使用不同方式去處理,新創建出來的對象產生垃圾和已存在一段時間的對象產生的垃圾;
  • 空間整合:通過標記整理解決內存碎片的問題;
  • 可預測的停頓:使用戶指定在GC上消耗的時間,不超過設定的時間。

使用此垃圾收集器之後整個Java堆內存被劃分成多個大小相等的Region,新生代和老年代不是物理隔離的。
在這裏插入圖片描述
不需要一個連續的內存空間決定哪個是新生代哪個是老年代。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章