并發(fā)系列1 Java并發(fā)編程基礎(chǔ)

參考:
《Java并發(fā)編程的藝術(shù)》第四章
《Java多線程編程核心技術(shù)》
博客 http://www.reibang.com/p/8a04b5ec786c Java多線程基礎(chǔ)
博客 http://www.reibang.com/p/12af2d966c13 Java并發(fā)編程1

一.線程簡(jiǎn)介

1.線程和進(jìn)程
  • 進(jìn)程是系統(tǒng)進(jìn)行資源分配和調(diào)度的一個(gè)獨(dú)立單位概而,現(xiàn)代操作系統(tǒng)運(yùn)行程序時(shí)會(huì)創(chuàng)建進(jìn)程
  • 線程也叫輕量級(jí)進(jìn)程狈孔,是現(xiàn)代操作系統(tǒng)調(diào)度的最小單元浑玛,一個(gè)進(jìn)程中可以有多個(gè)線程陕贮,每個(gè)線程都擁有各自的計(jì)數(shù)器带污、堆棧和局部變量等屬性怔软,并能夠訪問共享的內(nèi)存變量
2.為什么使用多線程
  • 更多的計(jì)算核心:充分利用多核處理器的硬件優(yōu)勢(shì)姜性,將計(jì)算邏輯分配給多個(gè)處理器同時(shí)執(zhí)行
  • 更快的響應(yīng)時(shí)間:在業(yè)務(wù)邏輯復(fù)雜的場(chǎng)景中猪叙,將數(shù)據(jù)一致性不強(qiáng)的操作派發(fā)給其他線程處理
  • 更好的編程邏輯:Java提供了良好并且一致的多線程編程模型赘风,方便開發(fā)者完成多線程開發(fā)
3.上下文切換
  • CPU切換運(yùn)行的線程時(shí)存儲(chǔ)和恢復(fù)CPU的過程夹囚,使得線程能夠從中斷點(diǎn)恢復(fù)執(zhí)行
  • 線程上下文切換過程中會(huì)記錄程序計(jì)數(shù)器、CPU寄存器狀態(tài)等
  • 多線程環(huán)境中上下文切換會(huì)帶來一定的性能開銷
4.線程優(yōu)先級(jí)
  • 現(xiàn)代操作系統(tǒng)采取分時(shí)的形式調(diào)度執(zhí)行的線程
  • 線程在獲取操作系統(tǒng)分出的時(shí)間片后開始執(zhí)行邀窃,時(shí)間片用完后停止執(zhí)行荸哟,等待再次獲得時(shí)間片
  • 線程優(yōu)先級(jí)決定線程獲取CPU時(shí)間片的優(yōu)先級(jí)
  • 注意:Java線程優(yōu)先級(jí)在某些操作系統(tǒng)中無效
5.線程的狀態(tài)
狀態(tài)名稱 說明
NEW 初始狀態(tài),線程被構(gòu)建瞬捕,但還沒有調(diào)用start()方法
RUNNABLE 運(yùn)行狀態(tài)鞍历,包括線程在操作系統(tǒng)中就緒和運(yùn)行兩種情況
BLOCKED 阻塞狀態(tài),表示線程阻塞于鎖
WAITING 等待狀態(tài)肪虎,進(jìn)入等待狀態(tài)的線程需要等待其他線程的特定動(dòng)作(通知或中斷)
TIME_WAITING 超時(shí)等待狀態(tài)劣砍,進(jìn)入超時(shí)等待狀態(tài)的線程可以在指定的時(shí)間自行返回
TERMINATED 終止?fàn)顟B(tài),表示當(dāng)前線程已經(jīng)執(zhí)行完畢
線程狀態(tài)切換
6. Daemon線程
  • 支持型線程扇救,用作程序中后臺(tái)調(diào)度以及支持型工作
  • JVM不存在非Daemon線程時(shí)刑枝,Daemon線程將自動(dòng)結(jié)束香嗓,JVM退出
  • 注意,在JVM退出時(shí)装畅,Daemon線程中的finally塊可能不會(huì)執(zhí)行

