多線程并發(fā)編程學(xué)習(xí)(jvm優(yōu)化惯雳、Linux優(yōu)化)壹

壹朝巫、B站狂神juc

1、什么是JUC

java.util.concurrent 包是在并發(fā)編程中使用的工具類(lèi)石景,有以下三個(gè)包:

2.進(jìn)程和線程回顧

進(jìn)程 / 線程是什么劈猿?

進(jìn)程:進(jìn)程是一個(gè)具有一定獨(dú)立功能的程序關(guān)于某個(gè)數(shù)據(jù)集合的一次運(yùn)行活動(dòng)。它是操作系統(tǒng)動(dòng)態(tài)執(zhí)行的基本單元潮孽,在傳統(tǒng)的操作系統(tǒng)中揪荣,進(jìn)程既是基本的分配單元,也是基本的執(zhí)行單元恩商。

線程:通常在一個(gè)進(jìn)程中可以包含若干個(gè)線程变逃,當(dāng)然一個(gè)進(jìn)程中至少有一個(gè)線程,不然沒(méi)有存在的意義怠堪,線程可以利用進(jìn)程所有擁有的資源揽乱。在引入線程的操作系統(tǒng)中,通常都是把進(jìn)程作為分配資源的基本單位粟矿,而把線程作為獨(dú)立運(yùn)行和獨(dú)立調(diào)度的基本單位凰棉,由于線程比進(jìn)程小,基本上不擁有系統(tǒng)資源陌粹,故對(duì)它的調(diào)度所付出的開(kāi)銷(xiāo)就會(huì)小得多撒犀,能更高效的提高系統(tǒng)多個(gè)程序間并發(fā)執(zhí)行的程度。

白話:

進(jìn)程:就是操作系統(tǒng)中運(yùn)行的一個(gè)程序,QQ.exe, music.exe或舞, word.exe 荆姆,這就是多個(gè)進(jìn)程

線程:每個(gè)進(jìn)程中都存在一個(gè)或者多個(gè)線程,比如用word寫(xiě)文章時(shí)映凳,就會(huì)有一個(gè)線程默默幫你定時(shí)自動(dòng)保存胆筒。

并發(fā) / 并行是什么?

做并發(fā)編程之前诈豌,必須首先理解什么是并發(fā)仆救,什么是并行。

線程的狀態(tài):Java的線程有6種狀態(tài):可以分析源碼:

wait / sleep 的區(qū)別????

3矫渔、Lock鎖

傳統(tǒng)的 synchronized

使用 juc.locks 包下的類(lèi)操作 Lock 鎖 + Lambda 表達(dá)式

synchronized 和 lock 區(qū)別

4彤蔽、生產(chǎn)者和消費(fèi)者

線程間的通信 , 線程之間要協(xié)調(diào)和調(diào)度

生產(chǎn)者和消費(fèi)者 synchroinzed 版 :

問(wèn)題升級(jí):防止虛假喚醒,4個(gè)線程庙洼,兩個(gè)加顿痪,兩個(gè)減

新版生產(chǎn)者和消費(fèi)者寫(xiě)法

閑聊常見(jiàn)筆試題:手寫(xiě)單例模式油够、手寫(xiě)冒泡排序员魏、手寫(xiě)生產(chǎn)者消費(fèi)者

精確通知順序訪問(wèn)

5、8鎖的現(xiàn)象

1叠聋、標(biāo)準(zhǔn)訪問(wèn),請(qǐng)問(wèn)先打印郵件還是短信受裹?

2碌补、郵件方法暫停4秒鐘,請(qǐng)問(wèn)先打印郵件還是短信棉饶?

3厦章、新增一個(gè)普通方法hello()沒(méi)有同步,請(qǐng)問(wèn)先打印郵件還是hello?

4照藻、兩部手機(jī)袜啃、請(qǐng)問(wèn)先打印郵件還是短信?

5幸缕、兩個(gè)靜態(tài)同步方法群发,同一部手機(jī),請(qǐng)問(wèn)先打印郵件還是短信发乔?

6熟妓、兩個(gè)靜態(tài)同步方法,2部手機(jī)栏尚,請(qǐng)問(wèn)先打印郵件還是短信起愈?

7、一個(gè)普通同步方法,一個(gè)靜態(tài)同步方法抬虽,同一部手機(jī)官觅,請(qǐng)問(wèn)先打印郵件還是短信?

8阐污、一個(gè)普通同步方法休涤,一個(gè)靜態(tài)同步方法,2部手機(jī)疤剑,請(qǐng)問(wèn)先打印郵件還是短信滑绒?

