1.共享變量的可見(jiàn)性問(wèn)題
在讀寫(xiě)操作同步進(jìn)行時(shí)践叠,寫(xiě)操作對(duì)共享變量進(jìn)行的改變沒(méi)有應(yīng)用到讀操作言缤,這時(shí)我們稱寫(xiě)操作對(duì)讀操作不可見(jiàn)。
2.什么是原子性
對(duì)于一些系列操作禁灼,要么執(zhí)行完管挟,要么不執(zhí)行,則稱這一系列操作具有原子性
3.什么是CAS
compareAndSet,比較內(nèi)存位置的變量是否是舊的預(yù)期值弄捕,如果是則使用新的值替換僻孝,這是處理器的一個(gè)原子性操作
4.什么是AQS
AQS維護(hù)了一個(gè)state變量類存放狀態(tài)信息,對(duì)于ReenTrantLock,開(kāi)說(shuō)察藐,state表示可以可重入鎖的次數(shù)
5.什么是可重入鎖
在獲取被自己線程占用的鎖時(shí)皮璧,不被阻塞,則是可重入鎖分飞,synchronized是強(qiáng)制性的內(nèi)置鎖悴务,屬于可重入鎖;
可重入鎖的原理: 在鎖內(nèi)部維護(hù)了一個(gè)線程標(biāo)識(shí)和一個(gè)計(jì)數(shù)器譬猫,標(biāo)識(shí)表示當(dāng)前被哪個(gè)線程占用讯檐,如果是當(dāng)前線程,
則獲取到鎖并計(jì)數(shù)器+1染服,當(dāng)釋放鎖后計(jì)數(shù)器-1别洪,當(dāng)計(jì)算器為0時(shí)候,現(xiàn)成標(biāo)示重置為null柳刮,阻塞線程將被喚醒挖垛。
6.Synchronized鎖的缺點(diǎn)
同一時(shí)間只能有一個(gè)線程訪問(wèn)共享變量,無(wú)法實(shí)現(xiàn)同步讀操作
7.ReenTrantReadWriteLock的概念和原理
可以實(shí)現(xiàn)讀寫(xiě)分離秉颗,多個(gè)讀操作可以同時(shí)讀取痢毒,但最多只有一個(gè)寫(xiě)線程存在。
如果已經(jīng)有一個(gè)線程獲取了讀鎖蚕甥,這個(gè)時(shí)候要想獲取寫(xiě)鎖哪替,則需要等待讀鎖釋放;如果已經(jīng)有一個(gè)線程獲取了寫(xiě)鎖菇怀,則
所有獲取讀鎖的線程都要等待寫(xiě)鎖被釋放凭舶。
8.volatile變量
當(dāng)線程寫(xiě)入的時(shí)候會(huì)把寄存器或者其他地方,當(dāng)線程讀取時(shí)會(huì)從主內(nèi)存中獲取最新值爱沟,而非在當(dāng)前線程的私有內(nèi)存或緩存中獲取帅霜。
Java5之后,JVM實(shí)現(xiàn)了在對(duì)volatile的保證:對(duì)volatile域的寫(xiě)入操作happens-before于每一個(gè)后續(xù)的同一個(gè)域的讀寫(xiě)操作呼伸。
9.樂(lè)觀鎖和悲觀鎖义屏、獨(dú)占鎖和共享鎖、公平鎖和非公平鎖
悲觀鎖,使用只能有一個(gè)線程占用闽铐,通常依靠數(shù)據(jù)庫(kù)的鎖機(jī)制蝶怔;樂(lè)觀鎖,只會(huì)數(shù)據(jù)更新的時(shí)候檢測(cè)compareAndSet兄墅。
獨(dú)占鎖踢星,獨(dú)占資源的互斥鎖。共享鎖隙咸,允許同時(shí)有多個(gè)讀線程沐悦,但最多只有一個(gè)寫(xiě)線程,讀和寫(xiě)是互斥的五督。
公平鎖藏否,阻塞的線程在獲取鎖時(shí),采用FIFO先進(jìn)先出的策略充包。非公平鎖副签,在鎖釋放后,多個(gè)線程基矮,根據(jù)線程調(diào)度策略去獲取鎖淆储;
ReenTrantLock是獨(dú)占鎖,也是悲觀鎖家浇。ReadWriteLock是共享鎖本砰,也是悲觀鎖。ReenTrantLcok和ReadWriteLock都提供了公平鎖和非公平鎖的實(shí)現(xiàn)
new ReenTrantLock(true/false) true為公平鎖钢悲,false為非公平鎖点额,不傳參數(shù)默認(rèn)為非公平鎖;
公平鎖比非公平鎖要更消耗資源
10.ConcureentHashMap原理 參考http://www.importnew.com/21781.html
ConcureentHashMap使用分離鎖莺琳,分段segment咖楣,每個(gè)segments繼承了ReenTrantLock,使用了ReenTrantLock的獨(dú)占鎖來(lái)控制同一段只能有一個(gè)線程進(jìn)行寫(xiě)。
而value采用volatile語(yǔ)義芦昔,讀操作直接從主內(nèi)存中獲取,不需要加鎖娃肿。
get方法: 先根據(jù)Hash算法咕缎,算出key的Hash值,根據(jù)Hash值來(lái)確定value存放在哪個(gè)segment中料扰;在當(dāng)前segment中找到對(duì)應(yīng)的entry凭豪,在獲取到后判斷是否是完整
對(duì)象,如果不完整有可能是在獲取的過(guò)程中插入了put了一個(gè)剛好需要get的entry晒杈,但是還沒(méi)有構(gòu)建完成嫂伞,就再用鎖的方式獲取一次,等待寫(xiě)鎖釋放后再讀取。segment
中計(jì)數(shù)entry的count值和entry中的value值都是volatile域的帖努,所以在獲取的時(shí)候都是最新值撰豺。
public V get(Object key) {
int hash = hash(key); // throws NullPointerException if key null
return segmentFor(hash).get(key, hash);
}
V get(Object key, int hash) {
if (count != 0) { // read-volatile // ①
HashEntry<K,V> e = getFirst(hash);
while (e != null) {
if (e.hash == hash && key.equals(e.key)) {
V v = e.value;
if (v != null) // ② 注意這里
return v;
return readValueUnderLock(e); // recheck
}
e = e.next;
}
}
return null;
}
static final class HashEntry<K,V> {
final K key;
final int hash;
volatile V value;
final HashEntry<K,V> next;
。拼余。污桦。
}
put方法和remove方法:采用ReenTranLock獨(dú)占鎖進(jìn)行寫(xiě)操作