菜鳥的jdk源碼學(xué)習(xí)

java源碼學(xué)習(xí)饥追,(基于java version 1.8.0_60)

1.基礎(chǔ)部分(原理咕痛,運(yùn)用熟練掌握)

1.1java.util

   這個(gè)包主要以集合為主仿便,這是數(shù)據(jù)結(jié)構(gòu)的最佳實(shí)踐悯仙。
集合羅列
集合 查詢時(shí)間復(fù)雜度 繼承前列 線程安全 支持排序
Map HashMap LinkedHashMap HashTable TreeMap
Set HashSet LinkedHashSet TreeSet
~ 線程安全 繼承前列線程安全
List ArrayList LinkedList Vector Stack
相似比較
Name 同作用 不同作用
Iterator 支持遍歷 支持fail-fast[ConcurrentModificationException]機(jī)制囱修,通過迭代器可以對(duì)集合刪除;可以對(duì)集合進(jìn)行增強(qiáng)for循環(huán)遍歷【Iterable和Iterator一起使用捞烟,Iterable像管理者薄声,產(chǎn)生Iterator,Iterator負(fù)責(zé)執(zhí)行
Enumeration 支持遍歷
Map 支持key-value 功能強(qiáng)(官方建議使用map)
Dictionary 支持key-value 和map比較功能弱
Comparable 支持比較 實(shí)體直接實(shí)現(xiàn)
Comparator 支持比較 更靈活题画,實(shí)體可以實(shí)現(xiàn)多個(gè)

1.1.1Map相關(guān)

  • 這是集合中個(gè)人認(rèn)為是最關(guān)鍵最復(fù)雜的類默辨,搞清楚map的常用實(shí)現(xiàn)類是非常關(guān)鍵的對(duì)于認(rèn)識(shí)集合總體的實(shí)現(xiàn)。
  • 每個(gè)key苍息,value鍵值對(duì)封裝為Map.Entry<K, V> 實(shí)體bean缩幸。

1.1.1.1HashMap

  • 數(shù)據(jù)結(jié)構(gòu):Node實(shí)體數(shù)組(又叫Hash表或散列表,hash函數(shù)又叫散列函數(shù))+ 單向鏈表+紅黑樹(又叫自平衡二叉查找樹)竞思。
  • Node實(shí)體基本結(jié)構(gòu):hash,key,value,next(鏈表的下一個(gè)實(shí)體);Map.Entry<K, V> 實(shí)現(xiàn)類表谊。
  • TreeNode實(shí)體基本結(jié)構(gòu):parent,left,right,prev;TreeNode繼承LinkedHashMap.Entry繼承HashMap.Node<K,V>。
  • 數(shù)組上的元素為鏈表(或紅黑樹)的頭節(jié)點(diǎn)(或根節(jié)點(diǎn))盖喷。
  • 對(duì)于hash沖突解決辦法使用鏈表(或紅黑樹)爆办,當(dāng)鏈表長(zhǎng)度大于等于8時(shí)轉(zhuǎn)化為紅黑樹。之所以轉(zhuǎn)化為紅黑樹是當(dāng)數(shù)量大時(shí)紅黑樹的查詢效率更高课梳。
  • 操作紅黑樹距辆,增加刪除后為了自平衡 進(jìn)行的左右旋和重新著色。
幾種時(shí)間復(fù)雜度
結(jié)構(gòu) 查詢時(shí)間復(fù)雜度 說明
hash表 O(1)
鏈表 O(n) 遍歷鏈表去查找
紅黑樹 O(log n)
多線程下當(dāng)共享變量使用時(shí)暮刃,擴(kuò)容鏈表造成的問題
版本 元素是否倒置 元素是否丟失 復(fù)雜程度
1.7 倒置(易形成閉合回路) 沒驗(yàn)證 代碼量約1000行
1.8 不倒置(99%的認(rèn)為不會(huì)形成挑格,1%再驗(yàn)證) 會(huì)丟失 代碼量約2000行
解決辦法 不當(dāng)共享變量使用(在局部變量中 new創(chuàng)建 是沒問題的,在棧中操作沾歪,屬于私有的)或使用Collections.synchronizedMap(Map<K, V>)包裝或使用ConcurrentHashMap
1.1.1.2HashTable
  • 數(shù)據(jù)結(jié)構(gòu):數(shù)組+單向鏈表漂彤。
  • Entry實(shí)體基本結(jié)構(gòu):hash,key,value,next與HsahMap的Node實(shí)體結(jié)構(gòu)一致;Map.Entry<K, V> 實(shí)現(xiàn)類。
  • 擴(kuò)容時(shí)元素順序不變。
  • 由于HashTable是同步的挫望,多數(shù)方法添加了synchronized關(guān)鍵字同步立润。
1.1.1.3TreeMap
  • 數(shù)據(jù)結(jié)構(gòu):紅黑樹(天然排序)。
  • Entry結(jié)構(gòu):key媳板,value桑腮, left,right蛉幸,parent破讨,color
  • 由于這是排序的hash表,必須在構(gòu)造函數(shù)傳遞比較器Comparator實(shí)現(xiàn)類或添加的實(shí)體實(shí)現(xiàn)Comparable接口
    • Comparator和Comparable區(qū)別:Comparable奕纫,方便提陶,實(shí)體直接繼承,不靈活匹层。Comparator隙笆,靈活,根據(jù)業(yè)務(wù)多維度實(shí)現(xiàn)比較
  • 實(shí)現(xiàn)結(jié)果基本和HashMap的紅黑樹實(shí)現(xiàn)部分一致
