[TOC]
死鎖
死鎖:指兩個或者兩個以上的線程在執(zhí)行的過程中,因爭奪資源產(chǎn)生的一種互相等待現(xiàn)象。
線程池
池: 緩沖區(qū) 數(shù)組 集合等容器
開裝修公司找工人
A 客戶來要人 3
排除3個人去A客戶處理 公司還有2個人
招了5個人,公司有7個人
B 客戶來要人 1個人 公司還剩6個人
A 客戶對應的工人回來了 公司9個人,裁一個人,還剩8個人
C 客戶來要人 要7個人 公司還剩1個人,招人 6個人
D 客戶來要人 要4個人 還剩1個人, 招人 6個人
C 客戶的人回來了, 公司有12個人
當公司業(yè)務做大,公司到了規(guī)模30個人,到了最大容量
和客戶說,您先預約好,等我的工人回來立馬給您安排
客戶等待
當程序中要創(chuàng)建大量生存期很短的線程時,應該考慮使用線程池,程序啟動一個新線程占用資源大,
使用線程池可以很好的提高性能,線程池里的每一個線程代碼結束后,并不會死亡,
而是再次回到線程池中成為空閑狀態(tài),等待下一個對象來使用。
Executors 工廠類來產(chǎn)生線程池。
構造方法
public static ExecutorService newCachedThreadPool()
public static ExecutorService newFixedThreadPool(int nThreads)
public static ExecutorService newSingleThreadExecutor()
線程通信
線程和線程之間實現(xiàn)數(shù)據(jù)交互
1.通過構造方法 A -> B A在啟動之前傳遞給B
2.通過實現(xiàn)Callable接口的方式 A -> B B在執(zhí)行結束之后將數(shù)據(jù)回傳給A
3.利用接口回調(diào)方式傳遞數(shù)據(jù)
4.利用同步鎖串行實現(xiàn)數(shù)據(jù)傳遞
5.利用等待喚醒機制
接口回調(diào)
1.創(chuàng)建一個回調(diào)接口[電話號碼],接口中書寫方法 A->B
方法的形參就是 B線程使用形參傳遞給A線程
方法的返回值就是 A線程使用返回值傳遞給B線程
2.A線程將這個回調(diào)接口通過構造方法傳遞給B線程
3.B線程在使用這個接口,即接口回調(diào)
等待喚醒機制
生產(chǎn)者消費者模型
生產(chǎn)者
先判斷是否有玩具
有,就等待消費者消費 wait
沒有,就生產(chǎn)
生產(chǎn)完畢之后通知消費者消費 nofity
消費者
先判斷是否有玩具
有,就消費
消費完畢之后,就通知生產(chǎn)者生產(chǎn)
沒有,就等待生產(chǎn)者生產(chǎn)
該模型是否存在線程安全問題 --> 存在
等待喚醒機制依賴的幾個方法
wait: 讓當前線程處理等待(阻塞)狀態(tài),會將當前線程放入到等待池中,并且會釋放鎖對象
void wait(long timeout)
void wait(long timeout, int nanos)
notify: 喚醒在同一把鎖上的處于等待的單個線程
nofityAll: 喚醒在同一把鎖上處于等待的所有線程
volatile關鍵字
volatile關鍵字的作用是:使變量在多個線程間可見(可見性)
volatile關鍵字的非原子性
所謂原子性,就是某系列的操作步驟要么全部執(zhí)行,要么都不執(zhí)行。
比如,變量的自增操作 i++,分三個步驟:
i = 10;
1.從內(nèi)存中讀取出變量 i 的值
2.將 i 的值加1
3.將 加1 后的值寫回內(nèi)存 *
A線程執(zhí)行到第二步, i變成11, B線程搶到了執(zhí)行權,B讀取內(nèi)存中的數(shù)據(jù)還是10,執(zhí)行第二步i=11
最后結果是11,預期結果是12,線程不安全
這說明 i++ 并不是一個原子操作。因為,它分成了三步,
有可能當某個線程執(zhí)行到了第2步時被中斷了,那么就意味著只執(zhí)行了其中的兩個步驟,沒有全部執(zhí)行。
volatile修飾的變量并不保證對它的操作(自增)具有原子性。
AtomicInteger
1、保證變量在線程間可見,對volatile變量所有的寫操作都能立即反應到其他線程中,
換句話說,volatile變量在各個線程中是一致的
2、禁止指令的重排序優(yōu)化; 指令重排序 , 這里間接可以保證線程安全
線程安全
如何保證線程安全? volatile + synchronized
synchronized和volatile的區(qū)別
1.volatile輕量級,只能修飾變量。synchronized重量級,還可修飾方法
2.volatile只能保證數(shù)據(jù)的可見性,不能用來同步,因為多個線程并發(fā)訪問volatile修飾的變量不會阻塞。
3.synchronized不僅保證可見性,而且還保證原子性,因為,只有獲得了鎖的線程才能進入臨界區(qū)
從而保證臨界區(qū)中的所有語句都全部執(zhí)行。多個線程爭搶synchronized鎖對象時,會出現(xiàn)阻塞。
本地線程
ThreadLocal
針對每一個線程都提供對應的副本數(shù)據(jù)
這樣操作每次只操作自己副本數(shù)據(jù),保證了線程的安全,同時也提高了效率
但是操作的不是同一份數(shù)據(jù)