今天準備開始簡書之路君编,記錄自己的進步,這個階段從java開始信不,希望自己可以堅持下來贱迟。。抬探。這里的東西很多都是網(wǎng)上其他大神的結(jié)論子巾,都說的非常好帆赢!
廢話不多說:這幾天我們來看看? ?java多線程。
今天我們從多線程定義线梗,生命周期椰于,互斥/同步,簡單場景來穩(wěn)固一下多線程的定義仪搔。
什么是多線程:我之前的理解瘾婿,就是多個用戶進行了同一個操作。但是我在之前開發(fā)的時候烤咧,也沒有用得到多線程代碼偏陪,但是多個人訪問同一個接口也沒有錯啊。煮嫌。笛谦。為什么呢?直到我看了某網(wǎng)友的解釋以后明白了:
方法?存在JVM的一個內(nèi)存區(qū)昌阿,這個方法區(qū)被各個線程共享饥脑。
打個不恰當?shù)谋确剑缦拢?/p>
老師在黑板上面寫了一條1+1=懦冰?灶轰,同學們?同時看到信息后開始拿起筆計算。這里的黑板就相當于內(nèi)存區(qū)儿奶,1+1=框往??指令相當于方法,同學們相當于線程闯捎,大家一起并行計算椰弊,并沒有阻塞。
那什么時候有阻塞瓤鼻?
老師說秉版,誰要解答,請上講臺上來茬祷,這個時候可能會出現(xiàn)阻塞清焕。
這個解釋真的還是比較好懂的。祭犯。秸妥。直到了線程的基本概念以后,我們來看看線程的生命周期
Java線程具有五中基本狀態(tài)
新建狀態(tài)(New):當線程對象對創(chuàng)建后沃粗,即進入了新建狀態(tài)粥惧,如:Thread t = new MyThread();
就緒狀態(tài)(Runnable):當調(diào)用線程對象的start()方法(t.start();),線程即進入就緒狀態(tài)最盅。處于就緒狀態(tài)的線程突雪,只是說明此線程已經(jīng)做好了準備起惕,隨時等待CPU調(diào)度執(zhí)行,并不是說執(zhí)行了t.start()此線程立即就會執(zhí)行咏删;
運行狀態(tài)(Running):當CPU開始調(diào)度處于就緒狀態(tài)的線程時惹想,此時線程才得以真正執(zhí)行,即進入到運行狀態(tài)督函。注:就 ? ? 緒狀態(tài)是進入到運行狀態(tài)的唯一入口嘀粱,也就是說,線程要想進入運行狀態(tài)執(zhí)行侨核,首先必須處于就緒狀態(tài)中草穆;
阻塞狀態(tài)(Blocked):處于運行狀態(tài)中的線程由于某種原因灌灾,暫時放棄對CPU的使用權搓译,停止執(zhí)行,此時進入阻塞狀態(tài)锋喜,直到其進入到就緒狀態(tài)些己,才 有機會再次被CPU調(diào)用以進入到運行狀態(tài)。根據(jù)阻塞產(chǎn)生的原因不同嘿般,阻塞狀態(tài)又可以分為三種:
1.等待阻塞:運行狀態(tài)中的線程執(zhí)行wait()方法段标,使本線程進入到等待阻塞狀態(tài);
2.同步阻塞 -- 線程在獲取synchronized同步鎖失敗(因為鎖被其它線程所占用)炉奴,它會進入同步阻塞狀態(tài)逼庞;
3.其他阻塞 -- 通過調(diào)用線程的sleep()或join()或發(fā)出了I/O請求時,線程會進入到阻塞狀態(tài)瞻赶。當sleep()狀態(tài)超時赛糟、join()等待線程終止或者超時、或者I/O處理完畢時砸逊,線程重新轉(zhuǎn)入就緒狀態(tài)璧南。
死亡狀態(tài)(Dead):線程執(zhí)行完了或者因異常退出了run()方法,該線程結(jié)束生命周期师逸。
這5種狀態(tài)基本就是我們現(xiàn)在能用到和遇到的99%的功能了司倚。
看到這里,差不多基本就對線程有了很多的理解篓像,我基本也就理解了這些动知。。员辩。下面我們來看看線程的兩個常用方法:互斥和同步
互斥
啥是互斥:就是有個方法盒粮,里面有個變量 i = 0,每次運行屈暗,這個變量 i 都會+1拆讯。但是現(xiàn)在有2個線程同時訪問了這個方法脂男,那么就有可能第一個線程算出來了 i+1=1;還沒有保存呢种呐,第二個線程進來了宰翅,獲取到的i還是0,而不是第一個線程的結(jié)果爽室,第二個線程也做了i+1的操作=1汁讼;這個時候第一個線程做的運算就沒有被計算進去,本來應該是2的阔墩,結(jié)果返回了1嘿架。
這時候就要用到?synchronized 線程鎖的概念
臨界段:多線程互斥使用共享資源的程序段,在操作系統(tǒng)中稱為臨界段啸箫。臨界段是一種加鎖的機制耸彪,與多線程共享資源有關。
臨界段的作用是在任何時刻一個共享資源只能供一個線程使用忘苛。當資源未被占用蝉娜,線程可以進入處理這個資源的臨界段,從而得到該資源的使用權扎唾;當線程執(zhí)行完畢召川,便退出臨界段。如果一個線程已進入某個共享資源胸遇,并且還沒有使用結(jié)束荧呐,其他線程必須等待。
在JAVA中使用關鍵字synchronized定義臨界段纸镊,能對共享對象進行上鎖操作倍阐。
synchronized 線程鎖是線程安全的保障。
互斥就是大家都去操作一個東西薄腻,互不干擾收捣,但是這個數(shù)據(jù)要保證每個人處理的過程都有效的保存,還有一種情況就是庵楷,大家都要去操作一個東西罢艾,A要等B操作完才能操作,這種怎么辦呢尽纽,那么就有了一個東西咐蚯,叫做:
同步
多線程之間除了有互斥情況外,還有線程同步弄贿。當線程A使用某個對象春锋,而此對象又需要線程B修改后才能符合本線程的需要,此時線程A就要等待線程B完成修改工作差凹。這種線程相互等待稱為線程的同步期奔。
為實現(xiàn)同步侧馅,JAVA語言提供了wait()、notify()和notifyAll()三個方法供線程在臨界段中使用呐萌。
在臨界段中使用wait()方法馁痴,使執(zhí)行該方法的線程等待,并允許其他線程使用這個臨界段肺孤。wait()常用兩種格式:
wait()——讓線程一直處于等待隊列罗晕,知道被使用了notify()或notifyAll()方法喚醒。
wait(long timeout)——讓線程等待到被喚醒赠堵,或經(jīng)過指定時間后結(jié)束等待小渊。
當線程使用完臨界段后,用notify()方法通知由于想使用這個臨界段而處于等待狀態(tài)的線程結(jié)束等待茫叭。notify()方法只是通知第一個處于等待的線程酬屉。
如果某個線程在使用完臨界段方法后,其他早先等待的線程都可以結(jié)束等待杂靶,一起重新競爭CPU梆惯,則可以使用notifyAll()方法酱鸭。
現(xiàn)在的企業(yè)應用開始越來越多的使用多線程的開發(fā)吗垮,可能有的人不懂到底什么時候才要用多線程呢,那我們這里舉一些簡單的例子:批量上傳凹髓,批量發(fā)郵件烁登,異步的添加,活動中的秒殺等等蔚舀。
現(xiàn)在很多程序更多的會遇到? ?高并發(fā)饵沧!
那么多線程也是解決高并發(fā)的一個有效手段,但不是唯一的方式赌躺!至于高并發(fā)狼牺,在后面介紹springboot的時候,我們在來看看高并發(fā)的定義和實際問題礼患。
多線程(1)就到這里結(jié)束了是钥,下一節(jié),我們用真實場景缅叠,來看一下多線程在代碼中的應用和實現(xiàn)悄泥!