Java 多線程2

[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ù)

?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容