常見面試題
1穆端、線程狀態(tài)绘盟。
2概而、synchronized原理
3、對象頭包含哪些內(nèi)容
4掷豺、CAS原理
5捐下、講講aqs
6、volatile原理
7萌业、講講ThreadLocal
8坷襟、CountDownLatch了解嗎
9、線程池
1生年、線程狀態(tài)
線程狀態(tài) | 解釋 |
---|---|
NEW | 尚未啟動的線程狀態(tài)婴程,即線程創(chuàng)建,還未調(diào)用start方法 |
RUNNABLE | 就緒狀態(tài)(調(diào)用start抱婉,等待調(diào)度)+正在運行 |
BLOCKED | 等待監(jiān)視器鎖時档叔,陷入阻塞狀態(tài) |
WAITING | 等待狀態(tài)的線程正在等待另一線程執(zhí)行特定的操作(如notify) |
TIMED_WAITING | 具有指定等待時間的等待狀態(tài) |
TERMINATED | 線程完成執(zhí)行桌粉,終止狀態(tài) |
常用方法
wait()和sleep():
- wait屬于TIMED_WATING,自動被喚醒。屬于Object類的方法衙四。wait屬于WATING铃肯,需要手動喚醒
- sleep()只會讓出CPU,不會導致鎖行為的改變传蹈。Object.wait()不僅讓出CPU押逼,還會釋放鎖資源
- sleep()可以在持有鎖或者不持有鎖的時候執(zhí)行。wait()必須在持有鎖的時候才可以執(zhí)行
PS:為什么wait方法必須在持有鎖的時候才能執(zhí)行惦界?
wait方法會將持有鎖的線程從owner扔到waitSet集合中挑格,這個操作實在修改ObjectMonitor對象,如果沒有持有synchronized鎖的話沾歪,是無法操作ObjectMonitor對象的漂彤。
并發(fā)編程的三大特性
一、原子性
原子性指一個操作是不可分割的灾搏,不可中斷的挫望,一個線程在執(zhí)行時,另一個線程不會影響到他狂窑。
如何保證:
1士骤、synchronized
2、CAS
在CPU層面保障的一個原子性蕾域,
3、Lock鎖
二到旦、可見性
可見性是基于CPU位置出現(xiàn)的旨巷,CPU處理速度非常快添忘,相對CPU來說惹恃,去主存中獲取數(shù)據(jù)的話就太慢了钠糊,CPU就提供了L123的三級緩存,每次去主存中拿完數(shù)據(jù)后,就會存儲到CPU的三級緩存召锈,每次去三級緩存中拿數(shù)據(jù)。
如何保證:
1稻爬、volatile
如果屬性被volatile修飾皿渗,相當于會告訴CPU,對當前屬性的操作乏冀,不允許使用CPU的緩存蝶糯,必須去和主存操作
當寫一個volatile變量時,JMM會把該線程對應的CPU緩存及時刷新到主內(nèi)存找那個
當度一個volatile變量辆沦,JMM會將對應的CPU緩存中的內(nèi)存設置為無效昼捍,必須去主存中重新讀取共享變量
2识虚、synchronized
synchronized也是可以解決可見性問題的。
如果涉及到了synchronized的同步代碼塊或者同步方法妒茬,獲取鎖資源之后担锤,會將內(nèi)部涉及到的變量從CPU緩存中移除,必須去主存中重新拿數(shù)據(jù)乍钻,并且釋放鎖之后肛循,會立即將CPU緩存中的數(shù)據(jù)同步到主內(nèi)存中
3、lock
lock鎖是基于volatile實現(xiàn)的团赁,lock鎖內(nèi)部在進行加鎖和釋放鎖時育拨,會對一個由volatile修飾的state屬性進行加減操作。
4欢摄、final
final修飾的屬性熬丧,被final修飾不能進行修改,就不需要保證可見性
三怀挠、有序性
.java文件中的內(nèi)容會被編譯析蝴,在執(zhí)行前需要轉(zhuǎn)化為CPU可以識別的指令,CPU在執(zhí)行這些指令時绿淋,為了提升效率闷畸,在不影響結果的前提下,會對指令進行重排
如何保證有序性
1吞滞、as-if-serial
2佑菩、happens-before
3、volatile
2裁赠、synchronized原理
使用synchronized之后殿漠,會在編譯之后在同步的代碼塊前后加上monitorenter和monitorexit字節(jié)碼指令,依賴操作系統(tǒng)底層互斥鎖實現(xiàn)佩捞,他的作用主要就是實現(xiàn)原子性操作和解決共享變量的內(nèi)存可見性問題绞幌。
monitorenter和monitorexit會讓對象在執(zhí)行時,使得其鎖計數(shù)器加1或者減1.每個對象在同一時間只與一個monitor(鎖)相關聯(lián)一忱,而一個monitor在同一時間只能被一個線程獲得莲蜘,一個對象在嘗試獲得與這個對象相關聯(lián)的monitor鎖的所有權的時候,monitorenter指令會發(fā)生如下三種情況之一:
- monitor計數(shù)器為0帘营,意味著目前還沒有被獲得票渠,那這個線程就會立刻獲得然后把鎖計數(shù)器+1,一旦+1芬迄,別的線程再想獲取庄新,就需要等待
- 如果這個monitor已經(jīng)拿到了這個鎖的所有權,又重入了這把鎖,那鎖計數(shù)器就會累加择诈,變成2械蹋,并且隨著重入的次數(shù),會一直累加
- 這把鎖已經(jīng)被別的線程獲取了羞芍,等待鎖釋放
monitorexit:
釋放對于monitor的所有權哗戈,釋放過程很簡單,就是講monitor的計數(shù)器減1荷科,如果減完以后唯咬,計數(shù)器不是0,則代表剛才是重入進來的畏浆,當前線程還繼續(xù)持有這把鎖的所有權胆胰,如果計數(shù)器變成0,則代表當前線程不再擁有該monitor的所有權刻获,即釋放鎖蜀涨。
內(nèi)存語義上來講,加鎖的過程會清楚工作內(nèi)存中的共享變量蝎毡,再從主存讀取厚柳,而釋放鎖的過程是將工作內(nèi)存中的共享變量寫回主內(nèi)存。
3沐兵、對象頭包含哪些內(nèi)容
4别垮、CAS原理
簡單解釋:CAS操作需要輸入兩個數(shù)值,一個舊值(期望操作前的值)和一個新值扎谎,在操作期間先比較下在舊值有沒有發(fā)生變化碳想,如果沒有發(fā)生變化,才交換成新值毁靶,發(fā)生了變化則不交換胧奔。CAS操作是原子性的,但他只能保證一個共享變量的原子性操作老充,并且循環(huán)時間開銷大,而且cas有個眾所周知的問題就是ABA螟左。
cas缺點:多線程情況下啡浊,如果都用cas的話,都相對占用部分CPU資源
cas的問題:ABA胶背。通過版本號的方式解決
5巷嚣、講講aqs
什么是aqs?
AbstractQueuedSynchronized抽象類钳吟,是JUC包下的一個基礎類廷粒。
aqs核心思想是,如果被請求的共享資源空閑,則將當前請求資源的線程設置為有效的工作線程坝茎,并且將共享資源設置為鎖定狀態(tài)涤姊。如果被請求的共享資源被占用,那么就需要一套線程阻塞等待以及被喚醒時鎖分配的機制嗤放,這個機制aqs是用clh隊列鎖實現(xiàn)的思喊,即將暫時獲取不到鎖的線程加入到隊列中。
aqs的組成部分是:
提供了一個由volatile修飾次酌,并且采用CAS方式修改的int類型的state變量恨课。
其次aqs種維護了一個雙向鏈表,有head岳服,有tail剂公,并且每個節(jié)點都是node對象。
6吊宋、volatile原理
作用:
1纲辽、防止指令重排
2、實現(xiàn)可見性
當寫一個volatile變量時贫母,JMM會把該線程對應的工作內(nèi)存中的共享變量值刷新到主內(nèi)存中文兑,
當讀取一個volatile變量時,JMM會把該線程對應的工作內(nèi)存置為無效腺劣,便只能去主內(nèi)存中讀取該變量绿贞。
7、講講ThreadLocal
ThreadLocal是一個將在多線程中為每一個線程創(chuàng)建單獨的變量副本的類; 當使用ThreadLocal來維護變量時, ThreadLocal會為每個線程創(chuàng)建單獨的變量副本, 避免因多線程操作共享變量而導致的數(shù)據(jù)不一致的情況橘原。
ThreadLocal有一個靜態(tài)內(nèi)部類ThreadLocalMap籍铁,ThreadLocalMap又包含了一個entry數(shù)組,Entry本身是一個弱引用趾断,他的key是指向ThreadLocal的弱引用拒名,Entry具備了保存key, value鍵值對的能力芋酌。
弱引?的?的是為了防?內(nèi)存泄露增显,如果是強引?那么ThreadLocal對象除?線程結束否則始終?法被回收,弱引?則會在下?次GC的時候被回收脐帝。
但是這樣還是會存在內(nèi)存泄露的問題同云,假如key和ThreadLocal對象被回收之后,entry中就存在key為null堵腹,但是value有值的entry對象炸站,但是永遠沒辦法被訪問到,同樣除?線程結束運?疚顷。
只要ThreadLocal使?恰當旱易,在使?完之后調(diào)?remove?法刪除Entry對象禁偎,實際上是不會出現(xiàn)這個問題。
8阀坏、CountDownLatch了解嗎
CountDownLatch底層也是由AQS如暖,用來同步一個或多個任務的常用并發(fā)工具類。
1全释、通過構造函數(shù)初始化傳入?yún)?shù)實際為aqs的state變量賦值装处,維持計數(shù)器倒數(shù)狀態(tài)。
2浸船、當主線程調(diào)用await()方法時妄迁,當前線程會被阻塞,當state不為0時進入aqs阻塞隊列等待李命。
3登淘、其他線程調(diào)用countDown()時,state值原子性遞減封字,當state值為0的時候黔州,喚醒所有調(diào)用await方法阻塞的線程。