1.1.1.4LinkedHashMap
  • 數(shù)據(jù)結(jié)構(gòu):雙向鏈表(輸入的順序和添加順序一致
  • Entry結(jié)構(gòu)升筏,繼承自HashMap.Node ,新添加before, after屬性
  • 繼承自HashMap
  • 新添加的元素放置到鏈表的尾部撑柔,遍歷時(shí)從頭節(jié)點(diǎn)開始,保證了輸入的順序和添加順序一致

幾種map總結(jié):
    1您访、在存儲(chǔ)上基本與value沒有關(guān)系铅忿,主要依賴K和K的hash值來放置到合適位置。
    2灵汪、內(nèi)部實(shí)現(xiàn)上基本以循環(huán)操作為主檀训。

1.1.2Set相關(guān)

1.1.2.1HashSet
  • 實(shí)現(xiàn)依賴于HashMap
1.1.2.3LinkedHashSet
  • 實(shí)現(xiàn)依賴于LinkedHashMap(通過構(gòu)造函數(shù)調(diào)用HashSet的LinkedHashMap構(gòu)造函數(shù)實(shí)現(xiàn))
1.1.2.2TreeSet
  • 支持排序,間接實(shí)現(xiàn)SortedSet接口
  • 實(shí)現(xiàn)依賴于NavigableMap

1.1.3List相關(guān)

1.1.2.1ArrayList
  • 數(shù)據(jù)結(jié)構(gòu):數(shù)組
  • 擴(kuò)容依賴Arrays.copyOf()识虚,它又依賴于 System.arraycopy()
  • 通過索引訪問遍歷效率最高肢扯,而使用迭代器的效率最低(還可以通過增強(qiáng)for循環(huán)遍歷)
1.1.2.2LinkedList
  • 數(shù)據(jù)結(jié)構(gòu):雙向鏈表
  • Node實(shí)體:item,next, prev(當(dāng)前,下一個(gè)担锤,上一個(gè))
  • LinkedList可以作為FIFO(先進(jìn)先出)的隊(duì)列
  • LinkedList可以作為L(zhǎng)IFO(后進(jìn)先出)的棧
1.1.2.3Vector
  • 數(shù)據(jù)結(jié)構(gòu):數(shù)組
  • 支持同步
1.1.2.3Stack
  • 數(shù)據(jù)結(jié)構(gòu):數(shù)組
  • 繼承自Vector蔚晨,支持同步,先進(jìn)后出

1.1.4工具類

  • Arrays:提供一系列靜態(tài)方法肛循,對(duì)數(shù)組排序铭腕,搜索等
  • Collections :提供一系列靜態(tài)方法,對(duì)集合 排序多糠,搜索累舷,包裝集合為安全類型等。包裝基本實(shí)現(xiàn)思路為夹孔,傳入之后賦值給局部變量被盈,通過synchronized關(guān)鍵字同步對(duì)于傳入集合的原有方法加以限制析孽。

1.2java.io

理解類提供的功能,才能更準(zhǔn)確的使用。要理解io必須先了解一些基本的概念和區(qū)別只怎。
  • 裝飾模式和適配器模式
  • 字符流和字節(jié)流
  • 流的基本介質(zhì)和區(qū)別
io字節(jié)輸入流(不是所有的輸入輸出都一一對(duì)應(yīng))
io字節(jié)輸入流
io字節(jié)輸出流
io字節(jié)輸出流
io字符輸入流
io字符輸出流
io字符輸出流
io字符輸出流

1.3java.lang

java的base包袜瞬,唯一一個(gè)只使用不用導(dǎo)包的包。
主要類的類型有:基本類型的包裝類型身堡,異常類邓尤,進(jìn)程類,Thread的相關(guān)類贴谎,字符(串)的系列類汞扎。
  • Object:主要提供hashcode,equals 擅这,getClass澈魄,以及線程之間通信的方式:等待和喚醒。
  • System
    • 主要是native方法
    • 集成一些其他類像IO流蕾哟,
    • 集成RunTime的方法
    • nanoTime():獲取微妙值一忱,主要用于線程阻塞時(shí)間的計(jì)算莲蜘。
    • arraycopy():高效數(shù)組的拷貝谭确,(包括Arrays.copyOf) 都是拷貝引用
  • RunTime:exit,gc票渠,exec逐哈,獲取os運(yùn)行核數(shù)。
  • Class:對(duì)象字節(jié)碼對(duì)象问顷,反射的重點(diǎn)

1.4java.util除過集合的其他類

  • Formatter:公式 %[argument_index$][flags][width][.precision]conversion

2.高級(jí)部分(深刻理解)

2.1java.lang.reflect

2.1.1反射

反射類的主要關(guān)系
  • 獲取對(duì)象字節(jié)對(duì)象的3種方式
    • this.getClass()
    • 對(duì)象.class
    • Class.forName() 獲取對(duì)象字節(jié)碼對(duì)象
  • Class 對(duì)象可以獲取字段數(shù)組昂秃,方法數(shù)組,構(gòu)造函數(shù)(通過方法可以創(chuàng)建實(shí)例)杜窄,所涉及的權(quán)限修飾符肠骆,參數(shù),參數(shù)類型塞耕,方法的返回值類等一切基本都可以獲取到蚀腿。

2.1.2動(dòng)態(tài)代理

動(dòng)態(tài)代理執(zhí)行邏輯
  • 代理模式的應(yīng)用
  • 創(chuàng)建過程類似于“高級(jí)裝飾者模式”+“高級(jí)繼承(非繼承實(shí)現(xiàn)類,繼承的是接口)”
  • 生成代理類過程:生成代理對(duì)象的字節(jié)碼數(shù)組->生成字節(jié)碼對(duì)象->通過構(gòu)造函數(shù)創(chuàng)建實(shí)例
  • 代理對(duì)象和被代理對(duì)象的區(qū)別:代理對(duì)象由于是Proxy的子類扫外,所以持有起橋梁作用的InvocationHandler子類(簡(jiǎn)稱h)莉钙,h又持有被代理對(duì),通過代理對(duì)象給h傳入Method對(duì)象和參數(shù)在加上h持有的被代理對(duì)象就可以對(duì)代理對(duì)象通過Method的invoke執(zhí)行筛谚。其實(shí)就是代理對(duì)象持有自己實(shí)現(xiàn)的InvocationHandler對(duì)象磁玉,而被代理對(duì)象是沒有的。(Method的invoke傳入的對(duì)象一定不能是h的invoke方法傳入的proxy對(duì)象驾讲,proxy對(duì)象是代理對(duì)象傳入的自己本身蚊伞,如果傳入Proxy席赂,將會(huì)發(fā)生代理對(duì)象和h對(duì)象之間的遞歸調(diào)用,直到棧溢出时迫,正確應(yīng)該傳入h持有的被代理對(duì)象氧枣。h的invoke方法傳入的proxy對(duì)象也沒有什么實(shí)際作用
  • 代理對(duì)象里面的基本方法有equals,toString别垮,hashCode和接口的方法便监。所有方法里面沒有額外的邏輯,都是通過h.invoke(this, method, 參數(shù))去調(diào)用真是對(duì)象的碳想。通過 ProxyGenerator.generateProxyClass("$Proxy11", 接口字節(jié)碼數(shù)組); 可以寫入生成代理對(duì)象到文件進(jìn)行查看烧董。
  • h對(duì)象里面的invoke是對(duì)被代理對(duì)象的所有方法的代理,想要定制化代理可以在里面通過傳入的Method對(duì)象獲取方法名進(jìn)行判斷處理胧奔。

2.2java.util.concurrent.*

并發(fā)包主要內(nèi)容:原子類逊移,鎖,容器龙填,線程池胳泉,框架,工具類
并發(fā)主要內(nèi)容

2.2.1原子類

  • 關(guān)于Unsafe的并發(fā)性岩遗。compareAndSwap*方法是原子的扇商,并且可用來實(shí)現(xiàn)高性能的、無鎖(free-lock)的數(shù)據(jù)結(jié)構(gòu)宿礁。

    可能存在ABA問題案铺、指令重排序等問題
  • 獲取Unsafe實(shí)例的2種方法:反射獲取字段的方法或反射獲取構(gòu)造函數(shù)獲取
  • 自定義實(shí)現(xiàn)Integer的原子操作類:CAtomicInteger
  • 原子類主要提供:3類(int,long梆靖,Reference)控汉,每類3種(本身,數(shù)組返吻,字段)的更新
    外加Boolean(底層轉(zhuǎn)化為int),具體實(shí)現(xiàn)對(duì)應(yīng)于Unsafe類的方法
  • unsafe.compareAndSwapInt(arg0, arg1, arg2, arg3)
  • unsafe.compareAndSwapLong(arg0, arg1, arg2, arg3)
  • unsafe.compareAndSwapObject(arg0, arg1, arg2, arg3)

    數(shù)組的原子更新是通過索引號(hào) 更新的具體數(shù)值的

    若想要實(shí)現(xiàn)其他基本類型姑子,可以通過轉(zhuǎn)化為int 或long類型轉(zhuǎn)化去操作
  • 實(shí)現(xiàn)原理大致過程如下:
  • 有一些狀態(tài)
  • 創(chuàng)建它的副本
  • 修改它
  • 執(zhí)行CAS
  • 如果失敗,重復(fù)嘗試直到成功

    無鎖編程(lock free)

    常見的lock free編程一般是基于CAS(Compare And Swap)操作:CAS(void ptr, Any oldValue, Any newValue);即查看內(nèi)存地址ptr處的值测僵,如果為oldValue則將其改為 newValue街佑,并返回true,否則返回false恨课。 X86平臺(tái)上的CAS操作一般是通過CPU的CMPXCHG指令來完成的舆乔。CPU在執(zhí)行此指令時(shí)會(huì)首先鎖住CPU總線,禁止其它核心對(duì)內(nèi)存的訪問剂公,然后再查看或修改ptr的值希俩。簡(jiǎn)單的說CAS利用了CPU的硬件鎖來實(shí)現(xiàn)對(duì)共享資源的串行使用。

    優(yōu)點(diǎn):
  • a纲辽、開銷較醒瘴洹:不需要進(jìn)入內(nèi)核璃搜,不需要切換線程;
  • b鳞上、沒有死鎖:總線鎖最長(zhǎng)持續(xù)為一次read+write的時(shí)間这吻;
  • c、只有寫操作需要使用CAS篙议,讀操作與串行代碼完全相同唾糯,可實(shí)現(xiàn)讀寫不互斥。

    缺點(diǎn):
  • a鬼贱、編程非常復(fù)雜移怯,兩行代碼之間可能發(fā)生任何事,很多常識(shí)性的假設(shè)都不成立这难。
  • b舟误、CAS模型覆蓋的情況非常少,無法用CAS實(shí)現(xiàn)原子的復(fù)數(shù)操作姻乓。

2.2.2鎖

主要類關(guān)系:

Lock包主要類關(guān)系

2.2.2.1AQS

  • 鎖是面向用戶的嵌溢,同步器是面向鎖的(就是鎖的內(nèi)部實(shí)現(xiàn)),AQS支持互斥鎖蹋岩,共享鎖的實(shí)現(xiàn)赖草。
  • AQS實(shí)現(xiàn)一個(gè)FIFO等待隊(duì)列。
  • 通過對(duì)state的原子修改來實(shí)現(xiàn)獲取鎖和釋放鎖星澳;
  • 互斥鎖:state為1時(shí)可以實(shí)現(xiàn)互斥鎖(TCustomSyncExclusiveLock)疚顷,大于1可以實(shí)現(xiàn)重入鎖旱易;
  • 共享鎖:state大于1時(shí)可以實(shí)現(xiàn)共享鎖(TCustomSyncShareLock)禁偎,此時(shí)state的值即表示并發(fā)的線程數(shù),此時(shí)不便實(shí)現(xiàn)重入鎖阀坏。
2.2.2.1.1關(guān)鍵詞理解
模板方法如暖,互斥鎖(排它鎖),共享鎖忌堂,同步隊(duì)列盒至,阻塞隊(duì)列(條件隊(duì)列),LockSupport士修,ConditionObject
  • AQS:提供一組模板方法用于具體業(yè)務(wù)實(shí)現(xiàn)互斥鎖或者共享鎖
  • 同步隊(duì)列:保存等待獲取鎖的線程節(jié)點(diǎn)
  • 阻塞隊(duì)列:保存執(zhí)行了await的線程節(jié)點(diǎn)
  • LockSupport:用于阻塞或者喚醒線程枷遂,屬于工具類,不和鎖關(guān)聯(lián)(Condition和synchronized阻止線程必須和鎖關(guān)聯(lián))
  • ConditionObject:AQS的監(jiān)視器

注意:Object的監(jiān)視器只有一個(gè)同步隊(duì)列和一個(gè)阻塞隊(duì)列棋嘲;而AQS卻有一個(gè)同步隊(duì)列和多個(gè)阻塞隊(duì)列酒唉,對(duì)應(yīng)多個(gè)ConditionObject

2.2.2.1.2同步隊(duì)列和阻塞隊(duì)列的節(jié)點(diǎn)互相轉(zhuǎn)化(結(jié)合ReentrantLock說明)
  • TReentrantLock3運(yùn)行示例
  • 同步隊(duì)列:雙向鏈表;阻塞隊(duì)列:?jiǎn)蜗蜴湵?/li>
  • 基本流程:首先所有節(jié)點(diǎn)會(huì)被加入同步隊(duì)列沸移,在執(zhí)行await后會(huì)加入阻塞隊(duì)列痪伦,喚醒時(shí)又會(huì)被轉(zhuǎn)化回同步隊(duì)列
  • 2個(gè)隊(duì)列獨(dú)立存在侄榴,都使用Node作為基本節(jié)點(diǎn)

注意使線程節(jié)點(diǎn)進(jìn)入阻塞隊(duì)列的不適合AQS實(shí)現(xiàn)的共享鎖操作,因?yàn)閚ewCondition.await()其中會(huì)調(diào)用tryRelease(long arg),而共享鎖不會(huì)實(shí)現(xiàn)這個(gè)

