菜鳥(niǎo)的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í)踐。
集合羅列
集合 查詢(xún)時(shí)間復(fù)雜度 繼承前列 線程安全 支持排序
Map HashMap LinkedHashMap HashTable TreeMap
Set HashSet LinkedHashSet TreeSet
~ 無(wú) 無(wú) 線程安全 繼承前列線程安全
List ArrayList LinkedList Vector Stack
相似比較
Name 同作用 不同作用
Iterator 支持遍歷 支持fail-fast[ConcurrentModificationException]機(jī)制,通過(guò)迭代器可以對(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ù)雜的類(lèi),搞清楚map的常用實(shí)現(xiàn)類(lèi)是非常關(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ù))+ 單向鏈表+紅黑樹(shù)(又叫自平衡二叉查找樹(shù))。
  • Node實(shí)體基本結(jié)構(gòu):hash,key,value,next(鏈表的下一個(gè)實(shí)體);Map.Entry<K, V> 實(shí)現(xiàn)類(lèi)。
  • TreeNode實(shí)體基本結(jié)構(gòu):parent,left,right,prev;TreeNode繼承LinkedHashMap.Entry繼承HashMap.Node<K,V>。
  • 數(shù)組上的元素為鏈表(或紅黑樹(shù))的頭節(jié)點(diǎn)(或根節(jié)點(diǎn))。
  • 對(duì)于hash沖突解決辦法使用鏈表(或紅黑樹(shù)),當(dāng)鏈表長(zhǎng)度大于等于8時(shí)轉(zhuǎn)化為紅黑樹(shù)。之所以轉(zhuǎn)化為紅黑樹(shù)是當(dāng)數(shù)量大時(shí)紅黑樹(shù)的查詢(xún)效率更高。
  • 操作紅黑樹(shù),增加刪除后為了自平衡 進(jìn)行的左右旋和重新著色。
幾種時(shí)間復(fù)雜度
結(jié)構(gòu) 查詢(xún)時(shí)間復(fù)雜度 說(shuō)明
hash表 O(1)
鏈表 O(n) 遍歷鏈表去查找
紅黑樹(shù) O(log n)
多線程下當(dāng)共享變量使用時(shí),擴(kuò)容鏈表造成的問(wèn)題
版本 元素是否倒置 元素是否丟失 復(fù)雜程度
1.7 倒置(易形成閉合回路) 沒(méi)驗(yàn)證 代碼量約1000行
1.8 不倒置(99%的認(rèn)為不會(huì)形成,1%再驗(yàn)證) 會(huì)丟失 代碼量約2000行
解決辦法 不當(dāng)共享變量使用(在局部變量中 new創(chuàng)建 是沒(méi)問(wèn)題的,在棧中操作,屬于私有的)或使用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)類(lèi)。
  • 擴(kuò)容時(shí)元素順序不變。
  • 由于HashTable是同步的,多數(shù)方法添加了synchronized關(guān)鍵字同步。
1.1.1.3TreeMap
  • 數(shù)據(jù)結(jié)構(gòu):紅黑樹(shù)(天然排序)。
  • Entry結(jié)構(gòu):key,value, left,right,parent,color
  • 由于這是排序的hash表,必須在構(gòu)造函數(shù)傳遞比較器Comparator實(shí)現(xiàn)類(lèi)或添加的實(shí)體實(shí)現(xiàn)Comparable接口
    • Comparator和Comparable區(qū)別:Comparable,方便,實(shí)體直接繼承,不靈活。Comparator,靈活,根據(jù)業(yè)務(wù)多維度實(shí)現(xiàn)比較
  • 實(shí)現(xiàn)結(jié)果基本和HashMap的紅黑樹(shù)實(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)開(kāi)始,保證了輸入的順序和添加順序一致

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

1.1.2Set相關(guān)

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

1.1.3List相關(guān)