小結(jié)

6、集合類(lèi)不安全

list 不安全

單線程

多線程

set 不安全

map 不安全

7隘膘、Callable

多線程中疑故,第3種獲得多線程的方式邪铲,Callable第练。它與Runnable有什么區(qū)別呢冰肴?

怎么調(diào)用callable

8胰蝠、常用輔助類(lèi)

8.1见咒、CountDownLatch

8.2誊薄、CyclicBarrier

作用:和上面的減法相反冠蒋,這里是加法殉疼,好比集齊7個(gè)龍珠召喚神龍才漆,或者人到齊了再開(kāi)會(huì)牛曹!

8.3、Semaphore

翻譯:Semaphore 信號(hào)量;信號(hào)燈;信號(hào)作用:搶車(chē)位

9醇滥、讀寫(xiě)鎖

獨(dú)占鎖(寫(xiě)鎖):指該鎖一次只能被一個(gè)線程鎖持有黎比。對(duì)于ReentranrLock和 Synchronized 而言都是獨(dú)占鎖。

共享鎖(讀鎖):該鎖可被多個(gè)線程所持有鸳玩。

對(duì)于ReentrantReadWriteLock其讀鎖時(shí)共享鎖阅虫,寫(xiě)鎖是獨(dú)占鎖,讀鎖的共享鎖可保證并發(fā)讀是非常高效的不跟。

10.阻塞隊(duì)列

阻塞隊(duì)列

接口結(jié)構(gòu)圖

SynchronousQueue 同步隊(duì)列

11颓帝、線程池

池化技術(shù)

為什么使用線程池

10 年前單核CPU電腦,假的多線程窝革,像馬戲團(tuán)小丑玩多個(gè)球 购城,CPU 需要來(lái)回切換。現(xiàn)在是多核電腦聊闯,多個(gè)線程各自跑在獨(dú)立的CPU上工猜,不用切換效率高

ThreadPoolExecutor 七大參數(shù)

線程池用哪個(gè)?生產(chǎn)中如何設(shè)置合理參數(shù)?????

12菱蔬、四大函數(shù)式接口

java.util.function , Java 內(nèi)置核心四大函數(shù)式接口篷帅,可以使用lambda表達(dá)式

13史侣、Stream流式計(jì)算

流(Stream)到底是什么呢?

14魏身、分支合并

什么是ForkJoin

核心類(lèi)

15惊橱、異步回調(diào)

16、JMM

17箭昵、volatile

volatile是不錯(cuò)的機(jī)制税朴,但是也不能保證原子性

18、深入單例模式

? ??1家制、餓漢式

? ? 2.懶漢式

????3.靜態(tài)內(nèi)部類(lèi)

????4正林、萬(wàn)惡的反射

5.枚舉

19、深入理解CAS

CAS : 比較并交換

CAS 底層原理颤殴?如果知道觅廓,談?wù)勀銓?duì)UnSafe的理解?

問(wèn)題:這個(gè)UnSafe類(lèi)到底是什么涵但? 可以看到AtomicInteger源碼中也是它杈绸!

20、原子引用

原子類(lèi) AtomicInteger 的ABA問(wèn)題談?wù)劙粒吭痈乱弥绬幔????

原子引用 AtomicReference

要解決ABA問(wèn)題瞳脓,我們就需要加一個(gè)版本號(hào)

版本號(hào)原子引用,類(lèi)似樂(lè)觀鎖

演示ABA問(wèn)題:

解決方案:

21澈侠、Java鎖

貳劫侧、拉鉤多線程

并發(fā)編程簡(jiǎn)介

????java是一個(gè)支持多線程的開(kāi)發(fā)語(yǔ)言。多線程可以在包含多個(gè)CPU核心的機(jī)器上同時(shí)處理多個(gè)不同的任務(wù)哨啃,優(yōu)化資源的使用率板辽,提升程序的效率。在一些對(duì)性能要求比較高場(chǎng)合棘催,多線程是java程序調(diào)優(yōu)的重要方面。比較重要的內(nèi)容除了算法耳标,就是并發(fā)編程醇坝。并發(fā)編程是最能體現(xiàn)一個(gè)程序員功底的方面之一。

????Java并發(fā)編程主要涉及以下幾個(gè)部分:

1. 并發(fā)編程三要素

原子性:即一個(gè)不可再被分割的顆粒次坡。在Java中原子性指的是一個(gè)或多個(gè)操作要么全部執(zhí)行成功要么全部執(zhí)行失敗呼猪。

有序性:程序執(zhí)行的順序按照代碼的先后順序執(zhí)行。(處理器可能會(huì)對(duì)指令進(jìn)行重排序)