2.2.2.1.3lock ,unLock,await,signal(signalAll:相當(dāng)于循環(huán)操作signal)的邏輯分析(結(jié)合ReentrantLock說明)
  • lock:獲取不到鎖阻塞該線程网沾,加入同步隊(duì)列
  • unLock:釋放鎖喚醒后繼節(jié)點(diǎn)
  • await:主要干三件事:1.阻塞該線程 2.添加到等待隊(duì)列3. 喚醒后繼線程
  • signal:主要干1件事:加入同步隊(duì)列

2.2.2.2ReentrantLock

ReentrantLock內(nèi)部關(guān)系
  • 主要理解公平鎖和非公平鎖的在獲取鎖時(shí)的不同之處(二者都使用同步隊(duì)列癞蚕,非公平鎖再獲取時(shí)存在插隊(duì)現(xiàn)象,這樣對(duì)于隊(duì)列其他的節(jié)點(diǎn)線程就是不公平的
  • ReentrantLock,屬于互斥鎖辉哥,重入鎖(釋放必須和獲取執(zhí)行次數(shù)一樣
  • ReentrantLock的方法在調(diào)用時(shí) 如果拋出 IllegalMonitorStateException - 則該方法必須在鎖的區(qū)域內(nèi)調(diào)用
  • 不管是公平鎖或者非公平鎖都使用的AQS的同步隊(duì)列
  • 性能問題:(TReentrantLock2測(cè)試)
    • 前提:把不同線程獲取鎖的一次定義為一次上下文切換
    • 獲取同等鎖次數(shù)情況下桦山,非公平鎖相對(duì)用時(shí)更少,原因是減少了cpu的上下文切換
    • 公平鎖執(zhí)行較多上下文切換次數(shù)醋旦, 而非公平鎖執(zhí)行上下文切換次數(shù)較少(原因是當(dāng)一個(gè)線程獲取釋放鎖后度苔,下一次如果它再需要鎖,相對(duì)比其他線程獲取鎖的概率更大浑度,此時(shí)就不需要切換就相對(duì)省時(shí))

2.2.2.3ReentrantReadWriteLock

ReentrantReadWriteLock內(nèi)部關(guān)系
  • 出現(xiàn)讀寫鎖的緣由:當(dāng)多讀少寫時(shí)寇窑,使用讀寫鎖比使用互斥鎖具有更高的并發(fā)性
  • 特點(diǎn):(讀鎖可以并發(fā)訪問,寫鎖時(shí)其他的讀鎖和其他的寫鎖都被阻塞
  • 主要依據(jù)32位的int類型的state的低16位的值表示寫鎖(為互斥鎖)箩张;高16位的值表示讀鎖(為共享鎖)
  • 通過位運(yùn)算把state值拆分為2個(gè)值:假設(shè)當(dāng)前狀態(tài)為s
  • 寫狀態(tài):s & (1 << 16) - 1 即:s&65535甩骏,也就是s與16個(gè)1(2進(jìn)制的),這樣就把高16位抹去了先慷;當(dāng)寫狀態(tài)+1時(shí)饮笛,即為s+1,只給低位加论熙。
  • 讀狀態(tài):s>>>16 ,表示無符號(hào)補(bǔ)0右移16位福青;當(dāng)讀狀態(tài)+1時(shí),等于s+(1<<16),結(jié)果就是只給高位加
  • 鎖降級(jí))流程:先獲取寫鎖脓诡,在獲取讀鎖无午,在釋放寫鎖,在釋放讀鎖(不支持鎖升級(jí))

2.2.3容器

主要并發(fā)容器


并發(fā)容器

2.2.3.1隊(duì)列

  • 阻塞隊(duì)列主要方法說明:
  • [add:remove]沒有值或隊(duì)列滿時(shí)祝谚,操作報(bào)異常宪迟;屬于Queue接口的規(guī)范
  • [offer:poll]返回特殊值(null或波爾值),隊(duì)列滿時(shí)添加失敗交惯,造成丟失元素次泽;屬于Queue接口的規(guī)范
  • [put:take]空或滿時(shí)操作阻塞,但是不會(huì)丟失元素席爽;屬于BlockingQueue接口的規(guī)范
  • ArrayBlockingQueue:數(shù)組實(shí)現(xiàn)的有節(jié)阻塞隊(duì)列意荤,此隊(duì)列按 FIFO(先進(jìn)先出)原則。

    自定義CArrayBlockingQueue注意:
    • putIndex和takeIndex只锻,當(dāng)?shù)竭_(dá)數(shù)組末端時(shí)玖像,必須從0開始 。
    • while和if的選擇炬藤?
    • 必須使用while御铃,因?yàn)樵趕ignal()take1線程時(shí)碴里,只會(huì)從阻塞隊(duì)列轉(zhuǎn)移到同步隊(duì)列(不見得會(huì)獲取鎖真正喚醒), 此時(shí)可能已經(jīng)有其他take2線程獲取到了鎖上真,把隊(duì)列中僅有的元素移除了咬腋,此時(shí)take2線程執(zhí)行完后是釋放鎖,喚醒后 繼節(jié)點(diǎn)也就是take1線程睡互。此時(shí)take1線程應(yīng)該再次判斷根竿,條件不滿足繼續(xù)阻塞。
    • 能否通過公平鎖或不公平鎖避免這個(gè)問題就珠? 不能寇壳,因?yàn)樯厦娴膖ake2線程可以認(rèn)為是不公平鎖的插隊(duì)線程。 加入是公平鎖呢妻怎?上面 take1線程順利獲取到了鎖壳炎,取走了唯一的元素。而新線程在獲取不到鎖時(shí)逼侦,加入同步隊(duì)列匿辩。當(dāng)線程 take1 線程執(zhí)行完后釋放鎖,take2線程被喚醒榛丢,也必須再次檢測(cè)while條件铲球。否則將返回null元素,不符合阻塞隊(duì)列晰赞。
    • 區(qū)別:while比if執(zhí)行完后多一次檢測(cè)
    • if:只會(huì)進(jìn)行一次判斷稼病,執(zhí)行if代碼塊完后就會(huì)執(zhí)行if之后的代碼
    • while:符合while條件后,執(zhí)行完while代碼塊里面的代碼掖鱼,執(zhí)行完后會(huì)再次檢查while條件然走,符合繼續(xù)執(zhí)行;不符合跳過锨用,while:多使用于多線程喚醒后的再次檢查條件
    • signal和signalAll:使用這倆個(gè)都可以丰刊,只不過只會(huì)有一個(gè)線程獲取鎖得到元素,所以使用signal比signalAll更恰當(dāng)
  • LinkedBlockingQueue:一個(gè)單向鏈表實(shí)現(xiàn)的有界(可指定大小增拥,默認(rèn)Integer.MAX_VALUE)阻塞隊(duì)列,此隊(duì)列按 FIFO(先進(jìn)先出)原則寻歧。鏈接隊(duì)列的吞吐量通常要高于基于數(shù)組的隊(duì)列掌栅,但是在大多數(shù)并發(fā)應(yīng)用程序中,其可預(yù)知的性能要低码泛。
  • PriorityBlockingQueue:一個(gè)無界阻塞隊(duì)列猾封,雖然此隊(duì)列邏輯上是無界的,但是資源被耗盡時(shí)試圖執(zhí)行 add 操作也將失敗噪珊,導(dǎo)致 OutOfMemoryError晌缘。不支持先進(jìn)先出原則
  • 由于隊(duì)列是無界的齐莲,所以put方法不會(huì)由于滿了(始終不會(huì)滿)而導(dǎo)致阻塞 。
  • 不保證具有同等優(yōu)先級(jí)的元素的順序
  • 入隊(duì)(通過比較找到合適位置入隊(duì))相同(值相等)元素不會(huì)覆蓋磷箕,出對(duì)從隊(duì)列頭出隊(duì)
  • DelayQueue:一個(gè)無界阻塞隊(duì)列选酗,內(nèi)部根據(jù)PriorityQueue(無界線程不安全隊(duì)列) 存儲(chǔ)元素,適用場(chǎng)景:定時(shí)執(zhí)行(獲仍兰稀)芒填,緩存失效等
  • LinkedBlockingDeque:鏈表實(shí)現(xiàn)的有界阻塞雙端隊(duì)列,支持同端存取(FILO)和異端存瓤辗薄(FIFO)殿衰。如果未指定容量,那么容量將等于 Integer.MAX_VALUE
  • LinkedTransferQueue:一個(gè)鏈表實(shí)現(xiàn)的無界阻塞隊(duì)列
    • tryTransfer()嘗試傳遞給消費(fèi)者 ,沒有消費(fèi)者放入隊(duì)列
    • transfer()嘗試傳遞給消費(fèi)者 ,沒有消費(fèi)者自己處于阻塞狀態(tài)盛泡,這種模式類似與SynchronousQueue
    • 無論是transfer還是tryTransfer方法闷祥,在>=1個(gè)消費(fèi)者線程等待獲取元素時(shí)(此時(shí)隊(duì)列為空),都會(huì)立刻轉(zhuǎn)交傲诵,這屬于線程之間的元素交換蜀踏。注意,這時(shí)掰吕,元素并沒有進(jìn)入隊(duì)列果覆。
    • 在隊(duì)列中已有數(shù)據(jù)情況下,transfer將需要等待前面數(shù)據(jù)被消費(fèi)掉殖熟,直到傳遞的元素e被消費(fèi)線程取走為止局待。
  • SynchronousQueue:一個(gè)不存儲(chǔ)元素的阻塞隊(duì)列
    • 其中每個(gè)插入操作必須等待另一個(gè)線程的對(duì)應(yīng)移除操作,如果沒被消費(fèi)則一直處于阻塞
    • 此同步隊(duì)列沒有任何內(nèi)部容量菱属,甚至連一個(gè)隊(duì)列的容量都沒有,適合傳遞性的應(yīng)用場(chǎng)景

