天天看點

Java并發知識點總結

1.Thread類的sleep方法和Object類wait方法對比. sleep讓目前線程暫停指定時間,不釋放鎖,結束後回到就緒狀态. wait方法導緻目前線程放棄對象的鎖,線程暫停,進入等待池,調用notify時,喚醒并進入等鎖池.

2.sleep()方法和yield()方法差別 4個     sleep将方法讓個其他線程不考慮線程的優先級,yield會優先個優先級高的線程.     yield執行直接進入就緒狀态.     sleep抛出異常(interrupted exception),yield沒有異常     sleep移植性好.

3.編寫多線程的三個方法   implements runnable            需要重寫run()   extends Thread                     需要重寫run()   implements callable              與 Runnable 相比,Callable 可以有傳回值,傳回值通過 FutureTask 進行封裝。

4.線程ExectorService有四種 線程池: 為了避免系統頻繁的建立和銷毀線程,我們可以将建立的線程進行複用。資料庫中的資料庫連接配接池也是此意。

  • newCachedThreadPool建立一個可緩存線程池,如果線程池長度超過處理需要,可靈活回收空閑線程,若無可回收,則建立線程。
  • newFixedThreadPool 建立一個定長線程池,可控制線程最大并發數,超出的線程會在隊列中等待。
  • newScheduledThreadPool 建立一個定長線程池,支援定時及周期性任務執行。定時執行
  • newSingleThreadExecutor 建立一個單線程化的線程池,它隻會用唯一的工作線程來執行任務,保證所有任務按照指定順序(FIFO, LIFO, 優先級)執行。

5.線程池構造方法

Java并發知識點總結

參數含義

Java并發知識點總結

**盡量避免用Executors建立線程池

Java并發知識點總結

6.線程池shutdown和shutdownnow的差別 shutdown會讓正在執行的線程執行完之後在進行停止,shutdownnow會立即停止.

7.submit() ,execute() Future比較 使用 submit(Runnable task)  的時候, 錯誤的堆棧資訊跑出來的時候會被内部捕獲到,是以列印不出來具體的資訊讓我們檢視 ,解決的方法有如下兩種: 1、使用execute()代替submit();2.Future

Java并發知識點總結

8.線程狀态圖

Java并發知識點總結

9. volatile關鍵字在Java中有什麼作用?

用來保證可見性和有序性。不具有原子性。 被關鍵了volatile修飾的變量,可以保證修改後的資料立即更新到主存,其他線程直接到主存中去取。 volatile通過靜止了指令重排來在一定程度上保證有序性。 應用場景: volatile在某些情況下優于synchronized 1.對變量的寫操作不依賴于目前值。(簡單來說不存在原子性操作) 2.該變量沒有包含在其他變量的不變式中 應用: 1.狀态标記量 2.雙重校驗

10. 什麼是ThreadLocal?

ThreadLocal用于 建立線程的本地變量,我們知道一個對象的所有線程會共享它的全局變量,是以這些變量不是線程安全的,我們可以使用同步技術。但是當我們不想使用同步的時候,我們可以選擇ThreadLocal變量。 每個線程都會擁有他們自己的Thread變量,它們可以使用get()\set()方法去擷取他們的預設值或者線上程内部改變他們的值。ThreadLocal執行個體通常是希望它們同線程狀态關聯起來是private static屬性。在 ThreadLoc al例子這篇文章中你可以看到一個關于ThreadLocal的小程式。 ThreadLocal類用于建立一個線程本地變量 在Thread中有一個成員變量ThreadLocals,該變量的類型是ThreadLocalMap,也就是一個Map,它的鍵是threadLocal,值為就是變量的副本。通過ThreadLocal的get()方法可以擷取該線程變量的本地副本,在get方法之前要先set,否則就要重寫initialValue()方法。 ThreadLocal的使用場景:         資料庫連接配接:在多線程中,如果使用懶漢式的單例模式建立Connection對象,由于該對象是共享的,那麼必須要使用同步方法保證線程安全,這樣當一個線程在連接配接資料庫時,那麼另外一個線程隻能等待。這樣就造成性能降低。如果改為哪裡要連接配接資料庫就來進行連接配接,那麼就會頻繁的對資料庫進行連接配接,性能還是不高。這時使用ThreadLocal就可以既可以保證線程安全又可以讓性能不會太低。但是ThreadLocal的缺點時占用了較多的空間。