可見(jiàn)性:當(dāng)多個(gè)線程訪問(wèn)同一個(gè)變量時(shí)砸琅,如果其中一個(gè)線程對(duì)其作了修改宋距,其他線程能立即獲取到最新的值。

2. 線程的五大狀態(tài)

創(chuàng)建狀態(tài):當(dāng)用 new 操作符創(chuàng)建一個(gè)線程的時(shí)候

就緒狀態(tài):調(diào)用 start 方法症脂,處于就緒狀態(tài)的線程并不一定馬上就會(huì)執(zhí)行 run 方法谚赎,還需要等待CPU的調(diào)度

運(yùn)行狀態(tài):CPU 開(kāi)始調(diào)度線程淫僻,并開(kāi)始執(zhí)行 run 方法

阻塞狀態(tài):線程的執(zhí)行過(guò)程中由于一些原因進(jìn)入阻塞狀態(tài)比如:調(diào)用 sleep 方法、嘗試去得到一個(gè)鎖等等

死亡狀態(tài):run 方法執(zhí)行完 或者 執(zhí)行過(guò)程中遇到了一個(gè)異常

3. 悲觀鎖與樂(lè)觀鎖

悲觀鎖:每次操作都會(huì)加鎖壶唤,會(huì)造成線程阻塞雳灵。

樂(lè)觀鎖:每次操作不加鎖而是假設(shè)沒(méi)有沖突而去完成某項(xiàng)操作,如果因?yàn)闆_突失敗就重試闸盔,直到成功為止悯辙,不會(huì)造成線程阻塞。

4. 線程之間的協(xié)作

線程間的協(xié)作有:wait/notify/notifyAll等

5. synchronized 關(guān)鍵字

synchronized是Java中的關(guān)鍵字迎吵,是一種同步鎖躲撰。它修飾的對(duì)象有以下幾種:

①修飾一個(gè)代碼塊:被修飾的代碼塊稱為同步語(yǔ)句塊,其作用的范圍是大括號(hào){}括起來(lái)的代碼击费,作用的對(duì)象是調(diào)用這個(gè)代碼塊的對(duì)象

②修飾一個(gè)方法:被修飾的方法稱為同步方法拢蛋,其作用的范圍是整個(gè)方法,作用的對(duì)象是調(diào)用這個(gè)方法的對(duì)象

③修飾一個(gè)靜態(tài)的方法:其作用的范圍是整個(gè)靜態(tài)方法荡灾,作用的對(duì)象是這個(gè)類(lèi)的所有對(duì)象

④修飾一個(gè)類(lèi):其作用的范圍是synchronized后面括號(hào)括起來(lái)的部分瓤狐,作用主的對(duì)象是這個(gè)類(lèi)的所有對(duì)象。

6. CAS

CAS全稱是Compare And Swap批幌,即比較替換础锐,是實(shí)現(xiàn)并發(fā)應(yīng)用到的一種技術(shù)。操作包含三個(gè)操作數(shù)—內(nèi)存位置(V)荧缘、預(yù)期原值(A)和新值(B)皆警。 如果內(nèi)存位置的值與預(yù)期原值相匹配,那么處理器會(huì)自動(dòng)將該位置值更新為新值 截粗。否則信姓,處理器不做任何操作。CAS存在三大問(wèn)題:ABA問(wèn)題绸罗,循環(huán)時(shí)間長(zhǎng)開(kāi)銷(xiāo)大意推,以及只能保證一個(gè)共享變量的原子操作。

7. 線程池

如果我們使用線程的時(shí)候就去創(chuàng)建一個(gè)線程珊蟀,雖然簡(jiǎn)單菊值,但是存在很大的問(wèn)題。如果并發(fā)的線程數(shù)量很多育灸,并且每個(gè)線程都是執(zhí)行一個(gè)時(shí)間很短的任務(wù)就結(jié)束了腻窒,這樣頻繁創(chuàng)建線程就會(huì)大大降低系統(tǒng)的效率,因?yàn)轭l繁創(chuàng)建線程和銷(xiāo)毀線程需要時(shí)間磅崭。線程池通過(guò)復(fù)用可以大大減少線程頻繁創(chuàng)建與銷(xiāo)毀帶來(lái)的性能上的損耗儿子。

常見(jiàn)的多線程問(wèn)題有:

1. 重排序有哪些分類(lèi)?如何避免砸喻?

2. Java 中新的Lock接口相對(duì)于同步代碼塊(synchronized block)有什么優(yōu)勢(shì)柔逼?如果讓你實(shí)現(xiàn)一