2.2.3.2Copy-On-Write簡(jiǎn)稱COW钳榨,僅2個(gè)類Set和List

  • Copy-On-Write簡(jiǎn)稱COW,是一種用于程序設(shè)計(jì)中的優(yōu)化策略纽门,采用數(shù)組存儲(chǔ)薛耻。
  • 使用場(chǎng)景:多讀少寫(讀不加鎖,寫會(huì)加鎖赏陵,防止多個(gè)線程多多個(gè)拷貝同時(shí)造成數(shù)據(jù)混亂饼齿,所以會(huì)加鎖防止此問題)
  • 寫時(shí)采用復(fù)制新的容器,進(jìn)行修改蝙搔;新容器為原容器中對(duì)象的引用缕溉,使用完把新容器賦值給類的原有容器引用。復(fù)制新的容器時(shí)吃型,這是一個(gè)比較耗費(fèi)性能的操作
  • CopyOnWriteArraySet 采用CopyOnWriteArrayList 作為存儲(chǔ)证鸥。基本差不多
  • CopyOnWrite的缺點(diǎn)
    • 內(nèi)存占用問題。因?yàn)镃opyOnWrite的寫時(shí)復(fù)制機(jī)制枉层,所以在進(jìn)行寫操作的時(shí)候泉褐,內(nèi)存里會(huì)同時(shí)駐扎兩個(gè)對(duì)象的內(nèi)存,舊的對(duì)象和新寫入的對(duì)象

      (注意:在復(fù)制的時(shí)候只是復(fù)制容器里的引用鸟蜡,只是在寫的時(shí)候會(huì)創(chuàng)建新對(duì)象添加到新容器里膜赃,而舊容器的對(duì)象還在使用,所以有兩份對(duì)象內(nèi)存)矩欠。
    • 數(shù)據(jù)一致性問題财剖。CopyOnWrite容器只能保證數(shù)據(jù)的最終一致性,不能保證數(shù)據(jù)的實(shí)時(shí)一致性癌淮。所以如果若希望寫入的的數(shù)據(jù)躺坟,馬上能讀到,不建議使用CopyOnWrite容器乳蓄。
  • java1.8 下CopyOnWriteArrayList 和 Collections.synchronizedList(new ArrayList<String>()) 性能測(cè)試結(jié)論:
    • 1.6下 CopyOnWriteArrayList 優(yōu)于 synchronizedList網(wǎng)上結(jié)論;
    • 1.8下基本差不多,可能是jvm對(duì)synchronized 不斷的優(yōu)化