1.1.2.1ArrayList
  • 數(shù)據(jù)結(jié)構(gòu):數(shù)組
  • 擴(kuò)容依賴(lài)Arrays.copyOf(),它又依賴(lài)于 System.arraycopy()
  • 通過(guò)索引訪問(wèn)遍歷效率最高,而使用迭代器的效率最低(還可以通過(guò)增強(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工具類(lèi)

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

1.2java.io

理解類(lèi)提供的功能,才能更準(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)包的包。
主要類(lèi)的類(lèi)型有:基本類(lèi)型的包裝類(lèi)型,異常類(lèi),進(jìn)程類(lèi),Thread的相關(guān)類(lèi),字符(串)的系列類(lèi)。
  • Object:主要提供hashcode,equals ,getClass,以及線程之間通信的方式:等待和喚醒。
  • System
    • 主要是native方法
    • 集成一些其他類(lèi)像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除過(guò)集合的其他類(lèi)

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

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

2.1java.lang.reflect

2.1.1反射

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

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

動(dòng)態(tài)代理執(zhí)行邏輯
  • 代理模式的應(yīng)用
  • 創(chuàng)建過(guò)程類(lèi)似于“高級(jí)裝飾者模式”+“高級(jí)繼承(非繼承實(shí)現(xiàn)類(lèi),繼承的是接口)”
  • 生成代理類(lèi)過(guò)程:生成代理對(duì)象的字節(jié)碼數(shù)組->生成字節(jié)碼對(duì)象->通過(guò)構(gòu)造函數(shù)創(chuàng)建實(shí)例
  • 代理對(duì)象和被代理對(duì)象的區(qū)別:代理對(duì)象由于是Proxy的子類(lèi),所以持有起橋梁作用的InvocationHandler子類(lèi)(簡(jiǎn)稱(chēng)h),h又持有被代理對(duì),通過(guò)代理對(duì)象給h傳入Method對(duì)象和參數(shù)在加上h持有的被代理對(duì)象就可以對(duì)代理對(duì)象通過(guò)Method的invoke執(zhí)行。其實(shí)就是代理對(duì)象持有自己實(shí)現(xiàn)的InvocationHandler對(duì)象,而被代理對(duì)象是沒(méi)有的。(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ì)象也沒(méi)有什么實(shí)際作用
  • 代理對(duì)象里面的基本方法有equals,toString,hashCode和接口的方法。所有方法里面沒(méi)有額外的邏輯,都是通過(guò)h.invoke(this, method, 參數(shù))去調(diào)用真是對(duì)象的。通過(guò) ProxyGenerator.generateProxyClass("$Proxy11", 接口字節(jié)碼數(shù)組); 可以寫(xiě)入生成代理對(duì)象到文件進(jìn)行查看。
  • h對(duì)象里面的invoke是對(duì)被代理對(duì)象的所有方法的代理,想要定制化代理可以在里面通過(guò)傳入的Method對(duì)象獲取方法名進(jìn)行判斷處理。

2.2java.util.concurrent.*

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

2.2.1原子類(lèi)

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

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

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

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

    無(wú)鎖編程(lock free)

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

    優(yōu)點(diǎn):
  • a、開(kāi)銷(xiāo)較小:不需要進(jìn)入內(nèi)核,不需要切換線程;
  • b、沒(méi)有死鎖:總線鎖最長(zhǎng)持續(xù)為一次read+write的時(shí)間;
  • c、只有寫(xiě)操作需要使用CAS,讀操作與串行代碼完全相同,可實(shí)現(xiàn)讀寫(xiě)不互斥。

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

2.2.2鎖

主要類(lèi)關(guān)系:

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

2.2.2.1AQS

  • 鎖是面向用戶(hù)的,同步器是面向鎖的(就是鎖的內(nèi)部實(shí)現(xiàn)),AQS支持互斥鎖,共享鎖的實(shí)現(xiàn)。
  • AQS實(shí)現(xiàn)一個(gè)FIFO等待隊(duì)列。
  • 通過(guò)對(duì)state的原子修改來(lái)實(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:用于阻塞或者喚醒線程,屬于工具類(lèi),不和鎖關(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說(shuō)明)
  • 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說(shuō)明)
  • 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ì)列
  • 性能問(wèn)題:(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)讀寫(xiě)鎖的緣由:當(dāng)多讀少寫(xiě)時(shí),使用讀寫(xiě)鎖比使用互斥鎖具有更高的并發(fā)性
  • 特點(diǎn):(讀鎖可以并發(fā)訪問(wèn),寫(xiě)鎖時(shí)其他的讀鎖和其他的寫(xiě)鎖都被阻塞
  • 主要依據(jù)32位的int類(lèi)型的state的低16位的值表示寫(xiě)鎖(為互斥鎖);高16位的值表示讀鎖(為共享鎖)
  • 通過(guò)位運(yùn)算把state值拆分為2個(gè)值:假設(shè)當(dāng)前狀態(tài)為s
  • 寫(xiě)狀態(tài):s & (1 << 16) - 1 即:s&65535,也就是s與16個(gè)1(2進(jìn)制的),這樣就把高16位抹去了;當(dāng)寫(xiě)狀態(tài)+1時(shí),即為s+1,只給低位加。
  • 讀狀態(tài):s>>>16 ,表示無(wú)符號(hào)補(bǔ)0右移16位;當(dāng)讀狀態(tài)+1時(shí),等于s+(1<<16),結(jié)果就是只給高位加
  • 鎖降級(jí))流程:先獲取寫(xiě)鎖,在獲取讀鎖,在釋放寫(xiě)鎖,在釋放讀鎖(不支持鎖升級(jí))

2.2.3容器

主要并發(fā)容器


并發(fā)容器

2.2.3.1隊(duì)列

  • 阻塞隊(duì)列主要方法說(shuō)明:
  • [add:remove]沒(méi)有值或隊(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開(kāi)始 。
    • while和if的選擇?
    • 必須使用while,因?yàn)樵趕ignal()take1線程時(shí),只會(huì)從阻塞隊(duì)列轉(zhuǎn)移到同步隊(duì)列(不見(jiàn)得會(huì)獲取鎖真正喚醒), 此時(shí)可能已經(jīng)有其他take2線程獲取到了鎖,把隊(duì)列中僅有的元素移除了,此時(shí)take2線程執(zhí)行完后是釋放鎖,喚醒后 繼節(jié)點(diǎn)也就是take1線程。此時(shí)take1線程應(yīng)該再次判斷,條件不滿足繼續(xù)阻塞。
    • 能否通過(guò)公平鎖或不公平鎖避免這個(gè)問(wèn)題? 不能,因?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í)行;不符合跳過(guò),while:多使用于多線程喚醒后的再次檢查條件
    • signal和signalAll:使用這倆個(gè)都可以,只不過(guò)只會(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è)無(wú)界阻塞隊(duì)列,雖然此隊(duì)列邏輯上是無(wú)界的,但是資源被耗盡時(shí)試圖執(zhí)行 add 操作也將失敗,導(dǎo)致 OutOfMemoryError。不支持先進(jìn)先出原則
  • 由于隊(duì)列是無(wú)界的,所以put方法不會(huì)由于滿了(始終不會(huì)滿)而導(dǎo)致阻塞 。
  • 不保證具有同等優(yōu)先級(jí)的元素的順序
  • 入隊(duì)(通過(guò)比較找到合適位置入隊(duì))相同(值相等)元素不會(huì)覆蓋,出對(duì)從隊(duì)列頭出隊(duì)
  • DelayQueue:一個(gè)無(wú)界阻塞隊(duì)列,內(nèi)部根據(jù)PriorityQueue(無(wú)界線程不安全隊(duì)列) 存儲(chǔ)元素,適用場(chǎng)景:定時(shí)執(zhí)行(獲?。?,緩存失效等
  • LinkedBlockingDeque:鏈表實(shí)現(xiàn)的有界阻塞雙端隊(duì)列,支持同端存取(FILO)和異端存?。‵IFO)。如果未指定容量,那么容量將等于 Integer.MAX_VALUE
  • LinkedTransferQueue:一個(gè)鏈表實(shí)現(xiàn)的無(wú)界阻塞隊(duì)列
    • tryTransfer()嘗試傳遞給消費(fèi)者 ,沒(méi)有消費(fèi)者放入隊(duì)列
    • transfer()嘗試傳遞給消費(fèi)者 ,沒(méi)有消費(fèi)者自己處于阻塞狀態(tài),這種模式類(lèi)似與SynchronousQueue
    • 無(wú)論是transfer還是tryTransfer方法,在>=1個(gè)消費(fèi)者線程等待獲取元素時(shí)(此時(shí)隊(duì)列為空),都會(huì)立刻轉(zhuǎn)交,這屬于線程之間的元素交換。注意,這時(shí),元素并沒(méi)有進(jìn)入隊(duì)列。
    • 在隊(duì)列中已有數(shù)據(jù)情況下,transfer將需要等待前面數(shù)據(jù)被消費(fèi)掉,直到傳遞的元素e被消費(fèi)線程取走為止。
  • SynchronousQueue:一個(gè)不存儲(chǔ)元素的阻塞隊(duì)列
    • 其中每個(gè)插入操作必須等待另一個(gè)線程的對(duì)應(yīng)移除操作,如果沒(méi)被消費(fèi)則一直處于阻塞
    • 此同步隊(duì)列沒(méi)有任何內(nèi)部容量,甚至連一個(gè)隊(duì)列的容量都沒(méi)有,適合傳遞性的應(yīng)用場(chǎng)景