個(gè)高性能緩存蒋譬,支持并發(fā)讀取和單一寫(xiě)入,你如何保證數(shù)據(jù)完整性卒落。

3. 如何在Java中實(shí)現(xiàn)一個(gè)阻塞隊(duì)列羡铲。

4. 寫(xiě)一段死鎖代碼。說(shuō)說(shuō)你在Java中如何解決死鎖儡毕。

5. volatile變量和atomic變量有什么不同也切?

6. 為什么要用線程池?

7. 實(shí)現(xiàn)Runnable接口和Callable接口的區(qū)別

8. 執(zhí)行execute()方法和submit()方法的區(qū)別是什么呢腰湾?

9. AQS的實(shí)現(xiàn)原理是什么雷恃?

10. java API中哪些類(lèi)中使用了AQS?

11. ...

并發(fā)編程課程很多內(nèi)容會(huì)從JDK源碼解析相關(guān)原理费坊。

主要內(nèi)容包括:

1. 多線程&并發(fā)設(shè)計(jì)原理

并發(fā)核心概念

并發(fā)的問(wèn)題

JMM內(nèi)存模型

2. JUC

并發(fā)容器

同步工具類(lèi)

Atomic類(lèi)

Lock與Condition

3. 線程池與Future

線程池的實(shí)現(xiàn)原理

線程池的類(lèi)繼承體系

ThreadPoolExecutor

Executors工具類(lèi)

ScheduledThreadPool Executor

CompletableFuture用法4. ForkJoinPool

ForkJoinPool用法

核心數(shù)據(jù)結(jié)構(gòu)

工作竊取隊(duì)列

ForkJoinPool狀態(tài)控制

Worker線程的阻塞-喚醒機(jī)制

任務(wù)的提交過(guò)程分析

工作竊取算法:任務(wù)的執(zhí)行過(guò)程分析

ForkJoinTask的fork/join

ForkJoinPool的優(yōu)雅關(guān)閉

5. 多線程設(shè)計(jì)模式

Single Threaded Execution模式

Immutable模式

Guarded Suspension模式

Balking模式

Producer-Consumer模式

Read-Write Lock模式

Thread-Per-Message模式

Worker Thread模式

Future模式

一倒槐、多線程&并發(fā)設(shè)計(jì)原理

1 多線程回顧

1.1 Thread和Runnable

1.1.1 Java中的線程

創(chuàng)建執(zhí)行線程有兩種方法:1.擴(kuò)展Thread 類(lèi)。2.實(shí)現(xiàn)Runnable 接口附井。

1.1.2 Java中的線程:特征和狀態(tài)

1. 所有的Java 程序讨越,不論并發(fā)與否,都有一個(gè)名為主線程的Thread 對(duì)象永毅。執(zhí)行該程序時(shí)把跨, Java虛擬機(jī)( JVM )將創(chuàng)建一個(gè)新Thread 并在該線程中執(zhí)行main()方法。這是非并發(fā)應(yīng)用程序中唯一的線程沼死,也是并發(fā)應(yīng)用程序中的第一個(gè)線程着逐。

2. Java中的線程共享應(yīng)用程序中的所有資源,包括內(nèi)存和打開(kāi)的文件意蛀,快速而簡(jiǎn)單地共享信息耸别。但是必須使用同步避免數(shù)據(jù)競(jìng)爭(zhēng)。

3. Java中的所有線程都有一個(gè)優(yōu)先級(jí)县钥,這個(gè)整數(shù)值介于Thread.MIN_PRIORITY(1)和Thread.MAX_PRIORITY(10)之間秀姐,默認(rèn)優(yōu)先級(jí)是Thread.NORM_PRIORITY(5)。線程的執(zhí)行順序并沒(méi)有保證若贮,通常囊扳,較高優(yōu)先級(jí)的線程將在較低優(yōu)先級(jí)的錢(qián)程之前執(zhí)行。

4. 在Java 中兜看,可以創(chuàng)建兩種線程:

守護(hù)線程。

非守護(hù)線程狭瞎。

區(qū)別在于它們?nèi)绾斡绊懗绦虻慕Y(jié)束细移。

Java程序結(jié)束執(zhí)行過(guò)程的情形:

程序執(zhí)行Runtime類(lèi)的exit()方法, 而且用戶有權(quán)執(zhí)行該方法熊锭。

應(yīng)用程序的所有非守護(hù)線程均已結(jié)束執(zhí)行弧轧,無(wú)論是否有正在運(yùn)行的守護(hù)線程雪侥。