2.2.3.3Concurrent*集合

均為安全的集合ConcurrentHashMap采用加鎖咪橙,其他幾個(gè)采用CAS無鎖更新
  • ConcurrentHashMap
  • 1.代碼體積約6000行
  • 2.java1.8 ConcurrentHashMap 和 HashMap 結(jié)構(gòu)一樣 ,在put操作時(shí)虚倒,當(dāng)數(shù)組索引位置大于1時(shí)進(jìn)行加鎖操作
  • 3.size()(或 mappingCount()) 使用無鎖操作美侦,返回并非準(zhǔn)確值, 因?yàn)榇藭r(shí)可能有線程對(duì)集合進(jìn)行刪除或增加操作
  • 4.比較:
    • java1.7
      • 1.版本采用Segment<K,V>[] segments數(shù)組,Segment繼承ReentrantLock魂奥,實(shí)現(xiàn)鎖分段菠剩,進(jìn)行安全操作
      • 2.每個(gè)Segment相當(dāng)于一個(gè)老版本的hashMap(數(shù)據(jù)結(jié)構(gòu)為:table數(shù)組+單向鏈表的數(shù)據(jù)結(jié)構(gòu))
      • 3.get時(shí) 取不到值最后在加鎖取一次
    • java1.8
      • 1.取消segments字段,直接采用 HashEntry<K,V>[] table保存數(shù)據(jù)
      • 2.數(shù)據(jù)結(jié)構(gòu)改為:變更為table數(shù)組+單向鏈表(或紅黑樹)
      • 3.get() 使用無鎖操作耻煤,取不到直接返回空
  • 5.1.8中的鎖力度更小具壮,數(shù)據(jù)結(jié)構(gòu)更簡(jiǎn)單
  • 6.CounterCell何時(shí)使用 沒有理解透徹?
  • ConcurrentLinkedDeque
    • 1.代碼體積約1500行
    • 2.一個(gè)無界線程安全雙向鏈表
    • 3.使用unsafe 保證原子性
  • ConcurrentLinkedQueue
    • 一個(gè)無界線程安全FIFO隊(duì)列
  • ConcurrentSkipListMap
    • 是TreeMap的多線的安全版本
    • 數(shù)據(jù)結(jié)構(gòu)使用跳表保存數(shù)據(jù)哈蝇,實(shí)質(zhì)為一種鏈表