二.線程啟動(dòng)和終止

1.構(gòu)造線程
  • void init(ThreadGroup g, Runnable target, String name靠娱,long stackSize,AccessControlContext acc)方法完成線程構(gòu)造
  • 新構(gòu)造的線程對(duì)象由其parent線程進(jìn)行空間分配洁灵,繼承了parent線程的Daemon饱岸、優(yōu)先級(jí)和加載資源的contextClassLoader以及可繼承的ThreadLocal,同時(shí)獲得唯一的線程ID
2.線程的實(shí)現(xiàn)
  • 繼承Thread類徽千,重寫run()方法苫费,Thread類本身實(shí)現(xiàn)了Runnable接口
  • 實(shí)現(xiàn)Runnable接口,重寫run()方法
  • 使用ExecutorService双抽、Callable百框、Future實(shí)現(xiàn)有返回結(jié)果的多線程
3.線程中斷
  • 一個(gè)線程應(yīng)該自行停止,而非由其他線程強(qiáng)制中斷或停止
  • Thread.stop()不保證資源的正確釋放牍汹、Thread.suspend()暫停時(shí)不釋放鎖容易導(dǎo)致死鎖铐维、Thread.resume()等三個(gè)方法都已廢棄
  • 每個(gè)線程均有一個(gè)中斷標(biāo)志位,表示是否有其他線程對(duì)該線程進(jìn)行了中斷操作
  • 當(dāng)對(duì)一個(gè)線程調(diào)用interrupt()方法時(shí)
    1)如果線程處于等待狀態(tài)(如sleep慎菲、wait嫁蛇、join)時(shí),線程將立即退出等待狀態(tài)露该,并拋出一個(gè)interruptedException異常睬棚,僅此而已
    2)如果線程處于正常活動(dòng)狀態(tài)解幼,會(huì)將該線程的中斷標(biāo)志設(shè)置為true抑党,僅此而已。被設(shè)置中斷標(biāo)志的線程將繼續(xù)正常運(yùn)行撵摆,不受影響
  • 所以interrupt()并不能真正的中斷線程底靠,需要被調(diào)用的線程進(jìn)行配合。如果一個(gè)線程有被中斷的需求特铝,可以這樣做
    1)在正常運(yùn)行任務(wù)時(shí)暑中,使用isInterrupted()方法經(jīng)常檢查本線程的中斷標(biāo)志位,如果被設(shè)置了中斷標(biāo)志就自行停止
    2)線程處于等待狀態(tài)時(shí)鲫剿,catch到InterruptedException異常后退出線程
  • Thread.interrupted()方法將清除中斷標(biāo)志位痒芝,但并不代表線程又恢復(fù),僅代表線程已響應(yīng)該中斷信號(hào)然后重置為可再次接收信號(hào)的狀態(tài)
  • 處于等待的線程在調(diào)用interrupt()方法后拋出InterruptedException前牵素,JVM將先清除線程的中斷標(biāo)志位
Modifier and Type Method Description
void interrupt() Interrupts this thread
static boolean interrupted() Tests whether the current thread has been interrupted
boolean isInterrupted() Tests whether this thread has been interrupted

三.線程間通信