11. 什麼是Java Timer類?如何建立一個有特定時間間隔的任務?

java.util.Timer是一個工具類,可以用于安排一個線程在未來的某個特定時間執行。Timer類可以用安排一次性任務或者周期任務。

12.線程和程序 程序:是程式的一次執行,動态且占用資源, 是系統進行資源配置設定和排程的基本機關. 線程:是一個微量實體, 是程式執行流的最小單元。 是系統獨立排程和分派CPU的基本機關.

13.sychronized可重入鎖,為什麼要引入重入鎖 當一個線程得到一個對象的鎖後,在該鎖裡執行代碼的時候可以再次請求該對象的鎖時可以再次得到該對象的鎖。 自己可以擷取自己的内部鎖。

最大的作用是 避免死鎖。 假如有一個場景:使用者名和密碼儲存在本地txt檔案中,則登入驗證方法和更新密碼方法都應該被加synchronized,那麼當更新密碼的時候需要驗證密碼的合法性,是以需要調用驗證方法,此時是可以調用的 可重入鎖的其他特性:父子可繼承性。

14.sychronized其他特性 (1)出現異常時,鎖自動釋放 (2)将任意對象作為螢幕(對象鎖) (3)單例模式-雙重校驗鎖的

15.線程同步的方法 1.sychronized同步方法 2.sychronized同步塊 3.ReentrantLock 重入鎖

16.ReentrapLock private Lock lock; public int func(int value) {    try {        lock.lock();        // ...    } finally {       lock.unlock();    } } ReentrantLock 是 java.util.concurrent(J.U.C)包中的鎖,相比于 synchronized,它多了一些進階功能: 1.等待可中斷  :( 當持有鎖的線程長期不釋放鎖的時候,正在等待的線程可以選擇放棄等待,執行其他任務) 2.可實作公平鎖      公平鎖是指多個線程在等待同一個鎖時,必須 按照申請鎖的時間順序來依次獲得鎖 ;而非公平鎖則不保證這一點,在鎖被釋放時,任何一個等待鎖的線程都有機會獲得鎖。synchronized 中的鎖是非公平的,ReentrantLock 預設情況下也是非公平的,但可以通過帶布爾值的構造函數要求使用公平鎖。 3.鎖綁定多個條件  *Lock和Sychronized的差別: 1. synchronized 是 JVM 實作的,而 ReentrantLock 是 JDK 實作的。 2. 在新版本的 JDK 中對 synchronized 進行了很多優化,例如自旋鎖等。性能基本持平,優先考慮Sychronized

17.BlockingQueue java.util.concurrent.BlockingQueue 接口有以下阻塞隊列的實作:

  • FIFO 隊列 :LinkedBlockingQueue、ArrayListBlockingQueue(固定長度)
  • 優先級隊列 :PriorityBlockingQueuejava.util.concurrent.BlockingQueue 接口有以下阻塞隊列的實作:

提供take()和put()方法  *是線程安全的 用阻塞隊列寫生産消費模型 // 生産者 public class Producer implements Runnable { private BlockingQueue< String > queue;

public Producer ( BlockingQueue< String > queue ) { this . queue = queue; }

@Override public void run () { System . out . println( Thread . currentThread() . getName() + " is making product. " ); String product = " Made By " + Thread . currentThread() . getName(); try { queue . put(product); } catch ( InterruptedException e) { e . printStackTrace(); } } } // 消費者 public class Consumer implements Runnable { private BlockingQueue< String > queue;

public Consumer ( BlockingQueue< String > queue ) { this . queue = queue; }

@Override public void run () { try { String product = queue . take(); System . out . println( Thread . currentThread() . getName() + " is consuming product. " + " ( " + product + " ) " ); } catch ( InterruptedException e) { e . printStackTrace(); } } } // 用戶端 public class Client { public static void main ( String [] args ) { BlockingQueue< String > queue = new LinkedBlockingQueue<> ( 5 ); for ( int i = 0 ; i < 2 ; i ++ ) { new Thread ( new Consumer (queue), " Consumer- " + i) . start(); } for ( int i = 0 ; i < 5 ; i ++ ) { // 隻有兩個 Product,是以隻能消費兩個,其它三個消費者被阻塞 new Thread ( new Producer (queue), " Producer- " + i) . start(); } for ( int i = 2 ; i < 5 ; i ++ ) { new Thread ( new Consumer (queue), " Consumer- " + i) . start(); } } } // 運作結果 Producer-0 is making product. Consumer-0 is consuming product.( Made By Producer-0 ) Producer-1 is making product. Consumer-1 is consuming product.( Made By Producer-1 ) Producer-2 is making product. Producer-3 is making product. Producer-4 is making product. Consumer-2 is consuming product.( Made By Producer-2 ) Consumer-3 is consuming product.( Made By Producer-3 ) Consumer-4 is consuming product.( Made By Producer-4 )    18.關于J.U.C, Java.util.concurrent  CAS(比較交換政策) 1.CountDownLatch :用來控制一個線程等地多個線程(cnt遞減) 2.CyclicBarrier: 用來控制多個線程互相等待,隻有多個線程都到達時,線程才會繼續執行.(cnt遞增) 3.Semaphore:  就是作業系統中的信号量,可以控制互斥資源的通路數. 4.FutureTask:  接口,繼承自Runnable.Futrure,可以封裝任務,而且有傳回值.(futuretask.get() ) 5.BlockingQueue<> : 阻塞隊列,兩種實作     ① FIFO  : LinkedBlockingQueue  ArrayListBlockingQueue     ② 優先級隊列:PriorityBlockingQueue 6.ForkJoin :主要用于并行計算,把大任務化成小任務進行計算