Key-Value數(shù)據(jù)結(jié)構(gòu)

目前常用的key-value數(shù)據(jù)結(jié)構(gòu)有三種:Hash表棺妓、紅黑樹、SkipList

名稱 描述
hash表 即數(shù)組:例如:Hashmap(Hash表+鏈表+紅黑樹)炮赦,HashTbale(Hash表+鏈表) 插入怜跑、查找最快,為O(1)吠勘;如使用鏈表實(shí)現(xiàn)則可實(shí)現(xiàn)無鎖性芬;數(shù)據(jù)有序化需要顯式的排序操作。
紅黑樹 例如:TreeMap 插入看幼、查找為O(logn)批旺,但常數(shù)項(xiàng)較小诵姜;無鎖實(shí)現(xiàn)的復(fù)雜性很高,一般需要加鎖;數(shù)據(jù)天然有序棚唆。
Skip表 例如:ConcurrentSkipListMap,插入暇赤、查找為O(logn),但常數(shù)項(xiàng)比紅黑樹要大宵凌;底層結(jié)構(gòu)為鏈表鞋囊,可無鎖實(shí)現(xiàn);數(shù)據(jù)天然有序瞎惫。

2.2.4線程池

線程池常用類關(guān)系

線程池常用類關(guān)系

2.2.4.1ExecutorCompletionService

  • CompletionService實(shí)現(xiàn)了生產(chǎn)者提交任務(wù)和消費(fèi)者獲取結(jié)果的解耦溜腐,消費(fèi)者一定是按照任務(wù)完成的先后順序來獲取執(zhí)行結(jié)果,注意不是提交順序。(自定義的實(shí)現(xiàn)為按照提交順序)
  • 基本實(shí)現(xiàn):Executor+阻塞隊(duì)列實(shí)現(xiàn)
  • 一組任務(wù)獲取結(jié)果的場(chǎng)景