1.volatile和synchronized
  • Java支持多個(gè)線程同時(shí)訪問共享對(duì)象,現(xiàn)代多核處理器為了加速程序運(yùn)行澄者,每個(gè)線程會(huì)擁有共享對(duì)象的一份拷貝笆呆,由此引出內(nèi)存可見性問題——一個(gè)線程看到的變量并一定是最新的
  • volatile:修飾的字段(成員變量)请琳,要求程序?qū)υ撟兞康脑L問必須從共享內(nèi)存獲取,修改必須同步刷新回共享內(nèi)存赠幕,從而保證所有線程對(duì)變量訪問的可見性
  • synchronized:修飾方法或同步塊俄精,確保同一時(shí)刻,只有一個(gè)線程處于方法或同步塊中榕堰,保證了線程對(duì)變量訪問的可見性和排他性
  • 對(duì)象竖慧、對(duì)象的監(jiān)視器、同步隊(duì)列和執(zhí)行線程之間的關(guān)系
    1)任意線程對(duì)由synchronized保護(hù)的object的訪問逆屡,首先要獲得object的監(jiān)視器Monitor
    2)如果Monitor獲取失敗圾旨,線程進(jìn)入同步隊(duì)列SynchronizedQueue,線程為BLOCKED狀態(tài)
    3)當(dāng)其他獲得鎖訪問object的線程釋放鎖魏蔗,該釋放操作喚醒阻塞在同步隊(duì)列中的線程砍的,使其重新嘗試獲取object的Monitor
2.等待/通知機(jī)制
  • 生產(chǎn)者消費(fèi)者模式
    1)線程A修改了一個(gè)對(duì)象的值,線程B在感知變化后進(jìn)行相應(yīng)的操作
    2)整個(gè)過程開始于線程A(生產(chǎn)者)莺治,最終執(zhí)行于線程B(消費(fèi)者)
    3)該模式隔離了“做什么”(What)和“怎么做”(How)廓鞠,功能層面實(shí)現(xiàn)了解耦
  • 原始辦法
    消費(fèi)者線程不斷循環(huán)檢查信號(hào)變量是否變化,偽代碼如下谣旁,存在程序及時(shí)性和資源消耗量的兩難
while ( value != desire )  {
    Thread.sleep ( 1000 ) ;
}
doSometing();
  • 等待/通知機(jī)制 notify/wait
    1)線程A調(diào)用對(duì)象O的wait()方法進(jìn)入等待狀態(tài)
    2)線程B調(diào)用對(duì)象O的notify()notifyAll()方法通知線程A
    3)線程A收到通知后從對(duì)象O的wait()方法返回床佳,繼續(xù)執(zhí)行后續(xù)操作

  • 等待/通知機(jī)制流程
    1)使用wait()notify()榄审、notifyAll()時(shí)需要先對(duì)調(diào)用對(duì)象加鎖
    2)調(diào)用wait()后砌们,線程狀態(tài)由RUNNING變?yōu)閃AITING,并將當(dāng)前線程放置在等待隊(duì)列
    3)notify()notifyAll()方法調(diào)用后瘟判,等待線程依舊不會(huì)從wait()返回怨绣,需要調(diào)用notify()notifyAll()的線程釋放鎖之后,等待線程才會(huì)從wait()返回
    4)notify()/notifyAll()將等待隊(duì)列中的一個(gè)/全部等待線程從等待隊(duì)列中移到同步隊(duì)列拷获,被移動(dòng)的線程狀態(tài)由WAITING變?yōu)锽LOCKED
    5)從wait()方法返回(離開同步隊(duì)列開始運(yùn)行)的前提是獲得了調(diào)用對(duì)象的鎖

    Wait/Notify

  • 等待/通知的經(jīng)典范式

等待方偽代碼
1.獲取對(duì)象的鎖
2.如果條件不滿足篮撑,則調(diào)用對(duì)象的wait()方法,被通知后仍要檢查條件
3.條件滿足則執(zhí)行對(duì)應(yīng)邏輯
synchronized(對(duì)象)  {
      while(條件不滿足)  {
            對(duì)象.wait();
      }
      對(duì)應(yīng)的處理邏輯
}

通知方偽代碼
1.獲取對(duì)象的鎖
2.改變條件
3.通知所有等待在對(duì)象上的線程
synchronized(對(duì)象)  {
      改變條件
      對(duì)象.notifyAll();
}
3.管道輸入/輸出流
  • 管道IO主要用于線程間數(shù)據(jù)傳輸匆瓜,傳輸媒介為內(nèi)存赢笨,與文件IO或網(wǎng)絡(luò)IO不同
  • 主要實(shí)現(xiàn)類
    1)管道字節(jié)流:PipedOutputStreamPipedInputStream
    2)管道字符流:PipedReader驮吱、PipedWriter