守護(hù)線程通常用在作為垃圾收集器或緩存管理器的應(yīng)用程序中,執(zhí)行輔助任務(wù)精绎。在線程start之前調(diào)用isDaemon()方法檢查線程是否為守護(hù)線程速缨,也可以使用setDaemon()方法將某個(gè)線程確立為守護(hù)線程宋光。

5. Thread.States類(lèi)中定義線程的狀態(tài)如下:

NEW:Thread對(duì)象已經(jīng)創(chuàng)建荤傲,但是還沒(méi)有開(kāi)始執(zhí)行。

RUNNABLE:Thread對(duì)象正在Java虛擬機(jī)中運(yùn)行呢燥。

BLOCKED : Thread對(duì)象正在等待鎖定搁吓。

WAITING:Thread 對(duì)象正在等待另一個(gè)線程的動(dòng)作原茅。

TIME_WAITING:Thread對(duì)象正在等待另一個(gè)線程的操作,但是有時(shí)間限制堕仔。

TERMINATED:Thread對(duì)象已經(jīng)完成了執(zhí)行擂橘。

getState()方法獲取Thread對(duì)象的狀態(tài),可以直接更改線程的狀態(tài)摩骨。

在給定時(shí)間內(nèi)通贞, 線程只能處于一個(gè)狀態(tài)。這些狀態(tài)是JVM使用的狀態(tài)恼五,不能映射到操作系統(tǒng)的線程狀態(tài)昌罩。

線程狀態(tài)的源碼:

1.1.3 Thread類(lèi)和Runnable 接口

Runnable接口只定義了一種方法:run()方法。這是每個(gè)線程的主方法唤冈。當(dāng)執(zhí)行start()方法啟動(dòng)新線程時(shí)峡迷,它將調(diào)用run()方法。

Thread類(lèi)其他常用方法:

獲取和設(shè)置Thread對(duì)象信息的方法:

①getId():該方法返回Thread對(duì)象的標(biāo)識(shí)符你虹。該標(biāo)識(shí)符是在錢(qián)程創(chuàng)建時(shí)分配的一個(gè)正整數(shù)绘搞。在線程的整個(gè)生命周期中是唯一且無(wú)法改變的。

②getName()/setName():這兩種方法允許你獲取或設(shè)置Thread對(duì)象的名稱傅物。這個(gè)名稱是一個(gè)String對(duì)象夯辖,也可以在Thread類(lèi)的構(gòu)造函數(shù)中建立。

③getPriority()/setPriority():你可以使用這兩種方法來(lái)獲取或設(shè)置Thread對(duì)象的優(yōu)先級(jí)董饰。

④isDaemon()/setDaemon():這兩種方法允許你獲取或建立Thread對(duì)象的守護(hù)條件蒿褂。

⑤getState():該方法返回Thread對(duì)象的狀態(tài)。

interrupt():中斷目標(biāo)線程卒暂,給目標(biāo)線程發(fā)送一個(gè)中斷信號(hào)啄栓,線程被打上中斷標(biāo)記。

interrupted():判斷目標(biāo)線程是否被中斷也祠,但是將清除線程的中斷標(biāo)記昙楚。

isinterrupted():判斷目標(biāo)線程是否被中斷,不會(huì)清除中斷標(biāo)記诈嘿。

sleep(long ms):該方法將線程的執(zhí)行暫停ms時(shí)間堪旧。

join():暫停線程的執(zhí)行削葱,直到調(diào)用該方法的線程執(zhí)行結(jié)束為止〈久危可以使用該方法等待另一個(gè)Thread對(duì)象結(jié)束析砸。

setUncaughtExceptionHandler():當(dāng)線程執(zhí)行出現(xiàn)未校驗(yàn)異常時(shí),該方法用于建立未校驗(yàn)異常的控制器爆袍。

currentThread():Thread類(lèi)的靜態(tài)方法首繁,返回實(shí)際執(zhí)行該代碼的Thread對(duì)象。

join示例程序(a程序在執(zhí)行螃宙,突然調(diào)用b程序的join方法就行執(zhí)行完b程序再執(zhí)行a程序):

1.1.4 Callable

Callable 接口是一個(gè)與Runnable 接口非常相似的接口蛮瞄。Callable 接口的主要特征如下。

①接口谆扎。有簡(jiǎn)單類(lèi)型參數(shù)挂捅,與call()方法的返回類(lèi)型相對(duì)應(yīng)。

②聲明了call()方法堂湖。執(zhí)行器運(yùn)行任務(wù)時(shí)闲先,該方法會(huì)被執(zhí)行器執(zhí)行。它必須返回聲明中指定類(lèi)型的對(duì)象无蜂。

