參考 我沒有三顆心臟
http://www.itdecent.cn/p/7382c0a843ff
http://www.itdecent.cn/p/cd9d0927be35
線程與進(jìn)程
線程是操作系統(tǒng)中分配和管理資源的基本單位
進(jìn)程是執(zhí)行運(yùn)算的最小單位,線程是進(jìn)程的一個(gè)實(shí)體
線程沒有地址空間,線程包含在進(jìn)程的地址空間中。線程上下文只包含一個(gè)堆棧、一個(gè)寄存器、一個(gè)優(yōu)先權(quán),線程文本包含在他的進(jìn)程的文本片段中,進(jìn)程擁有的所有資源都屬于線程。所有的線程共享進(jìn)程的內(nèi)存和資源。 同一進(jìn)程中的多個(gè)線程共享代碼段(代碼和常量),數(shù)據(jù)段(全局變量和靜態(tài)變量),擴(kuò)展段(堆存儲(chǔ))。但是每個(gè)線程擁有自己的棧段, 寄存器的內(nèi)容,棧段又叫運(yùn)行時(shí)段,用來存放所有局部變量和臨時(shí)變量。(線程共享代碼段、數(shù)據(jù)段和堆空間,擁有獨(dú)立的??臻g和寄存器內(nèi)容)
子進(jìn)程不對(duì)任何其他子進(jìn)程施加控制,進(jìn)程的線程可以對(duì)同一進(jìn)程的其它線程施加控制。子進(jìn)程不能對(duì)父進(jìn)程施加控制,進(jìn)程中所有線程都可以對(duì)主線程施加控制。
進(jìn)程切換時(shí),涉及到當(dāng)前進(jìn)程的 CPU 環(huán)境的保存和新被調(diào)度運(yùn)行進(jìn)程的 CPU 環(huán)境的設(shè)置。線程切換僅需要保存和設(shè)置少量的寄存器內(nèi)容,不涉及存儲(chǔ)管理方面的操作。
java多線程實(shí)現(xiàn)方式
extends Thread


implements Runnable


implement Callable


注意run() 方法和 start() 區(qū)別
start() 方法使創(chuàng)建好的線程從runnable狀態(tài)到running狀態(tài);而直接調(diào)用 run() 方法知識(shí)作為一個(gè)普通的方法調(diào)用而已,它只會(huì)在當(dāng)前線程中,串行執(zhí)行 run() 中的代碼
synchronized和ReentrantLock(Lock類)
參考:https://www.cnblogs.com/takumicx/p/9338983.html
.ReentrantLock和synchronized都是獨(dú)占鎖,只允許線程互斥的訪問臨界區(qū)。
synchronized加鎖解鎖的過程是隱式的,用戶不用手動(dòng)操作,優(yōu)點(diǎn)是操作簡(jiǎn)單,但顯得不夠靈活。ReentrantLock需要手動(dòng)加鎖和解鎖,且解鎖的操作盡量要放在finally代碼塊中,保證線程正確釋放鎖。
synchronized因?yàn)榭芍厝胍虼丝梢苑旁诒贿f歸執(zhí)行的方法上,且不用擔(dān)心線程最后能否正確釋放鎖;而ReentrantLock在重入時(shí)要卻確保重復(fù)獲取鎖的次數(shù)必須和重復(fù)釋放鎖的次數(shù)一樣,否則可能導(dǎo)致其他線程無法獲得該鎖。
在創(chuàng)建ReentrantLock的時(shí)候通過傳進(jìn)參數(shù)true創(chuàng)建公平鎖,如果傳入的是false或沒傳參數(shù)則創(chuàng)建的是非公平鎖;而synchronized是非公平鎖
當(dāng)使用synchronized實(shí)現(xiàn)鎖時(shí),阻塞在鎖上的線程除非獲得鎖否則將一直等待下去,也就是說這種無限等待獲取鎖的行為無法被中斷。而ReentrantLock給我們提供了一個(gè)可以響應(yīng)中斷的獲取鎖的方法lockInterruptibly()
使用synchronized結(jié)合Object上的wait和notify方法可以實(shí)現(xiàn)線程間的等待通知機(jī)制。ReentrantLock結(jié)合Condition接口的await()和signal()方法同樣可以實(shí)現(xiàn)這個(gè)功能。而且相比前者使用起來更清晰也更簡(jiǎn)單。
“阻塞”與"非阻塞"? ?"同步"與“異步"
同步和異步關(guān)注的是消息通信機(jī)制
同步,就是在發(fā)出一個(gè)*調(diào)用*時(shí),在沒有得到結(jié)果之前,該*調(diào)用*就不返回。但是一旦調(diào)用返回,就得到返回值了。異步則是相反,*調(diào)用*在發(fā)出之后,這個(gè)調(diào)用就直接返回了,所以沒有返回結(jié)果。換句話說,當(dāng)一個(gè)異步過程調(diào)用發(fā)出后,調(diào)用者不會(huì)立刻得到結(jié)果。而是在*調(diào)用*發(fā)出后,*被調(diào)用者*通過狀態(tài)、通知來通知調(diào)用者,或通過回調(diào)函數(shù)處理這個(gè)調(diào)用。
阻塞和非阻塞關(guān)注的是程序在等待調(diào)用結(jié)果(消息,返回值)時(shí)的狀態(tài).
阻塞調(diào)用是指調(diào)用結(jié)果返回之前,當(dāng)前線程會(huì)被掛起。調(diào)用線程只有在得到結(jié)果之后才會(huì)返回。非阻塞調(diào)用指在不能立刻得到結(jié)果之前,該調(diào)用不會(huì)阻塞當(dāng)前線程。
線程5大狀態(tài)
new/Runnable/Running/Blocked/Dead