2.2.3.2Copy-On-Write簡(jiǎn)稱(chēng)COW,僅2個(gè)類(lèi)Set和List

  • Copy-On-Write簡(jiǎn)稱(chēng)COW,是一種用于程序設(shè)計(jì)中的優(yōu)化策略,采用數(shù)組存儲(chǔ)。
  • 使用場(chǎng)景:多讀少寫(xiě)(讀不加鎖,寫(xiě)會(huì)加鎖,防止多個(gè)線程多多個(gè)拷貝同時(shí)造成數(shù)據(jù)混亂,所以會(huì)加鎖防止此問(wèn)題)
  • 寫(xiě)時(shí)采用復(fù)制新的容器,進(jìn)行修改;新容器為原容器中對(duì)象的引用,使用完把新容器賦值給類(lèi)的原有容器引用。復(fù)制新的容器時(shí),這是一個(gè)比較耗費(fèi)性能的操作
  • CopyOnWriteArraySet 采用CopyOnWriteArrayList 作為存儲(chǔ)?;静畈欢?/li>
  • CopyOnWrite的缺點(diǎn)
    • 內(nèi)存占用問(wèn)題。因?yàn)镃opyOnWrite的寫(xiě)時(shí)復(fù)制機(jī)制,所以在進(jìn)行寫(xiě)操作的時(shí)候,內(nèi)存里會(huì)同時(shí)駐扎兩個(gè)對(duì)象的內(nèi)存,舊的對(duì)象和新寫(xiě)入的對(duì)象

      (注意:在復(fù)制的時(shí)候只是復(fù)制容器里的引用,只是在寫(xiě)的時(shí)候會(huì)創(chuàng)建新對(duì)象添加到新容器里,而舊容器的對(duì)象還在使用,所以有兩份對(duì)象內(nèi)存)。
    • 數(shù)據(jù)一致性問(wèn)題。CopyOnWrite容器只能保證數(shù)據(jù)的最終一致性,不能保證數(shù)據(jù)的實(shí)時(shí)一致性。所以如果若希望寫(xiě)入的的數(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無(wú)鎖更新
  • ConcurrentHashMap
  • 1.代碼體積約6000行
  • 2.java1.8 ConcurrentHashMap 和 HashMap 結(jié)構(gòu)一樣 ,在put操作時(shí),當(dāng)數(shù)組索引位置大于1時(shí)進(jìn)行加鎖操作
  • 3.size()(或 mappingCount()) 使用無(wú)鎖操作,返回并非準(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ù)組+單向鏈表(或紅黑樹(shù))
      • 3.get() 使用無(wú)鎖操作,取不到直接返回空
  • 5.1.8中的鎖力度更小,數(shù)據(jù)結(jié)構(gòu)更簡(jiǎn)單
  • 6.CounterCell何時(shí)使用 沒(méi)有理解透徹?
  • ConcurrentLinkedDeque
    • 1.代碼體積約1500行
    • 2.一個(gè)無(wú)界線程安全雙向鏈表
    • 3.使用unsafe 保證原子性
  • ConcurrentLinkedQueue
    • 一個(gè)無(wú)界線程安全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表、紅黑樹(shù)、SkipList

名稱(chēng) 描述
hash表 即數(shù)組:例如:Hashmap(Hash表+鏈表+紅黑樹(shù)),HashTbale(Hash表+鏈表) 插入、查找最快,為O(1);如使用鏈表實(shí)現(xiàn)則可實(shí)現(xiàn)無(wú)鎖;數(shù)據(jù)有序化需要顯式的排序操作。
紅黑樹(shù) 例如:TreeMap 插入、查找為O(logn),但常數(shù)項(xiàng)較小;無(wú)鎖實(shí)現(xiàn)的復(fù)雜性很高,一般需要加鎖;數(shù)據(jù)天然有序。
Skip表 例如:ConcurrentSkipListMap,插入、查找為O(logn),但常數(shù)項(xiàng)比紅黑樹(shù)要大;底層結(jié)構(gòu)為鏈表,可無(wú)鎖實(shí)現(xiàn);數(shù)據(jù)天然有序。

2.2.4線程池

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

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

2.2.4.1ExecutorCompletionService

  • CompletionService實(shí)現(xiàn)了生產(chǎn)者提交任務(wù)和消費(fèi)者獲取結(jié)果的解耦,消費(fèi)者一定是按照任務(wù)完成的先后順序來(lái)獲取執(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類(lèi)型的任務(wù) ,提交的 Runnable 也會(huì)轉(zhuǎn)化為Callable。
    • 從類(lèi)型上講: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è)置原則
    • 無(wú)界隊(duì)列:大小線程數(shù)建議設(shè)置成一致,如果使用無(wú)界隊(duì)列 ,就不可能使用最大線程數(shù)
    • 有界隊(duì)列:大小線程數(shù)可以不一致(當(dāng)有界隊(duì)列特別大時(shí),也沒(méi)有必要把core和max設(shè)置的不一樣, 因?yàn)榭赡芎茈y達(dá)到有界的最值,也就更難達(dá)到max的值了)
  • 繼承關(guān)系:
    Executor->ExecutorService->AbstractExecutorService->ThreadPoolExecutor
  • 理解線程復(fù)用?(難點(diǎn))
  • ScheduledThreadPoolExecutor
  • ScheduledExecutorService的實(shí)現(xiàn)類(lèi)ScheduledThreadPoolExecutor是繼承線程池類(lèi)ThreadPoolExecutor的,因此它擁有線程池的全部特性。但是同時(shí)又是一種特殊的線程池,這個(gè)
    線程池的線程數(shù)大小最大Integer最大值,任務(wù)隊(duì)列是基于DelayQueue的無(wú)限任務(wù)隊(duì)列。
    主要提供定時(shí)執(zhí)行功能,通過(guò)延時(shí)隊(duì)列實(shí)現(xiàn)
  • 繼承關(guān)系:
    Executor->ExecutorService->AbstractExecutorService->ThreadPoolExecutor->ScheduledExecutorService
  • scheduleAtFixedRate【不關(guān)注上次線程執(zhí)行完成】和scheduleWithFixedDelay【關(guān)注上次線程執(zhí)行完成】
  • 功能效果和Timer類(lèi)似