* Java中CyclicBarrier 和 CountDownLatch有什麼不同?

CyclicBarrier 和 CountDownLatch 都可以用來讓一組線程等待其它線程。與 CyclicBarrier 不同的是,CountdownLatch 不能重新使用。 點此檢視更多資訊和示例代碼 。

19.如何定時完成一項任務 1.用Thread類裡的sleep方法 2.Timer類 3. java.util.concurrent裡的 ScheduledExecutorService Link

20.JVM中Synchronized的底層實作 Sychronized底層是由JVM實作.本質是一個對象螢幕(monitor) 任何對象都有一個 monitor 與之關聯,當且一個monitor 被持有後,它将處于鎖定狀态。線程執行到 monitorenter 指令時,将會嘗試擷取對象所對應的 monitor 的所有權,即嘗試獲得對象的鎖。

synchronized用的鎖是存放在對象頭中的  對象頭:(2word) Mark Word: 存儲對象的hashCode或鎖資訊等。 Klass Pointer: 存儲到對象類型資料的指針

1.對于普通方法,鎖是目前執行個體對象。 2.對于靜态同步方法,鎖是class對象。 3.同步方法塊,鎖是synchronized後面括号裡的對象。

Java并發知識點總結

21.Synchronized的鎖優化 鎖優化包括: 如自旋鎖、适應性自旋鎖、鎖消除、鎖粗化、偏向鎖、輕量級鎖等 鎖主要存在四中狀态,依次是: 無鎖狀态、偏向鎖狀态、輕量級鎖狀态、重量級鎖狀态   * 可以更新不可降級,這種政策是為了提高獲得鎖和釋放鎖的效率。

自旋鎖:  目的: 頻繁的阻塞和喚醒對CPU來說是一件負擔很重的,有些場景,對象鎖的狀态持續時間短 實作過程: 自旋鎖讓線程等待一會,去執行一個無意義的循環.不會被立即挂起.避免狀态切換帶來的資源開銷. 缺點: 對處理器核數有要求,占用處理器時間,遇到線程長時間不釋放鎖,對性能浪費. 優化: 自旋 預設次數為10次,可以通過參數-XX:PreBlockSpin來調整;(不好)

适應性自旋鎖: 自旋的次數不再是固定的,它是由前一次在同一個鎖上的自旋時間及鎖的擁有者的狀态來決定。