2.2.4.2FutureTask

  • 僅在計(jì)算完成時(shí)才能獲取結(jié)果瓜喇;如果計(jì)算尚未完成挺益,則阻塞 get 方法。
  • 單個(gè)任務(wù)獲取結(jié)果的場(chǎng)景
  • 可使用 FutureTask 包裝 Callable 或 Runnable 對(duì)象乘寒。因?yàn)?FutureTask 實(shí)現(xiàn)了 Runnable望众,所以可將 FutureTask 提交給 Executor 執(zhí)行。
  • FutureTask和Callable的關(guān)系伞辛?
    • 由于線程池(AbstractExecutorService)只執(zhí)行Callable類型的任務(wù) ,提交的 Runnable 也會(huì)轉(zhuǎn)化為Callable烂翰。
    • 從類型上講:FutureTask = Runnable+Future ;FutureTask內(nèi)部又維護(hù)一個(gè)Callable,所以實(shí)際上又是一個(gè) Callable
    • 總之:FutureTask既是Runnable 又是Callable 蚤氏,還有Future的特性甘耿。

2.2.4.3兩種線程池

  • ThreadPoolExecutor
  • ThreadPoolExecutor調(diào)節(jié)線程的原則是:先調(diào)整到最小線程,最小線程用完后竿滨,它會(huì)優(yōu)先將任務(wù) 放入緩存隊(duì)列(offer(task)),等緩沖隊(duì)列用完了佳恬,才會(huì)向最大線程數(shù)調(diào)節(jié)。
  • 線程池線程參數(shù)設(shè)置原則
    • 無界隊(duì)列:大小線程數(shù)建議設(shè)置成一致姐呐,如果使用無界隊(duì)列 殿怜,就不可能使用最大線程數(shù)
    • 有界隊(duì)列:大小線程數(shù)可以不一致(當(dāng)有界隊(duì)列特別大時(shí),也沒有必要把core和max設(shè)置的不一樣曙砂, 因?yàn)榭赡芎茈y達(dá)到有界的最值头谜,也就更難達(dá)到max的值了)
  • 繼承關(guān)系:
    Executor->ExecutorService->AbstractExecutorService->ThreadPoolExecutor
  • 理解線程復(fù)用?(難點(diǎn))
  • ScheduledThreadPoolExecutor
  • ScheduledExecutorService的實(shí)現(xiàn)類ScheduledThreadPoolExecutor是繼承線程池類ThreadPoolExecutor的鸠澈,因此它擁有線程池的全部特性柱告。但是同時(shí)又是一種特殊的線程池,這個(gè)
    線程池的線程數(shù)大小最大Integer最大值笑陈,任務(wù)隊(duì)列是基于DelayQueue的無限任務(wù)隊(duì)列际度。
    主要提供定時(shí)執(zhí)行功能,通過延時(shí)隊(duì)列實(shí)現(xiàn)
  • 繼承關(guān)系:
    Executor->ExecutorService->AbstractExecutorService->ThreadPoolExecutor->ScheduledExecutorService
  • scheduleAtFixedRate【不關(guān)注上次線程執(zhí)行完成】和scheduleWithFixedDelay【關(guān)注上次線程執(zhí)行完成】
  • 功能效果和Timer類似

2.2.4.4拒絕策略

  • 拒絕策略4個(gè)類屬于ThreadPoolExecutor的內(nèi)部類
  • 具體使用區(qū)別
    • AbortPolicy:當(dāng)提交的不能立即執(zhí)行且阻塞隊(duì)列無法容納時(shí)涵妥, 拋出異常乖菱,后續(xù)生產(chǎn)線程不能再正常提交到線程池
    • CallerRunsPolicy:當(dāng)提交的不能立即執(zhí)行且阻塞隊(duì)列無法容納時(shí),則立即執(zhí)行,后續(xù)正常提交到線程池
    • DiscardOldestPolicy:當(dāng)提交的不能立即執(zhí)行且阻塞隊(duì)列無法容納時(shí),移除調(diào)隊(duì)列中最早的任務(wù),后續(xù)正常提交到線程池
    • DiscardPolicy:當(dāng)提交的不能立即執(zhí)行且阻塞隊(duì)列無法容納時(shí)窒所,丟棄提交的任務(wù),后續(xù)正常提交到線程池