2.2.4.4拒絕策略

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

2.2.5框架

  • Executors
    • 也可以認(rèn)為是創(chuàng)建線程池的一個(gè)工具類(lèi)
    • 提供創(chuàng)建線程池的一些靜態(tài)方法
  • Fork/Join
  • Fork/Join實(shí)現(xiàn)了“工作竊取算法”,F(xiàn)orkJoinTask需要通過(guò)ForkJoinPool來(lái)執(zhí)行,任務(wù)分割出的子任務(wù)會(huì)添加到當(dāng)前工作線程所維護(hù)的雙端隊(duì)列中,進(jìn)入隊(duì)列的頭部。當(dāng)一個(gè)工作線程的隊(duì)列里暫時(shí)沒(méi)有任務(wù)時(shí),它會(huì)隨機(jī)從其他工作線程的隊(duì)列的尾部獲取一個(gè)任務(wù)。
  • Fork/Join框架的設(shè)計(jì)主要2步任務(wù)
    • 第一步分割任務(wù)。首先我們需要有一個(gè)fork類(lèi)來(lái)把大任務(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的子類(lèi):

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

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

2.2.6工具類(lèi)

  • CountDownLatch : 基于AQS共享鎖的實(shí)現(xiàn),當(dāng)state為0時(shí)喚醒等待的一個(gè)或一組線程
  • CyclicBarrier : 內(nèi)部維護(hù)一個(gè)count 當(dāng)count為0時(shí),等待的線程開(kāi)始運(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í),如果一直沒(méi)有被消費(fèi)完,線程將處于阻塞狀態(tài)
  • Semaphore:
    • 基于AQS共享鎖的實(shí)現(xiàn)
    • Semaphore可以應(yīng)用于流量控制,比如對(duì)數(shù)據(jù)庫(kù)的連接數(shù)控制

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

并發(fā)常見(jiàn)問(wèn)題

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)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容