java多線程知識點總結


1.什么是進程和線程

進程:程序運行資源分配的最小單位,進程內部有多個線程,會共享這個進程的資源

線程:CPU調度的最小單位,必須依賴進程而存在。

 

1、進程是資源分配的最小單位,線程是程序執行的最小單位(資源調度的最小單位)
2、進程有自己的獨立地址空間,每啟動一個進程,系統就會為它分配地址空間,建立數據表來維護代碼段、堆棧段和數據段,這種操作非常昂貴。
而線程是共享進程中的數據的,使用相同的地址空間,因此CPU切換一個線程的花費遠比進程要小很多,同時創建一個線程的開銷也比進程要小很多。
3、線程之間的通信更方便,同一進程下的線程共享全局變量、靜態變量等數據,而進程之間的通信需要以通信的方式(IPC)進行。不過如何處理好同步與互斥是編寫多線程程序的難點。
4、但是多進程程序更健壯,多線程程序只要有一個線程死掉,整個進程也死掉了,而一個進程死掉並不會對另外一個進程造成影響,因為進程有自己獨立的地址空間

2. 新起線程方法

 

兩種方法:繼承類Thread

 

實現接口 Runnable

 

為什么要類,也要接口。因為JAVA單繼承,類只能繼承一個

 

接口 Callable  Runnable 區別:Callable 有返回值

 

3.怎么樣才能讓Java里的線程安全停止工作呢

 

線程自然終止:自然執行完或拋出未處理異常

 

stop()resume(),suspend()已不建議使用,stop()會導致線程不會正確釋放資源,suspend()不釋放資源容易導致死鎖。

 

java線程是協作式,而非搶占式

 

調用一個線程的interrupt() 方法中斷一個線程,並不是強行關閉這個線程,只是跟這個線程打個招呼,將線程的中斷標志位置為true,線程是否中斷,由線程本身決定。

 

isInterrupted() 判定當前線程是否處於中斷狀態。

 

static方法interrupted() 判定當前線程是否處於中斷狀態,同時中斷標志位改為false

 

方法里如果拋出InterruptedException,線程的中斷標志位會被復位成false,如果確實是需要中斷線程,要求我們自己在catch語句塊里再次調用interrupt()。

 

所有阻塞方法都會拋出InterruptedException

4.一個線程的生命周期(線程的方法)

新建線程調用start()方法進入就緒狀態,cpu分配或join()方法獲取執行權進入運行狀態,調用sleep()wait()進入阻塞狀態,sleep時間到或調用notifynotifyAll方法進入就緒狀態,運行時還可以調用yield方法讓步進入就緒狀態進行重新爭搶cpu

5.調用yield() sleep()wait()notify()等方法對鎖有何影響? 

線程在執行yield()以后持有的鎖是不釋放的

sleep()方法被調用以后,持有的鎖是不釋放的

調動方法之前必須要持有鎖調用了wait()方法以后,鎖就會被釋放,當wait方法返回的時候,線程會重新持有鎖

調動方法之前必須要持有鎖,調用notify()方法本身不會釋放鎖的

 

6.守護線程是什么

 

和主線程共死,finally不能保證一定執行

 

start之前setDaemon(true);設置守護線程,主線程運行完,子線程也結束。

 

7.synchronized內置鎖

 

對象鎖,鎖的是類的對象實例。

 

類鎖 ,鎖的是每個類的的Class對象,每個類的的Class對象在一個虛擬機中只有一個,所以類鎖也只有一個。

 

8.volatile關鍵字

 

適合於只有一個線程寫,多個線程讀的場景,因為它只能確保可見性。

 

9.ThreadLocal

   ThreadLocal是一個本地線程副本變量工具類。主要用於將私有線程和該線程存放的副本對象做一個映射,各個線程之間的變量互不干擾,在高並發場景下,可以實現無狀態的調用,特別適用於各個線程依賴不同的變量值完成操作的場景。

   ThreadLocal為變量在每個線程中都創建了一個副本,那么每個線程可以訪問自己內部的副本變量。

   該類中方法有

 public T get() { }
 public void set(T value) { }
 public void remove() { }
 protected T initialValue() { }

    get()方法是用來獲取ThreadLocal在當前線程中保存的變量副本,set()用來設置當前線程中變量的副本,remove()用來移除當前線程中變量的副本,initialValue()是一個protected方法,一般是用來在使用時進行重寫的,它是一個延遲加載方法,ThreadLocal沒有被當前線程賦值時或當前線程剛調用remove方法后調用get方法,返回此方法值。