消除鎖: 當JVM檢測到不共享資料競争,這時會對同步鎖進行鎖消除。鎖消除的依據是逃逸分析的資料支援。

鎖粗化: 就是将多個連續的加鎖、解鎖操作連接配接在一起,擴充成一個範圍更大的鎖。 

輕量級鎖: 在多沒有多線程競争的前提下,減少傳統的重量級鎖使用作業系統互斥量産生的性能消耗。當關閉偏向鎖功能或者多個線程競争偏向鎖導緻偏向鎖更新為輕量級鎖,則會嘗試擷取輕量級鎖,

偏向鎖: 偏向鎖主要解決無競争下的鎖性能問題, 一旦線程第一次獲得了監視對象,之後讓監視對象“偏向”這個線程

重量級鎖: 重量級鎖通過對象内部的螢幕(monitor)實作,其中monitor的本質是依賴于底層作業系統的Mutex Lock實作,作業系統實作線程之間的切換需要從使用者态到核心态的切換,切換成本非常高。

22.系統記憶體模型相關概念 高速緩存cache: cpu在寄存器上執行指令時候,會涉及到資料的讀取和寫入,由于資料是存放在主存裡,而且 由于CPU執行速度很快,而從記憶體讀取資料和向記憶體寫入資料的過程跟CPU執行指令的速度比起來要慢的多. 是以在CPU裡面就有了高速緩存。 當程式在運作過程中,會将運算需要的資料從主存複制一份到CPU的高速緩存當中,那麼CPU進行計算時就可以直接從它的高速緩存讀取資料和向其中寫入資料,當運算結束之後,再将高速緩存中的資料重新整理到主存當中。

通過cache緩存在多線程會出現緩存不一緻問題.

為解決緩存不一緻問題,硬體層面提出的解決方案: 1.在總線加Lock#鎖 (隻能有一個cpu來操作變量,效率低) 2.緩存一緻性協定MESL ( 保證了 每個緩存中使用的共享變量的副本是一緻的。)

23.JAVA記憶體模型 JMM : 用 來屏蔽各個硬體平台和作業系統的記憶體通路差異,以實作讓Java程式在各種平台下都能達到一緻的記憶體通路效果。 JAVA記憶體模型 也會出現緩存不一緻和指令重排問題.

Java記憶體模型分為 : 主記憶體和工作記憶體 (類似主存和高速緩存關系)   如何保證并發特性?

  • 原子性: 在Java中,對基本資料類型的變量的讀取和指派操作是原子性操作,即這些操作是不可被中斷的,要麼執行,要麼不執行。   

* i++不滿足原子性操作,應為i++需要先從主存讀取i值,再在工作記憶體+1,再将新的值寫入主存。 * 記憶體模型隻有簡單的讀取,指派才是原子性操作,實作更大範圍的操作,需要用Synchronized或Lock或AtomicInteger來實作。  *在32位作業系統中,對64位資料進行讀寫指派操作也不是原子性的

  • 可見性:一個線程修改了共享變量的值,其他線程可以立刻得知這個修改。普通共享變量不能實作可見性。因為不知道什麼時候将修改的值寫入主存。

*Java提供volatile來保證可見性(被v修飾的變量會立刻更新到主存,其他線程直接去主存裡取) *Synchronized和Lock也可以保證。(會在釋放鎖之前将資料更新到主存)         

  • 有序性: 在Java記憶體模型中,允許編譯器和處理器進行指令重排序,但是重排序過程不會影響到單線程程式的執行(重排是會考慮指令之間資料依賴性),卻會影響到多線程并發執行的正确性。

*java記憶體模型具有先天有序性。(通過happens-before原則) *通過volatile來保證有序性。( 通過添加記憶體屏障的方式來禁止指令重排) *通過Synchronized和Lock也能保證

24.先行發生原則(happens-before) 1.程式次序原則 2.管城鎖定原則 3.volitle變量原則 4.傳遞原則 5.線程啟動原則 6.線程終止原則 7.線程中斷原則 8.對象終結原則

總結待補充ing...

繼續閱讀