③call()方法可以拋出任何一種校驗(yàn)異常伺糠。可以實(shí)現(xiàn)自己的執(zhí)行器并重載afterExecute()方法來(lái)處理這些異常斥季。

可以有返回值

可以處理任何異常

1.2 synchronized關(guān)鍵字

1.2.1 鎖的對(duì)象

synchronized關(guān)鍵字“給某個(gè)對(duì)象加鎖”训桶,示例代碼:

等價(jià)于=

實(shí)例方法的鎖加在對(duì)象myClass上;靜態(tài)方法的鎖加在MyClass.class上酣倾。

1.2.2 鎖的本質(zhì)

如果一份資源需要多個(gè)線程同時(shí)訪問(wèn)舵揭,需要給該資源加鎖。加鎖之后躁锡,可以保證同一時(shí)間只能有一個(gè)線程訪問(wèn)該資源午绳。資源可以是一個(gè)變量、一個(gè)對(duì)象或一個(gè)文件等映之。

1.2.3 實(shí)現(xiàn)原理

鎖如何實(shí)現(xiàn)拦焚?

在對(duì)象頭里,有一塊數(shù)據(jù)叫Mark Word杠输。在64位機(jī)器上赎败,Mark Word是8字節(jié)(64位)的,這64位中有2個(gè)重要字段:鎖標(biāo)志位和占用該鎖的thread ID蠢甲。因?yàn)椴煌姹镜腏VM實(shí)現(xiàn)僵刮,對(duì)象頭的數(shù)據(jù)結(jié)構(gòu)會(huì)有各種差異。

1.3 wait與notify

1.3.1 生產(chǎn)者?消費(fèi)者模型

生產(chǎn)者-消費(fèi)者模型是一個(gè)常見(jiàn)的多線程編程模型,如下圖所示:

1.如何阻塞妓笙?

辦法1:線程自己阻塞自己,也就是生產(chǎn)者能岩、消費(fèi)者線程各自調(diào)用wait()和notify()寞宫。

辦法2:用一個(gè)阻塞隊(duì)列,當(dāng)取不到或者放不進(jìn)去數(shù)據(jù)的時(shí)候拉鹃,入隊(duì)/出隊(duì)函數(shù)本身就是阻塞的辈赋。

2.如何雙向通知?

辦法1:wait()與notify()機(jī)制膏燕。

辦法2:Condition機(jī)制钥屈。

單個(gè)生產(chǎn)者單個(gè)消費(fèi)者線程的情形:

多個(gè)生產(chǎn)者單個(gè)消費(fèi)者線程的情形:

1.3.2 為什么必須和synchronized一起使用

在Java里面,wait()和notify()是Object的成員函數(shù)坝辫,是基礎(chǔ)中的基礎(chǔ)篷就。為什么Java要把wait()和notify()放在如此基礎(chǔ)的類(lèi)里面,而不是作為像Thread一類(lèi)的成員函數(shù)近忙,或者其他類(lèi)的成員函數(shù)呢竭业?

先看為什么wait()和notify()必須和synchronized一起使用?請(qǐng)看下面的代碼:

或者下面代碼????

1.3.3 為什么wait()的時(shí)候必須釋放鎖

1.3.4 wait()與notify()的問(wèn)題

以上述的生產(chǎn)者-消費(fèi)者模型來(lái)看及舍,其偽代碼大致如下:

生產(chǎn)者在通知消費(fèi)者的同時(shí)未辆,也通知了其他的生產(chǎn)者;消費(fèi)者在通知生產(chǎn)者的同時(shí)锯玛,也通知了其他消費(fèi)者咐柜。原因在于wait()和notify()所作用的對(duì)象和synchronized所作用的對(duì)象是同一個(gè),只能有一個(gè)對(duì)象攘残,無(wú)法區(qū)分隊(duì)列空和列隊(duì)滿兩個(gè)條件拙友。這正是Condition要解決的問(wèn)題。

1.4 InterruptedException與interrupt()方法

1.4.1 Interrupted異常

什么情況下會(huì)拋出Interrupted異常

假設(shè)while循環(huán)中沒(méi)有調(diào)用任何的阻塞函數(shù)肯腕,就是通常的算術(shù)運(yùn)算献宫,或者打印一行日志,如下所示实撒。

這個(gè)時(shí)候姊途,在主線程中調(diào)用一句thread.interrupt(),請(qǐng)問(wèn)該線程是否會(huì)拋出異常知态?不會(huì)捷兰。

