進(jìn)程:一個(gè)正在執(zhí)行的程序.每個(gè)進(jìn)程執(zhí)行都有一個(gè)執(zhí)行順序,該順序是一個(gè)執(zhí)行路徑,或叫一個(gè)控制單元.一個(gè)進(jìn)程至少有一個(gè)線程.
線程:就是進(jìn)程中的一個(gè)獨(dú)立的控制單元.線程控制這進(jìn)程的執(zhí)行.
多進(jìn)程的缺點(diǎn):進(jìn)程切換開(kāi)銷(xiāo)大;進(jìn)程間的通信很不方便。
多線程:指的是在單個(gè)程序中可以同時(shí)運(yùn)行多個(gè)不同的線程,執(zhí)行不同的任務(wù),線程切換的開(kāi)銷(xiāo)小。
線程的生命周期
Java做了很多工作,力求把這些細(xì)節(jié)抽象化。Java提供了一個(gè)名為T(mén)hread.State的枚舉類(lèi)型,囊括了操作系統(tǒng)看到的線程狀態(tài)。Thread.State中的值概述了一個(gè)線程的生命周期。
NEW
已經(jīng)創(chuàng)建線程,但還沒(méi)在線程對(duì)象上調(diào)用start()方法。所有線程一開(kāi)始都處于這個(gè)狀態(tài)。
RUNNABLE
線程正在運(yùn)行,或者當(dāng)操作系統(tǒng)調(diào)度線程時(shí)可以運(yùn)行。
Java實(shí)現(xiàn)內(nèi)存管理和并發(fā)編程的方式。
BLOCKED阻塞狀態(tài)
線程中止運(yùn)行,因?yàn)樗诘却@得一個(gè)鎖,以便進(jìn)入聲明為synchronized的方法或代碼塊。
具備運(yùn)行資格,沒(méi)有執(zhí)行權(quán)。
WAITING
線程中止運(yùn)行,因?yàn)樗{(diào)用了Object.wait()或Thread.join()方法。
在sleep和wait時(shí),既沒(méi)有運(yùn)行資格,有沒(méi)有執(zhí)行權(quán)。
TIMED_WAITING
線程中止運(yùn)行,因?yàn)樗{(diào)用了Thread.sleep()方法,或者調(diào)用了Object.wait()或Thread.join()方法,而且傳入了超時(shí)時(shí)間。
TERMINATED
線程執(zhí)行完畢。線程對(duì)象的run()方法正常退出,或者拋出了異常。
可見(jiàn)性和可變性
在Java中,其實(shí)一個(gè)進(jìn)程中的每個(gè)Java應(yīng)用線程都有自己的棧(和局部變量),不過(guò)這些線程共用同一個(gè)堆,因此可以輕易在線程之間共享對(duì)象,畢竟需要做的只是把引用從一個(gè)線程傳到另一個(gè)線程。
由此引出Java的一個(gè)一般設(shè)計(jì)原則——對(duì)象默認(rèn)可見(jiàn)。如果我有一個(gè)對(duì)象的引用,就可以復(fù)制一個(gè)副本,然后將其交給另一個(gè)線程,不受任何限制。Java中的引用其實(shí)就是類(lèi)型指針,指向內(nèi)存中的一個(gè)位置,而且所有線程都共用同一個(gè)地址空間,所以默認(rèn)可見(jiàn)符合自然規(guī)律。
除了默認(rèn)可見(jiàn)之外,Java還有一個(gè)特性對(duì)理解并發(fā)很重要——對(duì)象是可變的(mutable),對(duì)象的內(nèi)容(實(shí)例字段的值)一般都可以修改。使用final關(guān)鍵字可以把變量或引用聲明為常量,但這種字段不屬于對(duì)象的內(nèi)容。
這兩個(gè)特性(跨線程可見(jiàn)性和對(duì)象可變性)結(jié)合在一起,大大增加了理解Java并發(fā)編程的難度。
并發(fā)編程的安全性
如果我們想編寫(xiě)正確的多線程代碼,得讓程序滿足一個(gè)重要的條件,
即:在一個(gè)程序中,不管調(diào)用什么方法,也不管操作系統(tǒng)如何調(diào)度應(yīng)用線程,一個(gè)對(duì)象看到的任何其他對(duì)象都不處于非法或不一致的狀態(tài),這樣的程序才稱(chēng)得上是安全的多線程程序。
互斥(mutualexclusion)和狀態(tài)保護(hù)
只要修改或讀取對(duì)象的過(guò)程中,對(duì)象的狀態(tài)可能不一致,這段代碼就要受到保護(hù)。為了保護(hù)這種代碼,Java平臺(tái)只提供了一種機(jī)制:互斥。
Java為開(kāi)發(fā)者提供了synchronized關(guān)鍵字。這個(gè)關(guān)鍵字可以用在代碼塊或方法上,使用時(shí),Java平臺(tái)會(huì)限制訪問(wèn)代碼塊或方法中的代碼。
因?yàn)閟ynchronized關(guān)鍵字把代碼包圍起來(lái),所以很多開(kāi)發(fā)者認(rèn)為,Java的
并發(fā)和代碼有關(guān)。有些資料甚至把synchronized修飾的塊或方法中的代碼
稱(chēng)為臨界區(qū),還認(rèn)為臨界區(qū)是并發(fā)的關(guān)鍵所在。其實(shí)不然,稍后會(huì)看到,其
實(shí)我們要防范的是數(shù)據(jù)的不一致性。
Java平臺(tái)會(huì)為它創(chuàng)建的每個(gè)對(duì)象記錄一個(gè)特殊的標(biāo)記,這個(gè)標(biāo)記叫監(jiān)視器(monitor)。synchronized使用這些監(jiān)視器(或叫鎖)指明,隨后的代碼可以臨時(shí)把對(duì)象渲染成不一致的狀態(tài)。synchronized修飾的代碼塊或方法會(huì)發(fā)生一系列事件,詳述如下:
線程需要修改對(duì)象時(shí),會(huì)臨時(shí)把對(duì)象變成不一致?tīng)顟B(tài);
線程獲取監(jiān)視器,指明它需要臨時(shí)互斥存儲(chǔ)這個(gè)對(duì)象;
線程修改對(duì)象,修改完畢后對(duì)象處于一致的合法狀態(tài);
線程釋放監(jiān)視器。
同步是保護(hù)狀態(tài)的一種協(xié)助機(jī)制,因此非常脆弱。一個(gè)缺陷(需要使用
synchronized修飾的方法卻沒(méi)有使用)就可能為系統(tǒng)的整體安全性帶來(lái)災(zāi)難
性的后果。
之所以使用synchronized這個(gè)詞作為“需要臨時(shí)互斥存儲(chǔ)”的關(guān)鍵詞,除了說(shuō)明需要獲取監(jiān)視器之外,還表明進(jìn)入代碼塊時(shí),JVM會(huì)從主內(nèi)存中重新讀取對(duì)象的當(dāng)前狀態(tài)。類(lèi)似地,退出synchronized修飾的代碼塊或方法時(shí),JVM會(huì)刷新所有修改過(guò)的對(duì)象,把新?tīng)顟B(tài)存入主內(nèi)存。
volatile關(guān)鍵字
Java還提供了另一個(gè)關(guān)鍵字,用來(lái)并發(fā)訪問(wèn)數(shù)據(jù)——volatile。這個(gè)關(guān)鍵字指明,應(yīng)用代碼使用字段或變量前,必須重新從主內(nèi)存讀取值。同樣,修改使用volatile修飾的值后,在寫(xiě)入變量之后,必須存回主內(nèi)存。
volatile關(guān)鍵字的主要用途之一是在“關(guān)閉前一直運(yùn)行”模式中使用。編寫(xiě)多線程程序時(shí),如果外部用戶或系統(tǒng)需要向處理中的線程發(fā)出信號(hào),告訴線程在完成當(dāng)前作業(yè)后優(yōu)雅關(guān)閉線程,那么就要使用volatile。這個(gè)過(guò)程有時(shí)叫作“優(yōu)雅結(jié)束”模式。
以上就是天津卓眾教育java培訓(xùn)機(jī)構(gòu)的小編針對(duì)“Java基礎(chǔ)學(xué)習(xí):java多線程編程視頻”的內(nèi)容進(jìn)行的回答,希望對(duì)大家有所幫助,如有疑問(wèn),請(qǐng)?jiān)诰€咨詢,有專(zhuān)業(yè)老師隨時(shí)為你服務(wù)。