PipedReader in = new PipedReader();
PipedWriter out = new PipedWriter();
//必須連接輸入流和輸出流茧妒,否則拋出異常
out.connect(in);
4.Thread.join()
  • 線程A使用thread.join()表示當(dāng)前線程A等待thread線程終止后才從thread.join()返回
  • join()方法的源代碼邏輯結(jié)構(gòu)與等待/通知經(jīng)典范式一致,即加鎖左冬、循環(huán)和處理邏輯三步
5.線程變量ThreadLocal
  • 以ThreadLocal對(duì)象為鍵桐筏、任意對(duì)象為值得存儲(chǔ)結(jié)構(gòu),依附于線程
  • 線程可以根據(jù)一個(gè)ThreadLocal對(duì)象查詢到綁定在這個(gè)線程上的一個(gè)值

那年離別日拇砰,只道住桐廬梅忌。桐廬人不見狰腌,今得廣州書

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市牧氮,隨后出現(xiàn)的幾起案子琼腔,更是在濱河造成了極大的恐慌,老刑警劉巖踱葛,帶你破解...
    沈念sama閱讀 206,126評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件丹莲,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡尸诽,警方通過查閱死者的電腦和手機(jī)甥材,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,254評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來逊谋,“玉大人擂达,你說我怎么就攤上這事〗鹤蹋” “怎么了板鬓?”我有些...
    開封第一講書人閱讀 152,445評(píng)論 0 341
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)究恤。 經(jīng)常有香客問我俭令,道長(zhǎng),這世上最難降的妖魔是什么部宿? 我笑而不...
    開封第一講書人閱讀 55,185評(píng)論 1 278
  • 正文 為了忘掉前任抄腔,我火速辦了婚禮,結(jié)果婚禮上理张,老公的妹妹穿的比我還像新娘赫蛇。我一直安慰自己,他們只是感情好雾叭,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,178評(píng)論 5 371
  • 文/花漫 我一把揭開白布悟耘。 她就那樣靜靜地躺著,像睡著了一般织狐。 火紅的嫁衣襯著肌膚如雪暂幼。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 48,970評(píng)論 1 284
  • 那天移迫,我揣著相機(jī)與錄音旺嬉,去河邊找鬼。 笑死厨埋,一個(gè)胖子當(dāng)著我的面吹牛邪媳,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 38,276評(píng)論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼悲酷,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼套菜!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起设易,我...
    開封第一講書人閱讀 36,927評(píng)論 0 259
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎蛹头,沒想到半個(gè)月后顿肺,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,400評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡渣蜗,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,883評(píng)論 2 323
  • 正文 我和宋清朗相戀三年屠尊,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片耕拷。...
    茶點(diǎn)故事閱讀 37,997評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡讼昆,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出骚烧,到底是詐尸還是另有隱情浸赫,我是刑警寧澤,帶...
    沈念sama閱讀 33,646評(píng)論 4 322
  • 正文 年R本政府宣布赃绊,位于F島的核電站既峡,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏碧查。R本人自食惡果不足惜运敢,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,213評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望忠售。 院中可真熱鬧传惠,春花似錦、人聲如沸稻扬。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,204評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽腐螟。三九已至愿汰,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間乐纸,已是汗流浹背衬廷。 一陣腳步聲響...
    開封第一講書人閱讀 31,423評(píng)論 1 260
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留汽绢,地道東北人吗跋。 一個(gè)月前我還...
    沈念sama閱讀 45,423評(píng)論 2 352
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親跌宛。 傳聞我的和親對(duì)象是個(gè)殘疾皇子酗宋,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,722評(píng)論 2 345

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