2.2.5框架

  • Executors
    • 也可以認(rèn)為是創(chuàng)建線程池的一個(gè)工具類
    • 提供創(chuàng)建線程池的一些靜態(tài)方法
  • Fork/Join
  • Fork/Join實(shí)現(xiàn)了“工作竊取算法”鹉勒,F(xiàn)orkJoinTask需要通過ForkJoinPool來執(zhí)行,任務(wù)分割出的子任務(wù)會(huì)添加到當(dāng)前工作線程所維護(hù)的雙端隊(duì)列中吵取,進(jìn)入隊(duì)列的頭部禽额。當(dāng)一個(gè)工作線程的隊(duì)列里暫時(shí)沒有任務(wù)時(shí),它會(huì)隨機(jī)從其他工作線程的隊(duì)列的尾部獲取一個(gè)任務(wù)皮官。
  • Fork/Join框架的設(shè)計(jì)主要2步任務(wù)
    • 第一步分割任務(wù)脯倒。首先我們需要有一個(gè)fork類來把大任務(wù)分割成子任務(wù),有可能子任務(wù)還是很大捺氢,所以還需要不停的分割藻丢,直到分割出的子任務(wù)足夠小。
    • 第二步執(zhí)行任務(wù)并合并結(jié)果讯沈。分割的子任務(wù)分別放在雙端隊(duì)列里郁岩,然后幾個(gè)啟動(dòng)線程分別從雙端隊(duì)列里獲取任務(wù)執(zhí)行。子任務(wù)執(zhí)行完的結(jié)果都統(tǒng)一放在一個(gè)隊(duì)列里缺狠,啟動(dòng)一個(gè)線程從隊(duì)列里拿數(shù)據(jù)问慎,然后合并這些數(shù)據(jù)。
  • 應(yīng)用
    • 第一步:創(chuàng)建任務(wù)job挤茄,繼承ForkJoinTask的子類:

      -----RecursiveAction:用于沒有返回結(jié)果的任務(wù)如叼。

      -----RecursiveTask :用于有返回結(jié)果的任務(wù)。
    • 第二步:提交job到ForkJoinPool(獲取結(jié)果如果有)

2.2.6工具類

  • CountDownLatch : 基于AQS共享鎖的實(shí)現(xiàn)穷劈,當(dāng)state為0時(shí)喚醒等待的一個(gè)或一組線程
  • CyclicBarrier : 內(nèi)部維護(hù)一個(gè)count 當(dāng)count為0時(shí)笼恰,等待的線程開始運(yùn)行,恢復(fù)CyclicBarrier的count為原初始值parties歇终,所以相比CountDownLatch是可以重復(fù)使用的
  • Exchanger:線程互換數(shù)據(jù)
  • 每個(gè)線程既可以充當(dāng)消費(fèi)者社证,也可以充當(dāng)生產(chǎn)者
  • 當(dāng)生產(chǎn)大于消費(fèi)時(shí),如果一直沒有被消費(fèi)完评凝,線程將處于阻塞狀態(tài)
  • Semaphore:
    • 基于AQS共享鎖的實(shí)現(xiàn)
    • Semaphore可以應(yīng)用于流量控制追葡,比如對(duì)數(shù)據(jù)庫(kù)的連接數(shù)控制

2.2.7常見問題(整理自并發(fā)編程網(wǎng))

并發(fā)常見問題

2.2.8 jvm常用命令

jps、jstack奕短、jmap宜肉、jhat、jstat

2.3java.net

2.4javax.net.*

2.5java.nio.*

3.其它包使用

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末翎碑,一起剝皮案震驚了整個(gè)濱河市谬返,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌日杈,老刑警劉巖遣铝,帶你破解...
    沈念sama閱讀 216,744評(píng)論 6 502
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件佑刷,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡翰蠢,警方通過查閱死者的電腦和手機(jī)项乒,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,505評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門啰劲,熙熙樓的掌柜王于貴愁眉苦臉地迎上來梁沧,“玉大人,你說我怎么就攤上這事蝇裤⊥⒅В” “怎么了?”我有些...
    開封第一講書人閱讀 163,105評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵栓辜,是天一觀的道長(zhǎng)恋拍。 經(jīng)常有香客問我,道長(zhǎng)藕甩,這世上最難降的妖魔是什么施敢? 我笑而不...
    開封第一講書人閱讀 58,242評(píng)論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮狭莱,結(jié)果婚禮上僵娃,老公的妹妹穿的比我還像新娘。我一直安慰自己腋妙,他們只是感情好默怨,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,269評(píng)論 6 389
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著骤素,像睡著了一般匙睹。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上济竹,一...
    開封第一講書人閱讀 51,215評(píng)論 1 299
  • 那天痕檬,我揣著相機(jī)與錄音,去河邊找鬼送浊。 笑死梦谜,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的罕袋。 我是一名探鬼主播改淑,決...
    沈念sama閱讀 40,096評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼浴讯!你這毒婦竟也來了朵夏?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,939評(píng)論 0 274
  • 序言:老撾萬榮一對(duì)情侶失蹤榆纽,失蹤者是張志新(化名)和其女友劉穎仰猖,沒想到半個(gè)月后捏肢,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,354評(píng)論 1 311
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡饥侵,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,573評(píng)論 2 333
  • 正文 我和宋清朗相戀三年鸵赫,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片躏升。...
    茶點(diǎn)故事閱讀 39,745評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡辩棒,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出膨疏,到底是詐尸還是另有隱情一睁,我是刑警寧澤,帶...
    沈念sama閱讀 35,448評(píng)論 5 344
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響廊谓,放射性物質(zhì)發(fā)生泄漏握童。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,048評(píng)論 3 327
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦育八、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,683評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至深纲,卻和暖如春仲锄,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背湃鹊。 一陣腳步聲響...
    開封第一講書人閱讀 32,838評(píng)論 1 269
  • 我被黑心中介騙來泰國(guó)打工儒喊, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人币呵。 一個(gè)月前我還...
    沈念sama閱讀 47,776評(píng)論 2 369
  • 正文 我出身青樓怀愧,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親余赢。 傳聞我的和親對(duì)象是個(gè)殘疾皇子芯义,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,652評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容