只有那些聲明了會(huì)拋出InterruptedException的函數(shù)才會(huì)拋出異常,也就是下面這些常用的函數(shù):

本來(lái)sleep1000毫秒负敏,現(xiàn)在改變狀態(tài)為100毫秒贡茅,就拋出異常,但是一拋出異常,中斷狀態(tài)就變成false了

1.4.2 輕量級(jí)阻塞與重量級(jí)阻塞

能夠被中斷的阻塞稱為輕量級(jí)阻塞顶考,對(duì)應(yīng)的線程狀態(tài)是WAITING或者TIMED_WAITING赁还;而像synchronized 這種不能被中斷的阻塞稱為重量級(jí)阻塞,對(duì)應(yīng)的狀態(tài)是 BLOCKED驹沿。如圖所示:調(diào)用不同的方法后艘策,一個(gè)線程的狀態(tài)遷移過(guò)程。

????????初始線程處于NEW狀態(tài)渊季,調(diào)用start()開(kāi)始執(zhí)行后朋蔫,進(jìn)入RUNNING或者READY狀態(tài)。如果沒(méi)有調(diào)用任何的阻塞函數(shù)却汉,線程只會(huì)在RUNNING和READY之間切換驯妄,也就是系統(tǒng)的時(shí)間片調(diào)度。這兩種狀態(tài)的切換是操作系統(tǒng)完成的合砂,除非手動(dòng)調(diào)用yield()函數(shù)青扔,放棄對(duì)CPU的占用。

????????一旦調(diào)用了圖中的任何阻塞函數(shù)既穆,線程就會(huì)進(jìn)入WAITING或者TIMED_WAITING狀態(tài)赎懦,兩者的區(qū)別只是前者為無(wú)限期阻塞,后者則傳入了一個(gè)時(shí)間參數(shù)幻工,阻塞一個(gè)有限的時(shí)間励两。如果使用了synchronized關(guān)鍵字或者synchronized塊,則會(huì)進(jìn)入BLOCKED狀態(tài)囊颅。

????????不太常見(jiàn)的阻塞/喚醒函數(shù)当悔,LockSupport.park()/unpark()。這對(duì)函數(shù)非常關(guān)鍵踢代,Concurrent包中Lock的實(shí)現(xiàn)即依賴這一對(duì)操作原語(yǔ)盲憎。

????????因此thread.interrupted()的精確含義是“喚醒輕量級(jí)阻塞”,而不是字面意思“中斷一個(gè)線程”胳挎。

thread.isInterrupted()與Thread.interrupted()的區(qū)別

????????因?yàn)?thread.interrupted()相當(dāng)于給線程發(fā)送了一個(gè)喚醒的信號(hào)饼疙,所以如果線程此時(shí)恰好處于WAITING或者TIMED_WAITING狀態(tài),就會(huì)拋出一個(gè)InterruptedException慕爬,并且線程被喚醒窑眯。而如果線程此時(shí)并沒(méi)有被阻塞,則線程什么都不會(huì)做医窿。但在后續(xù)磅甩,線程可以判斷自己是否收到過(guò)其他線程發(fā)來(lái)的中斷信號(hào),然后做一些對(duì)應(yīng)的處理姥卢。

? ??????這兩個(gè)方法都是線程用來(lái)判斷自己是否收到過(guò)中斷信號(hào)的卷要,前者是實(shí)例方法渣聚,后者是靜態(tài)方法。二者的區(qū)別在于僧叉,前者只是讀取中斷狀態(tài)奕枝,不修改狀態(tài);后者不僅讀取中斷狀態(tài)瓶堕,還會(huì)重置中斷標(biāo)志位倍权。

1.5 線程的優(yōu)雅關(guān)閉

1.5.1 stop與destory函數(shù)

1.5.2 守護(hù)線程

daemon線程和非daemon線程的對(duì)比:

1.5.3 設(shè)置關(guān)閉的標(biāo)志位

開(kāi)發(fā)中一般通過(guò)設(shè)置標(biāo)志位的方式,停止循環(huán)運(yùn)行的線程捞烟。

????????但上面的代碼有一個(gè)問(wèn)題:如果MyThread t在while循環(huán)中阻塞在某個(gè)地方,例如里面調(diào)用了object.wait()函數(shù)当船,那它可能永遠(yuǎn)沒(méi)有機(jī)會(huì)再執(zhí)行 while( ! stopped)代碼题画,也就一直無(wú)法退出循環(huán)。

? ??????此時(shí)德频,就要用到InterruptedException()與interrupt()函數(shù)苍息。

2 并發(fā)核心概念

2.1 并發(fā)與并行

2.2 同步?

2.3 不可變對(duì)象

2.4 原子操作和原子變量

2.5 共享內(nèi)存與消息傳遞

3 并發(fā)的問(wèn)題

3.1 數(shù)據(jù)競(jìng)爭(zhēng)

????????如果有兩個(gè)或者多個(gè)任務(wù)在臨界段之外對(duì)一個(gè)共享變量進(jìn)行寫(xiě)入操作,也就是說(shuō)沒(méi)有使用任何同步機(jī)制壹置,那么應(yīng)用程序可能存在數(shù)據(jù)競(jìng)爭(zhēng)(也叫做競(jìng)爭(zhēng)條件)竞思。

????????在這些情況下,應(yīng)用程序的最終結(jié)果可能取決于任務(wù)的執(zhí)行順序钞护。

????????假設(shè)有兩個(gè)不同的任務(wù)執(zhí)行了同一個(gè)modify方法盖喷。由于任務(wù)中語(yǔ)句的執(zhí)行順序不同,最終結(jié)果也會(huì)不同难咕。

????????modify方法不是原子的课梳, ConcurrentDemo 也不是線程安全的。

3.2 死鎖

3.3 活鎖

3.4 資源不足

3.5 優(yōu)先權(quán)反轉(zhuǎn)

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
禁止轉(zhuǎn)載余佃,如需轉(zhuǎn)載請(qǐng)通過(guò)簡(jiǎn)信或評(píng)論聯(lián)系作者暮刃。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市爆土,隨后出現(xiàn)的幾起案子椭懊,更是在濱河造成了極大的恐慌,老刑警劉巖步势,帶你破解...
    沈念sama閱讀 222,378評(píng)論 6 516
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件氧猬,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)磁椒,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,970評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門(mén)粹庞,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人泉哈,你說(shuō)我怎么就攤上這事。” “怎么了丛晦?”我有些...
    開(kāi)封第一講書(shū)人閱讀 168,983評(píng)論 0 362
  • 文/不壞的土叔 我叫張陵奕纫,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我烫沙,道長(zhǎng)匹层,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 59,938評(píng)論 1 299
  • 正文 為了忘掉前任锌蓄,我火速辦了婚禮升筏,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘瘸爽。我一直安慰自己您访,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,955評(píng)論 6 398
  • 文/花漫 我一把揭開(kāi)白布剪决。 她就那樣靜靜地躺著灵汪,像睡著了一般。 火紅的嫁衣襯著肌膚如雪柑潦。 梳的紋絲不亂的頭發(fā)上享言,一...
    開(kāi)封第一講書(shū)人閱讀 52,549評(píng)論 1 312
  • 那天,我揣著相機(jī)與錄音渗鬼,去河邊找鬼览露。 笑死,一個(gè)胖子當(dāng)著我的面吹牛譬胎,可吹牛的內(nèi)容都是我干的肛循。 我是一名探鬼主播,決...
    沈念sama閱讀 41,063評(píng)論 3 422
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼银择,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼多糠!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起浩考,我...
    開(kāi)封第一講書(shū)人閱讀 39,991評(píng)論 0 277
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤夹孔,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后析孽,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體搭伤,經(jīng)...
    沈念sama閱讀 46,522評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,604評(píng)論 3 342
  • 正文 我和宋清朗相戀三年袜瞬,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了怜俐。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,742評(píng)論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡邓尤,死狀恐怖拍鲤,靈堂內(nèi)的尸體忽然破棺而出贴谎,到底是詐尸還是另有隱情,我是刑警寧澤季稳,帶...
    沈念sama閱讀 36,413評(píng)論 5 351
  • 正文 年R本政府宣布擅这,位于F島的核電站,受9級(jí)特大地震影響景鼠,放射性物質(zhì)發(fā)生泄漏仲翎。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,094評(píng)論 3 335
  • 文/蒙蒙 一铛漓、第九天 我趴在偏房一處隱蔽的房頂上張望溯香。 院中可真熱鬧,春花似錦浓恶、人聲如沸逐哈。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,572評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至禀梳,卻和暖如春杜窄,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背算途。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,671評(píng)論 1 274
  • 我被黑心中介騙來(lái)泰國(guó)打工塞耕, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人嘴瓤。 一個(gè)月前我還...
    沈念sama閱讀 49,159評(píng)論 3 378
  • 正文 我出身青樓扫外,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親廓脆。 傳聞我的和親對(duì)象是個(gè)殘疾皇子筛谚,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,747評(píng)論 2 361

推薦閱讀更多精彩內(nèi)容