Java高併發程式設計
第一章 走入並行世界
關於並行的兩個定律: Amdahl定律 和Gustafson定律 考慮方向不同
Java記憶體模型 JMM 原子性 可見性 有序性
第二章 Java並行程式基礎
執行緒建立: new Thread(Runable).start()
執行緒終止: stop 方法 會立即釋放鎖,導致資料不一致問題,已經廢棄
執行緒中斷: interrupt() 設定中斷標識,run方法中可以依靠這個做執行緒退出的邏輯處理Thread.interrupted()用來判斷
等待和通知:wait()和notify()必須在synchronized中,涉及到鎖的操作
掛起和繼續執行:suspend 和 resume 已經廢棄
等待執行緒結束和謙讓:
如果一個執行緒A依賴另外一個執行緒B,那就在A中執行B.join() 即 A要等待執行緒B結束
yield()是讓出CPU資源,但是還是會進行資源競爭.
volatile關鍵字:保證執行緒間的可見性和禁止執行重排(有序性)但是不能保證原子性 JMM
守護執行緒: daemon 後臺執行緒,當用戶執行緒都結束時,守護執行緒也會結束,如垃圾回收執行緒
第三章 JDK併發包
1.同步控制
1.1可重入鎖 ReentrantLock
ReentrantLock lock = new ReentrantLock()
lock.lock() 加鎖
lock.unlock解鎖
對同一個執行緒而言,可以重複的加鎖,也要解相同次數的鎖才行
中斷響應: lock.lockInterruptibly() 會對thread.interrupt()丟擲異常,對其進行處理即可
限時申請鎖: lock.tryLock(time,timeUnit.xxx) 在限定時間內申請獲取鎖,成功返回true 失敗返回false
公平鎖: ReentrantLock lock = new ReentrantLock(true) 預設非公平,公平鎖需要維護一個執行緒申請鎖的佇列
1.2 重入鎖好搭檔: Conditon 條件
Condition condition = lock.newCondition()
condition的用法類似於object.wait() 和 object.notify()
await()方法會使當前執行緒等待,同時釋放當前鎖,當其他執行緒中使用signal()或者signalAll()方法是,執行緒活重新獲取鎖,繼續執行.
當前執行緒被中斷時也能跳出等待.
awaitUninterruptibly() 和 await()類似,但是不會中斷相應
singal()喚醒一個執行緒,singalAll()喚醒所有執行緒.
併發容器中使用兩個condition實現佇列的take和put的阻塞.見ArrayBlockingQueue原始碼
1.3 允許多執行緒同時訪問: 訊號量 Semaphore
Semaphore (int permits) 或者 Semaphore (int permits,boolean fair) 數量 和 公平
大家看方法就能猜如來如何使用了
acquire() 獲取一個憑證
acquireUninterruptibly() 獲取憑證對中斷響應
tryAcquire() 不等待獲取憑證 類似 tryLock()
tryAcquire(timeout,unit) 指定時間內獲取憑證
release() 釋放憑證
1.4 ReadWriteLock 讀寫鎖
ReentrantReadWriteLock readWriteLock = new ReentrantReadWriteLock ();
Lock readLock = readWriteLock.readLock(); 讀鎖
Lock writeLock = readWriteLock.writeLock(); 寫鎖
讀讀不互斥,寫寫互斥,讀寫互斥.
1.5 CountDownLatch 倒計時器
這個很常見不就寫了
1.6 迴圈柵欄: CyclicBarrier
和CountDownLatch類似但比其強大.
CyclicBarrier(int parties,Runnable barrieraction)
迴圈柵欄會阻塞 xxx.await()直到滿足數目才讓執行緒一起向下執行,且在此之前會執行一次 barrieraction中run方法
1.7 執行緒阻塞工具類: LockSupport
它可以線上程內任意位置讓執行緒阻塞.
LockSupport.park() 可以阻塞當前執行緒,類似的還有parkNanos(),parkUntil()等實現一個閒時的阻塞
LockSupprot.unpark(Thread) 釋放指定執行緒的阻塞
2. 執行緒複用:執行緒池
這個就不浪費筆墨了,依託底層 ThreadPoolExecutor實現了幾種常用的執行緒池工具,大家應該都明白的.
執行緒池可以根據自己的需求進行相應的自定義處理:
ThreadPoolExecutor提供了beforeExecute() ,afterExecute(),terminated() 方法對其進行控制.
執行緒數量選取: Nthreads = Nepu * Ucpu * ( 1 + W/C) 即 cpu數量 * 目標Cpu使用率 *(1 + 等待時間與計算時間比)
分而治之:Fork/Join框架
ForkJoinPool.submit(ForkJoinTask) 提交任務 task.fork() 執行結束後 使用 task.join收集結果
3. JDK併發容器
1. 併發集合
ConcurrenHashMap
CopyOnWriteArrayList
ConcurrentLinkedQueue
BlockingQueue
ConcurrentSkipListMap
2. 高效讀寫佇列:深度剖析 ConcurentLinkedQueue
主要通過CAS(比較交換)操作和對head及tail的演算法實現高效的讀寫
3. 高效讀取: 不變模式下的CopyOnWriteArrayList
任何讀取操作沒有鎖相關操作,但是寫入時候.會加鎖,複製原來的集合寫一個新集合後替換老集合.
4. 資料共享通道: BlockingQueue
前面說過其take和put的通過兩個condition裡相互通知實現阻塞.
5.隨機資料結構:跳錶(SkipList)
維護多層連結串列,連結串列分層,通過空間換時間的方法來實現高速的查詢.