串行: 串行就是線程完成整個(gè)流程是按照順序執(zhí)行,如果是多個(gè)任務(wù),必須一個(gè)一個(gè)來(lái),要等前一個(gè)執(zhí)行完才執(zhí)行后面的
并行: 并行就是可以同時(shí)獲取多個(gè)任務(wù),并且可以同時(shí)執(zhí)行多個(gè)任務(wù)
并發(fā):是一個(gè)CPU或者是CPU的一個(gè)同時(shí)執(zhí)行多個(gè)任務(wù).
并行和并發(fā)的區(qū)別:
并行是多個(gè)CPU或者一個(gè)多核CPU,執(zhí)行任務(wù),就是并行.,并發(fā),需要分CPU的時(shí)間片,任務(wù)占用CPU,任務(wù)隨機(jī)輪流執(zhí)行
線程的六種狀態(tài):
NEW 新建狀態(tài),線程對(duì)象剛創(chuàng)建
RUNNABLE 就緒狀態(tài),等待 CPU 時(shí)間片
# 兩個(gè)線程,一個(gè)進(jìn)入sleep狀態(tài)占有同步鎖,另外一個(gè)線程就進(jìn)入阻塞狀態(tài)
BLOCKED 阻塞狀態(tài),wait方法,等待同步鎖
WAITING 等待狀態(tài),等待被喚醒notify或者notifyAll
TIMED_WAITING 限時(shí)等待狀態(tài),進(jìn)入等待狀態(tài)設(shè)定了等待時(shí)間,時(shí)間到了線程回到就緒狀態(tài)
TERMINATED 終止?fàn)顟B(tài),代碼運(yùn)行完,線程結(jié)束
wait和sleep方法的區(qū)別:
wait是線程進(jìn)入WAITING等待狀態(tài),會(huì)釋放鎖,需要另外的線程通過(guò)notify或者notifyAll方法喚醒,sleep是線程進(jìn)入TIMED_WAITING狀態(tài),不會(huì)釋放鎖,等時(shí)間到休眠結(jié)束,自己再運(yùn)行完才釋放鎖,其次前者是Object類(lèi)的非靜態(tài)方法,后者是Thread類(lèi)的靜態(tài)方法
鎖的使用各種情況:
如果兩個(gè)線程開(kāi)啟用同一個(gè)對(duì)象了,此時(shí)加鎖并沒(méi)有使用同一把鎖,則所不生效,例如是兩個(gè)對(duì)象,或者一個(gè)是靜態(tài)同步方法,一個(gè)是非靜態(tài)同步方法,或者是代碼塊指定的鎖對(duì)象不一樣,使用各自的鎖(不是同一個(gè)鎖對(duì)象),則各自線程各運(yùn)行各的,沒(méi)有鎖住.
同步代碼塊和同步方法的區(qū)別:
同步代碼塊的作用域和鎖都是可以自定義設(shè)定的,同步方法的作用域就是這個(gè)方法,靜態(tài)的同步方法的鎖是(類(lèi)命.class)對(duì)象,非靜態(tài)的同步方法就是this對(duì)象.
synchronized鎖改良后的幾種鎖的狀態(tài):
鎖膨脹的過(guò)程:無(wú)鎖==>>偏向鎖==>>輕量鎖==>>重量鎖
鎖清除:去除不可能存在競(jìng)爭(zhēng)的鎖,鎖對(duì)象是局部變量
鎖粗化:自動(dòng)擴(kuò)大鎖的范圍,避免反復(fù)的申請(qǐng)加鎖和釋放鎖
自旋鎖:當(dāng)一個(gè)線程碰到一個(gè)被鎖住的方法,不會(huì)去阻塞隊(duì)列等待,而是在被鎖的方法外繼續(xù)執(zhí)行一些無(wú)意義代碼,等這個(gè)鎖釋放.適合場(chǎng)景,鎖占用的時(shí)間段,這個(gè)時(shí)候就在鎖外面等,自旋有很大幾率就馬上獲得到鎖,不適用場(chǎng)景,鎖占用的時(shí)間長(zhǎng),因?yàn)樽孕臅r(shí)間過(guò)長(zhǎng)就會(huì)過(guò)于消耗CPU性能
自適應(yīng)自旋鎖:是自旋鎖的升級(jí),這個(gè)線程自旋的次數(shù)不在是固定的,而是由上一次自旋的時(shí)間來(lái)決定了
對(duì)象包括對(duì)象頭,對(duì)象體,對(duì)其字節(jié)
對(duì)象頭:包括Mark Word和Klass Pointer兩個(gè)區(qū)域
klass pointer:指向元數(shù)據(jù)區(qū)的類(lèi),每個(gè)變量都屬于它自己的類(lèi)
mark word有對(duì)應(yīng)著五種狀態(tài):
01狀態(tài)==>>指向0的時(shí)候是無(wú)鎖狀態(tài)
01狀態(tài)==>>指向1的時(shí)候是偏向鎖狀態(tài),此時(shí)會(huì)有一個(gè)偏向線程ID,標(biāo)記那個(gè)偏向的線程
00狀態(tài)==>>輕量鎖狀態(tài),
10狀態(tài)==>>重量鎖狀態(tài)
11==>>垃圾回收GC狀態(tài)
監(jiān)視器(ObjectMonitor)
- 三個(gè)關(guān)鍵變量
_EntryList : 處于等待鎖 block 狀態(tài)的線程,會(huì)被加入到該列表(阻塞隊(duì)列)
_count : 鎖計(jì)數(shù)器
_owner : 指向當(dāng)前線程
- monitorenter和monitorexit指令(monitorexit有兩個(gè))
把class文件進(jìn)行反編譯javap,可以查看到monitorenter和monitorexit兩個(gè)指令
當(dāng)加鎖或者阻塞時(shí),運(yùn)行monitorenter指令,當(dāng)鎖釋放或者拋出異常的時(shí)候運(yùn)行monitorext指令,
可重入性
可重入性就是指一個(gè)線程可以直接獲得它自己加的鎖,如果不可重入性則就會(huì)導(dǎo)致死鎖,而且鎖不住數(shù)據(jù)
JMM(Java memory model)
需要掌握的概念: 主內(nèi)存,工作內(nèi)存
原子性 : 如果沒(méi)有保持原子性,主內(nèi)存的共享變量,各個(gè)線程先從主內(nèi)存讀取到工作內(nèi)存,在自己的工作內(nèi)存區(qū)域內(nèi)運(yùn)行,但是會(huì)導(dǎo)致重復(fù)覆蓋主內(nèi)存的共享變量,就會(huì)出錯(cuò)
可見(jiàn)性 : 如果沒(méi)有可見(jiàn)性,每個(gè)線程只始終都是在從自己的本地內(nèi)存獲取數(shù)據(jù),沒(méi)有去讀取主內(nèi)存,就出錯(cuò)了.
有序性 : 用戶(hù)代碼class文件的指令最終到 CPU 上執(zhí)行的時(shí)候都會(huì)轉(zhuǎn)變?yōu)?CPU 能夠識(shí)別的指令,而 CPU 在執(zhí)行時(shí)為了提升性能,會(huì)對(duì)這些指令進(jìn)行重排序,但是這些排序是有規(guī)范的,無(wú)需我們考慮
volatile關(guān)鍵字
volatile 寫(xiě)的內(nèi)存語(yǔ)義:當(dāng)寫(xiě)一個(gè) volatile 變量時(shí),JMM 會(huì)把該線程對(duì)應(yīng)的本地內(nèi)存中的變量值 flush 到主內(nèi)存。
volatile 讀的內(nèi)存語(yǔ)義:當(dāng)讀一個(gè) volatile 變量時(shí),JMM 會(huì)把該線程對(duì)應(yīng)的本地內(nèi)存置為無(wú)效。線程接下來(lái)將從主內(nèi)存中讀取共享變量。
CAS鎖機(jī)制
compare and swap
舊值比較,如果比較成功,就修改為新值,如果舊值不對(duì)失敗,則讀取正確的舊值,再用讀取的舊值去比較,這次就成功了,就可以修改為新值.
如果舊值一直再被其他線程修改,那么在等待讀取正確舊值的線程就循環(huán)反復(fù)讀取正確的舊值,直到讀取到正確的,這也就是自旋的過(guò)程.
相比較于樂(lè)觀鎖:
樂(lè)觀鎖時(shí)相比CAS鎖機(jī)制多了版本號(hào),更新一次后會(huì)更新版本號(hào).
CAS鎖機(jī)制因?yàn)闆](méi)有版本號(hào)可能會(huì)有ABA問(wèn)題,但是不影響使用.
AQS: AbstractQueuedSynchronizer 抽象的隊(duì)列式同步器,它維護(hù)了一個(gè) volatile int state(代表共享資源),這里 volatile 是核心關(guān)鍵詞。state 的訪問(wèn)方式有三種:
- getState()
- setState()
- compareAndSetState()
底層是實(shí)現(xiàn)了共享資源的state狀態(tài)的獲取與釋放
AQS機(jī)制=CAS機(jī)制+volatile關(guān)鍵字