線程變量。可以理解為是個map,類型 Map<Thread,T>

 

10.CountDownLatch

 

作用是一線程等待其他的線程完成工作以后在執行加強版join

await用來等待,countDown負責計數器的減一

 

11.CyclicBarrier

讓一組線程達到某個屏障,被阻塞,一直到組內最后一個線程達到屏障時,屏障開放,所有被阻塞的線程會繼續運行CyclicBarrier(int parties)

12.Semaphore

控制同時訪問某個特定資源的線程數量,用在流量控制

13.Exchange

兩個線程間的數據交換

14.CAS的原理

CAS(Compare And Swap),指令級別保證這是一個原子操作

基本思路:如果地址V上的值和期望的值A相等,就給地址V賦給新值B,如果不是,不做任何操作。

CAS可以有效的提升並發的效率,但同時也會引入ABA問題。

ABA問題可加入版本號進行標識是否有變更

    從Java1.5開始JDK的atomic包里提供了一個類AtomicStampedReference來解決ABA問題。這個類的compareAndSet方法作用是首先檢查當前引用是否等於預期引用,並且當前標志是否等於預期標志,如果全部相等,則以原子方式將該引用和該標志的值設置為給定的更新值。

 

15.Lock接口和synchronized的比較

synchronized jvm級別的鎖,代碼簡潔,LockJava語言級別的鎖,獲取鎖可以被中斷,超時獲取鎖,嘗試獲取鎖,讀多寫少用讀寫鎖

16.可重入鎖ReentrantLock所謂鎖的公平和非公平有什么區別

如果在時間上,先對鎖進行獲取的請求,一定先被滿足,這個鎖就是公平的,不滿足,就是非公平的

非公平的效率一般來講更高

節約了從掛起(排隊)到拿鎖的時間

17.AQS是什么

AbstractQueuedSynchronizer

實質上用雙向鏈表實現同步隊列

用AQS實現同步,首先線程獲取同步狀態失敗時,生成note節點加入同步隊列尾部(用CAS設置),判斷前驅是否為首節點,是的話嘗試獲取同步狀態,獲取成功將其設置為首節點,獲取不成功進入等待隊列,再去嘗試獲取同步狀態

競爭失敗的線程會打包成Node放到同步隊列

注:AQS實質上擁有一個同步隊列和多個等待隊列,具體對應關系如下圖所示:

上邊為同步隊列 雙向鏈表
下邊為condition等待隊列 單向鏈表
Await從同步隊列移動到等待隊列等待
Signal從等待隊列移動到同步隊列爭搶鎖

18.Concurrenthashmap實現原理

1.7及之前: ConcurrentHashMap是由Segment數組結構和HashEntry數組結構組成。Segment實際繼承自可重入鎖(ReentrantLock),在ConcurrentHashMap里扮演鎖的角色;HashEntry則用於存儲鍵值對數據。一個ConcurrentHashMap里包含一個Segment數組,每個Segment里包含一個HashEntry數組,我們稱之為table,每個HashEntry是一個鏈表結構的元素。

1.8

1、 取消了segment數組,直接用table保存數據,鎖的粒度更小,減少並發沖突的概率。

2、 存儲數據時采用了鏈表+紅黑樹的形式,純鏈表的形式時間復雜度為O(n),紅黑樹則為Ologn),性能提升很大。什么時候鏈表轉紅黑樹?當key值相等的元素形成的鏈表中元素個數超過8個的時候。

 

主要數據結構和關鍵變量

 

Node類存放實際的keyvalue,hash next

 

sizeCtl:

 

負數:表示進行初始化或者擴容,-1表示正在初始化,-N,表示有N-1個線程正在進行擴容

 

正數:0 表示還沒有被初始化,>0的數,初始化或者是下一次進行擴容的閾值

 

TreeNode 用在紅黑樹,表示樹的節點, TreeBin是實際放在table數組中的,代表了這個紅黑樹的根。

 

在高並發下的情況下如何保證取得的元素是最新的?

 

:用於存儲鍵值對數據的HashEntry,在設計上它的成員變量value等都是volatile類型的,這樣就保證別的線程對value值的修改,get方法可以馬上看到。

 

ConcurrentHashMap如何在保證高並發下線程安全的同時實現了性能提升?

 

答:ConcurrentHashMap允許多個修改操作並發進行,其關鍵在於使用了鎖分離技術。它使用了多個鎖來控制對hash表的不同部分進行的修改。內部使用段(Segment)來表示這些不同的部分,每個段其實就是一個小的hash table,只要多個修改操作發生在不同的段上,它們就可以並發進行。

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM