成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

Java 多線程核心技術(shù)梳理(附源碼)

Winer / 3155人閱讀

摘要:本文對(duì)多線程基礎(chǔ)知識(shí)進(jìn)行梳理,主要包括多線程的基本使用,對(duì)象及變量的并發(fā)訪問,線程間通信,的使用,定時(shí)器,單例模式,以及線程狀態(tài)與線程組。源碼采用構(gòu)建,多線程這部分源碼位于模塊中。通知可能等待該對(duì)象的對(duì)象鎖的其他線程。

本文對(duì)多線程基礎(chǔ)知識(shí)進(jìn)行梳理,主要包括多線程的基本使用,對(duì)象及變量的并發(fā)訪問,線程間通信,lock的使用,定時(shí)器,單例模式,以及線程狀態(tài)與線程組。

寫在前面

花了一周時(shí)間閱讀《java多線程編程核心技術(shù)》(高洪巖 著),本文算是此書的整理歸納,書中幾乎所有示例,我都親手敲了一遍,并上傳到了我的github上,有興趣的朋友可以到我的github下載。源碼采用maven構(gòu)建,多線程這部分源碼位于java-multithread模塊中。

倉庫地址:java-learning

git clone: [email protected]:brianway/java-learning.git

java多線程

基礎(chǔ)知識(shí)

創(chuàng)建線程的兩種方式:1.繼承Thread類,2.實(shí)現(xiàn)Runnable接口。具體兩者的聯(lián)系可以參考我之前的博文《java基礎(chǔ)鞏固筆記(5)-多線程之傳統(tǒng)多線程》

一些基本API:isAlive(),sleep(),getId(),yield()等。

isAlive()測(cè)試線程是否處于活動(dòng)狀態(tài)

sleep()讓“正在執(zhí)行的線程”休眠

getId()取得線程唯一標(biāo)識(shí)

yield()放棄當(dāng)前的CPU資源

棄用的API:stop(),suspend(),resume()等,已經(jīng)棄用了,因?yàn)榭赡墚a(chǎn)生數(shù)據(jù)不同步等問題。

停止線程的幾種方式:

使用退出標(biāo)識(shí),使線程正常退出,即run方法完成。

使用interrupt方法中斷線程

線程的優(yōu)先級(jí):繼承性,規(guī)則性,隨機(jī)性

線程的優(yōu)先級(jí)具有繼承性. 如,線程A啟動(dòng)線程B,則B和A優(yōu)先級(jí)一樣

線程的優(yōu)先級(jí)具有規(guī)則性. CPU盡量傾向于把資源優(yōu)先級(jí)高的線程

線程的優(yōu)先級(jí)具有隨機(jī)性. 優(yōu)先級(jí)不等同于執(zhí)行順序,二者關(guān)系不確定

java中的兩種線程:用戶線程和守護(hù)(Daemon)線程。

守護(hù)線程:進(jìn)程中不存在非守護(hù)線程時(shí),守護(hù)線程自動(dòng)銷毀。典型例子如:垃圾回收線程。

比較和辨析

某個(gè)線程與當(dāng)前線程:當(dāng)前線程則是指正在運(yùn)行的那個(gè)線程,可由currentThread()方法返回值確定。例如,直接在main方法里調(diào)用run方法,和調(diào)用線程的start方法,打印出的當(dāng)前線程結(jié)果是不同的。

interrupted()isInterrupted()

interrupted()是類的靜態(tài)方法,測(cè)試當(dāng)前線程是否已經(jīng)是中斷狀態(tài),執(zhí)行后具有將狀態(tài)標(biāo)志清除為false的功能。

isInterrupted()是類的實(shí)例方法,測(cè)試Thread對(duì)象是否已經(jīng)是中斷狀態(tài),但不清楚狀態(tài)標(biāo)志。

sleep()wait()區(qū)別:

sleep()是Thread類的static(靜態(tài))的方法;wait()方法是Object類里的方法

sleep()睡眠時(shí),保持對(duì)象鎖,仍然占有該鎖;wait()睡眠時(shí),釋放對(duì)象鎖

在sleep()休眠時(shí)間期滿后,該線程不一定會(huì)立即執(zhí)行,這是因?yàn)槠渌€程可能正在運(yùn)行而且沒有被調(diào)度為放棄執(zhí)行,除非此線程具有更高的優(yōu)先級(jí);wait()使用notify或者notifyAlll或者指定睡眠時(shí)間來喚醒當(dāng)前等待池中的線程

wait()必須放在synchronized block中,否則會(huì)在runtime時(shí)扔出java.lang.IllegalMonitorStateException異常

方法 是否釋放鎖 備注
wait wait和notify/notifyAll是成對(duì)出現(xiàn)的, 必須在synchronize塊中被調(diào)用
sleep 可使低優(yōu)先級(jí)的線程獲得執(zhí)行機(jī)會(huì)
yield yield方法使當(dāng)前線程讓出CPU占有權(quán), 但讓出的時(shí)間是不可設(shè)定的
對(duì)象及變量的并發(fā)訪問

synchronized關(guān)鍵字

調(diào)用用關(guān)鍵字synchronized聲明的方法是排隊(duì)運(yùn)行的。但假如線程A持有某對(duì)象的鎖,那線程B異步調(diào)用非synchronized類型的方法不受限制。

synchronized鎖重入:一個(gè)線程得到對(duì)象鎖后,再次請(qǐng)求此對(duì)象鎖時(shí)是可以得到該對(duì)象的鎖的。同時(shí),子類可通過“可重入鎖”調(diào)用父類的同步方法。

同步不具有繼承性。

synchronized使用的“對(duì)象監(jiān)視器”是一個(gè),即必須是同一個(gè)對(duì)象

synchronized同步方法和synchronized同步代碼塊。

對(duì)其他synchronized同步方法或代碼塊調(diào)用呈阻塞狀態(tài)。

同一時(shí)間只有一個(gè)線程可執(zhí)行synchronized方法/代碼塊中的代碼

synchronized(非this對(duì)象x),將x對(duì)象作為“對(duì)象監(jiān)視器”

當(dāng)多個(gè)線程同時(shí)執(zhí)行synchronized(x){}同步代碼塊時(shí)呈同步效果

當(dāng)其他線程執(zhí)行x對(duì)象中synchronizd同步方法時(shí)呈同步效果

當(dāng)其他線程執(zhí)行x對(duì)象方法里的synchronized(this)代碼塊時(shí)呈同步效果

靜態(tài)同步synchronized方法與synchronized(class)代碼塊:對(duì)當(dāng)前對(duì)應(yīng)的class類進(jìn)行持鎖。

線程的私有堆棧圖

volatile關(guān)鍵字:主要作用是使變量在多個(gè)線程間可見。加volatile關(guān)鍵字可強(qiáng)制性從公共堆棧進(jìn)行取值,而不是從線程私有數(shù)據(jù)棧中取得變量的值

在方法中while循環(huán)中設(shè)置狀態(tài)位(不加volatile關(guān)鍵字),在外面把狀態(tài)位置位并不可行,循環(huán)不會(huì)停止,比如JVM在-server模式。

原因:是私有堆棧中的值和公共堆棧中的值不同步

volatile增加了實(shí)例變量在多個(gè)線程間的可見性,但不支持原子性

原子類:一個(gè)原子類型就是一個(gè)原子操作可用的類型,可在沒有鎖的情況下做到線程安全。但原子類也不是完全安全,雖然原子操作是安全的,可方法間的調(diào)用卻不是原子的,需要用同步。

讀取公共內(nèi)存圖

辨析和零散補(bǔ)充

synchronized靜態(tài)方法與非靜態(tài)方法:synchronized關(guān)鍵字加static靜態(tài)方法上是給Class類上鎖,可以對(duì)類的所有實(shí)例對(duì)象起作用;synchronized關(guān)鍵字加到非static靜態(tài)方法上是給對(duì)象上鎖,對(duì)該對(duì)象起作用。這兩個(gè)鎖不是同一個(gè)鎖。

synchronized和volatile比較

1)關(guān)鍵字volatile是線程同步的輕量級(jí)實(shí)現(xiàn),性能比synchronized好,且volatile只能修飾變量,synchronized可修飾方法和代碼塊。

2)多線程訪問volatile不會(huì)發(fā)生阻塞,synchronized會(huì)出現(xiàn)阻塞

3)volatile能保證數(shù)據(jù)可見性,不保證原子性;synchronized可以保證原子性,也可以間接保證可見性,因?yàn)?strong>synchronized會(huì)將私有內(nèi)存和公共內(nèi)存中的數(shù)據(jù)做同步。

4)volatile解決的是變量在多個(gè)線程間的可見性,synchronized解決的是多個(gè)線程訪問資源的同步性。

String常量池特性,故大多數(shù)情況下,synchronized代碼塊都不適用String作為鎖對(duì)象。

多線程死鎖。使用JDK自帶工具,jps命令+jstack命令監(jiān)測(cè)是否有死鎖。

內(nèi)置類與靜態(tài)內(nèi)置類。

鎖對(duì)象的的改變。

一個(gè)線程出現(xiàn)異常時(shí),其所持有的鎖會(huì)自動(dòng)釋放。

變量在內(nèi)存中的工作過程圖

線程間通信

等待/通知機(jī)制:wait()notify()/notifyAll()。wait使線程停止運(yùn)行,notify使停止的線程繼續(xù)運(yùn)行。

wait():將當(dāng)前執(zhí)行代碼的線程進(jìn)行等待,置入"預(yù)執(zhí)行隊(duì)列"。

在調(diào)用wait()之前,線程必須獲得該對(duì)象的對(duì)象級(jí)別鎖;

執(zhí)行wait()方法后,當(dāng)前線程立即釋放鎖;

從wait()返回前,線程與其他線程競爭重新獲得鎖

當(dāng)線程呈wait()狀態(tài)時(shí),調(diào)用線程的interrup()方法會(huì)出現(xiàn)InterrupedException異常

wait(long)是等待某一時(shí)間內(nèi)是否有線程對(duì)鎖進(jìn)行喚醒,超時(shí)則自動(dòng)喚醒。

notify():通知可能等待該對(duì)象的對(duì)象鎖的其他線程。隨機(jī)挑選一個(gè)呈wait狀態(tài)的線程,使它等待獲取該對(duì)象的對(duì)象鎖。

在調(diào)用notify()之前,線程必須獲得該對(duì)象的對(duì)象級(jí)別鎖;

執(zhí)行完notify()方法后,不會(huì)馬上釋放鎖,要直到退出synchronized代碼塊,當(dāng)前線程才會(huì)釋放鎖。

notify()一次只隨機(jī)通知一個(gè)線程進(jìn)行喚醒

notifyAll()notify()差不多,只不過是使所有正在等待隊(duì)中等待同一共享資源的“全部”線程從等待狀態(tài)退出,進(jìn)入可運(yùn)行狀態(tài)。

每個(gè)鎖對(duì)象有兩個(gè)隊(duì)列:就緒隊(duì)列和阻塞隊(duì)列。

就緒隊(duì)列:存儲(chǔ)將要獲得鎖的線程

阻塞隊(duì)列:存儲(chǔ)被阻塞的的線程

生產(chǎn)者/消費(fèi)者模式

“假死”:線程進(jìn)入WAITING等待狀態(tài),呈假死狀態(tài)的進(jìn)程中所有線程都呈WAITING狀態(tài)。

假死的主要原因:有可能連續(xù)喚醒同類。notify喚醒的不一定是異類,也許是同類,如“生產(chǎn)者”喚醒“生產(chǎn)者”。

解決假死:將notify()改為notifyAll()

wait條件改變,可能出現(xiàn)異常,需要將if改成while

通過管道進(jìn)行線程間通信:一個(gè)線程發(fā)送數(shù)據(jù)到輸出管道,另一個(gè)線程從輸入管道讀數(shù)據(jù)。

字節(jié)流:PipedInputStreamPipedOutputStream

字符流:PipedReaderPipedWriter

join():等待線程對(duì)象銷毀,具有使線程排隊(duì)運(yùn)行的作用。

join()與interrupt()方法彼此遇到會(huì)出現(xiàn)異常。

join(long)可設(shè)定等待的時(shí)間

joinsynchronized的區(qū)別:join在內(nèi)部使用wait()方法進(jìn)行等待;synchronized使用的是“對(duì)象監(jiān)視器”原理作為同步

join(long)sleep(long)的區(qū)別:join(long)內(nèi)部使用wait(long)實(shí)現(xiàn),所以join(long)具有釋放鎖的特點(diǎn);Thread.sleep(long)不釋放鎖。

ThreadLocal類:每個(gè)線程綁定自己的值

覆寫該類的initialValue()方法可以使變量初始化,從而解決get()返回null的問題

InheritableThreadLocal類可在子線程中取得父線程繼承下來的值。

Lock的使用

ReentrantLock類:實(shí)現(xiàn)線程之間的同步互斥,比synchronized更靈活

lock(),調(diào)用了的線程就持有了“對(duì)象監(jiān)視器”,效果和synchronized一樣

使用Condition實(shí)現(xiàn)等待/通知:比wait()和notify()/notyfyAll()更靈活,比如可實(shí)現(xiàn)多路通知。

調(diào)用condition.await()前須先調(diào)用lock.lock()獲得同步監(jiān)視器

Object與Condition方法對(duì)比

Object Condition
wait() await()
wait(long timeout) await(long time,TimeUnit unit)
notify() signal()
notifyAll() signalAll()

一些API

方法 說明
int getHoldCount() 查詢當(dāng)前線程保持此鎖定的個(gè)數(shù),即調(diào)用lock()方法的次數(shù)
int getQueueLength() 返回正在等待獲取此鎖定的線程估計(jì)數(shù)
int getWaitQueueLength(Condition condition) 返回等待與此鎖定相關(guān)的給定條件Conditon的線程估計(jì)數(shù)
boolean hasQueueThread(Thread thread) 查詢指定的線程是否正在等待獲取此鎖定
boolean hasQueueThreads() 查詢是否有線程正在等待獲取此鎖定
boolean hasWaiters(Condition) 查詢是否有線程正在等待與此鎖定有關(guān)的condition條件
boolean isFair() 判斷是不是公平鎖
boolean isHeldByCurrentThread() 查詢當(dāng)前線程是否保持此鎖定
boolean isLocked() 查詢此鎖定是否由任意線程保持
void lockInterruptibly() 如果當(dāng)前線程未被中斷,則獲取鎖定,如果已經(jīng)被中斷則出現(xiàn)異常
boolean tryLock() 僅在調(diào)用時(shí)鎖定未被另一個(gè)線程保持的情況下,才獲取該鎖定
boolean tryLock(long timeout,TimeUnit unit) 如果鎖定在給定等待時(shí)間內(nèi)沒有被另一個(gè)線程保持,且當(dāng)前線程未被中斷,則獲取該鎖定

公平鎖與非公平鎖

公平鎖表示線程獲取鎖的順序是按照加鎖的順序來分配的,即FIFO先進(jìn)先出。

非公平鎖是一種獲取鎖的搶占機(jī)制,隨機(jī)獲得鎖。

ReentrantReadWriteLock

讀讀共享

寫寫互斥

讀寫互斥

寫讀互斥

定時(shí)器

常用API

方法 說明
schedule(TimerTask task, Date time) 在指定的日期執(zhí)行某一次任務(wù)
scheduleAtFixedRate(TimerTask task, Date firstTime, long period) 在指定的日期之后按指定的間隔周期,無限循環(huán)的執(zhí)行某一任務(wù)
schedule(TimerTask task, long delay) 以執(zhí)行此方法的當(dāng)前時(shí)間為參考時(shí)間,在此時(shí)間基礎(chǔ)上延遲指定的毫秒數(shù)后執(zhí)行一次TimerTask任務(wù)
schedule(TimerTask task, long delay, long period) 以執(zhí)行此方法的當(dāng)前時(shí)間為參考時(shí)間,在此時(shí)間基礎(chǔ)上延遲指定的毫秒數(shù),再以某一間隔時(shí)間無限次數(shù)地執(zhí)行某一TimerTask任務(wù)

schedulescheduleAtFixedRate的區(qū)別:schedule不具有追趕執(zhí)行性;scheduleAtFixedRate具有追趕執(zhí)行性

單例模式與多線程

立即加載/“餓漢模式”:調(diào)用方法前,實(shí)例已經(jīng)被創(chuàng)建了。通過靜態(tài)屬性new實(shí)例化實(shí)現(xiàn)的

延遲加載/“懶漢模式”:調(diào)用get()方法時(shí)實(shí)例才被創(chuàng)建。最常見的實(shí)現(xiàn)辦法是在get()方法中進(jìn)行new實(shí)例化

缺點(diǎn):多線程環(huán)境中,會(huì)出問題

解決方法

聲明synchronized關(guān)鍵字,但運(yùn)行效率非常低下

同步代碼塊,效率也低

針對(duì)某些重要代碼(實(shí)例化語句)多帶帶同步,效率提升,但會(huì)出問題

使用DCL雙檢查鎖

使用enum枚舉數(shù)據(jù)類型實(shí)現(xiàn)單例模式

拾遺補(bǔ)增

方法與狀態(tài)關(guān)系示意圖

線程的狀態(tài):Thread.State枚舉類,參考官網(wǎng)APIEnum Thread.State

線程組:線程組中可以有線程對(duì)象,也可以有線程組,組中還可以有線程??膳抗芾砭€程或線程組對(duì)象。

SimpleDateFormat非線程安全,解決辦法有:

創(chuàng)建多個(gè)SimpleDateFormat類的實(shí)例

使用ThreadLocal類

線程組出現(xiàn)異常的處理

setUncaughtExceptionHandler()給指定線程對(duì)象設(shè)置異常處理器

setDefaultUncaughtExceptionHandler()對(duì)所有線程對(duì)象設(shè)置異常處理器

參考資料

淺談Java中的鎖

java synchronized關(guān)鍵字的用法

Java Thread(線程)案例詳解sleep和wait的區(qū)別

作者@brianway更多文章:個(gè)人網(wǎng)站 | CSDN | oschina

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/71133.html

相關(guān)文章

  • Java學(xué)習(xí)路線總結(jié),搬磚工逆襲Java架構(gòu)師(全網(wǎng)最強(qiáng))

    摘要:哪吒社區(qū)技能樹打卡打卡貼函數(shù)式接口簡介領(lǐng)域優(yōu)質(zhì)創(chuàng)作者哪吒公眾號(hào)作者架構(gòu)師奮斗者掃描主頁左側(cè)二維碼,加入群聊,一起學(xué)習(xí)一起進(jìn)步歡迎點(diǎn)贊收藏留言前情提要無意間聽到領(lǐng)導(dǎo)們的談話,現(xiàn)在公司的現(xiàn)狀是碼農(nóng)太多,但能獨(dú)立帶隊(duì)的人太少,簡而言之,不缺干 ? 哪吒社區(qū)Java技能樹打卡?【打卡貼 day2...

    Scorpion 評(píng)論0 收藏0
  • 后臺(tái)開發(fā)常問面試題集錦(問題搬運(yùn)工,鏈接)

    摘要:基礎(chǔ)問題的的性能及原理之區(qū)別詳解備忘筆記深入理解流水線抽象關(guān)鍵字修飾符知識(shí)點(diǎn)總結(jié)必看篇中的關(guān)鍵字解析回調(diào)機(jī)制解讀抽象類與三大特征時(shí)間和時(shí)間戳的相互轉(zhuǎn)換為什么要使用內(nèi)部類對(duì)象鎖和類鎖的區(qū)別,,優(yōu)缺點(diǎn)及比較提高篇八詳解內(nèi)部類單例模式和 Java基礎(chǔ)問題 String的+的性能及原理 java之yield(),sleep(),wait()區(qū)別詳解-備忘筆記 深入理解Java Stream流水...

    spacewander 評(píng)論0 收藏0
  • 后臺(tái)開發(fā)常問面試題集錦(問題搬運(yùn)工,鏈接)

    摘要:基礎(chǔ)問題的的性能及原理之區(qū)別詳解備忘筆記深入理解流水線抽象關(guān)鍵字修飾符知識(shí)點(diǎn)總結(jié)必看篇中的關(guān)鍵字解析回調(diào)機(jī)制解讀抽象類與三大特征時(shí)間和時(shí)間戳的相互轉(zhuǎn)換為什么要使用內(nèi)部類對(duì)象鎖和類鎖的區(qū)別,,優(yōu)缺點(diǎn)及比較提高篇八詳解內(nèi)部類單例模式和 Java基礎(chǔ)問題 String的+的性能及原理 java之yield(),sleep(),wait()區(qū)別詳解-備忘筆記 深入理解Java Stream流水...

    xfee 評(píng)論0 收藏0
  • 后臺(tái)開發(fā)常問面試題集錦(問題搬運(yùn)工,鏈接)

    摘要:基礎(chǔ)問題的的性能及原理之區(qū)別詳解備忘筆記深入理解流水線抽象關(guān)鍵字修飾符知識(shí)點(diǎn)總結(jié)必看篇中的關(guān)鍵字解析回調(diào)機(jī)制解讀抽象類與三大特征時(shí)間和時(shí)間戳的相互轉(zhuǎn)換為什么要使用內(nèi)部類對(duì)象鎖和類鎖的區(qū)別,,優(yōu)缺點(diǎn)及比較提高篇八詳解內(nèi)部類單例模式和 Java基礎(chǔ)問題 String的+的性能及原理 java之yield(),sleep(),wait()區(qū)別詳解-備忘筆記 深入理解Java Stream流水...

    makeFoxPlay 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<