注:線程阻塞情況有多種
(一). 等待阻塞:運(yùn)行(running)的線程執(zhí)行o.wait()方法,JVM會(huì)把該線程放入等待隊(duì)列(waitting queue)中。
(二). 同步阻塞:運(yùn)行(running)的線程在獲取對(duì)象的同步鎖時(shí),若該同步鎖被別的線程占用,則JVM會(huì)把該線程放入鎖池(lock pool)中。
(三). 其他阻塞:運(yùn)行(running)的線程執(zhí)行Thread.sleep(long ms)或t.join()方法,或者發(fā)出了I/O請(qǐng)求時(shí),JVM會(huì)把該線程置為阻塞狀態(tài)。當(dāng)sleep()狀態(tài)超時(shí)、join()等待線程終止或者超時(shí)、或者I/O處理完畢時(shí),線程重新轉(zhuǎn)入可運(yùn)行(runnable)狀態(tài)
并發(fā)(Concurrency)和并行(Parallelism)的區(qū)別
并行性是指兩個(gè)或多個(gè)事件在同一時(shí)刻發(fā)生。而并發(fā)性是指連個(gè)或多個(gè)事件在同一時(shí)間間隔內(nèi)發(fā)生。
Monitor機(jī)制

當(dāng)一個(gè)線程需要訪問受保護(hù)的數(shù)據(jù)(即需要獲取對(duì)象的Monitor)時(shí),它會(huì)首先在entry-set入口隊(duì)列中排隊(duì)(這里并不是真正的按照排隊(duì)順序),如果沒有其他線程正在持有對(duì)象的Monitor,那么它會(huì)和entry-set隊(duì)列和wait-set隊(duì)列中的被喚醒的其他線程進(jìn)行競(jìng)爭(zhēng)(即通過CPU調(diào)度),選出一個(gè)線程來獲取對(duì)象的Monitor,執(zhí)行受保護(hù)的代碼段,執(zhí)行完畢后釋放Monitor,如果已經(jīng)有線程持有對(duì)象的Monitor,那么需要等待其釋放Monitor后再進(jìn)行競(jìng)爭(zhēng)。
再說一下wait-set隊(duì)列。當(dāng)一個(gè)線程擁有Monitor后,經(jīng)過某些條件的判斷(比如用戶取錢發(fā)現(xiàn)賬戶沒錢),這個(gè)時(shí)候需要調(diào)用Object的wait方法,線程就釋放了Monitor,進(jìn)入wait-set隊(duì)列,等待Object的notify方法(比如用戶向賬戶里面存錢)。當(dāng)該對(duì)象調(diào)用了notify方法或者notifyAll方法后,wait-set中的線程就會(huì)被喚醒,然后在wait-set隊(duì)列中被喚醒的線程和entry-set隊(duì)列中的線程一起通過CPU調(diào)度來競(jìng)爭(zhēng)對(duì)象的Monitor,最終只有一個(gè)線程能獲取對(duì)象的Monitor。
通過上圖可以得知,調(diào)用obj.wait()時(shí),當(dāng)前線程必須獲取到了obj的Monitor。即wait必須放在同步方法或同步代碼塊中。
調(diào)用wait方法,就意味著釋放了Monitor;調(diào)用notify方法,并不意味著釋放了Monitor,必須要等同步代碼塊結(jié)束后才會(huì)釋放Monitor。
Volatile關(guān)鍵字
保證變量的可見性:將修改的值立即寫入主存,對(duì)值的修改是其他線程工作內(nèi)存的stop緩存失效,使得其他線程去主存讀取更新自己的緩存。
禁止指令重排:插入內(nèi)存屏障(內(nèi)存屏障????)
線程池
包括工作線程和等待隊(duì)列
如果運(yùn)行的線程少于 corePoolSize,則 Executor 始終首選添加新的線程,而不進(jìn)行排隊(duì);如果運(yùn)行的線程等于或者多于 corePoolSize,則 Executor 始終首選將請(qǐng)求加入隊(duì)列,而不是添加新線程;如果等待隊(duì)列已滿,但是當(dāng)前線程大小小于maxinumPoolSize,創(chuàng)建新的線程;如果核心線程數(shù)、等待隊(duì)列、最大線程數(shù)都滿,則使用handler處理任務(wù)。
handler策略:1.AbortPolicy 拋出異常? 2.DiscardPolicy直接丟棄? ? 3.DiscardOldestPolicy 丟棄隊(duì)列中最舊的? ? 4.CallerRunsPolicy 不用線程池中的線程,用調(diào)用者所在線程執(zhí)行。
線程池的好處:1.減少創(chuàng)建和銷毀線程的次數(shù),每個(gè)工作線程都可以被重復(fù)利用,可執(zhí)行多個(gè)任務(wù)? ? 2.提高響應(yīng)速度,不需要等待線程創(chuàng)立即可執(zhí)行? ? 3.提高線程的可管理性? ? 4.避免創(chuàng)建大量線程,導(dǎo)致消耗系統(tǒng)資源。