摘要:程序執(zhí)行時,至少會有一個線程在運行,這個運行的線程被稱為主線程。程序的終止是指除守護線程以外的線程全部終止。多線程程序由多個線程組成的程序稱為多線程程序。線程休眠期間可以被中斷,中斷將會拋出異常。
線程
我們在閱讀程序時,表面看來是在跟蹤程序的處理流程,實際上跟蹤的是線程的執(zhí)行。
單線程程序
在單線程程序中,在某個時間點執(zhí)行的處理只有一個。
Java 程序執(zhí)行時,至少會有一個線程在運行,這個運行的線程被稱為主線程(Main Thread)。
Java 程序在主線程運行的同時,后臺線程也在運行,例如:垃圾回收線程、GUI 相關(guān)線程等。
Java 程序的終止是指除守護線程(Daemon Thread)以外的線程全部終止。守護線程是執(zhí)行后臺作業(yè)的線程,例如垃圾回收線程。我們可以通過 setDaemon() 方法把線程設(shè)置為守護線程。
多線程程序
由多個線程組成的程序稱為多線程程序(Multithreaded Program)。多個線程運行時,各個線程的運行軌跡將會交織在一起,同一時間點執(zhí)行的處理有多個。
多線程應(yīng)用場景:
GUI 應(yīng)用程序:存在專門執(zhí)行 GUI 操作的線程(UI Thread)
耗時任務(wù):文件與網(wǎng)絡(luò)的 I/O 處理
網(wǎng)絡(luò)服務(wù)器同時處理多個客戶端請求場景
P.S. 使用 java.nio 包中的類,有時即便不使用線程,也可以執(zhí)行兼具性能和可擴展性的 I/O 處理。
并行(parallel)與并發(fā)(concurrent)的區(qū)別
程序運行存在順序、并行與并發(fā)模式。
順序(sequential)用于表示多個操作依次處理。
并行用于表示多個操作同時處理,取決于 CPU 的個數(shù)。
并發(fā)用于表示將一個操作分割成多個部分并且允許無序處理。
并發(fā)相對于順序和并行來說比較抽象。單個 CPU 并發(fā)處理即為順序執(zhí)行,多個 CPU 并發(fā)處理可以并行執(zhí)行。
如果是單個 CPU,即便多個線程同時運行,并發(fā)處理也只能順序執(zhí)行,在線程之間不斷切換。
并發(fā)處理包括:并發(fā)處理的順序執(zhí)行、并發(fā)處理的并行執(zhí)行。
線程和進程的區(qū)別
線程之間共享內(nèi)存
進程和線程之間最大的區(qū)別就是內(nèi)存是否共享。
通常,每個進程都擁有彼此獨立的內(nèi)存空間。一個進程不可以擅自讀取、寫入其他進程的內(nèi)存。正因為每個進程內(nèi)存空間獨立,無需擔(dān)心被其他進程破壞。
線程之間共享內(nèi)存,使得線程之間的通信實現(xiàn)起來更加自然、簡單。一個線程向?qū)嵗袑懭雰?nèi)容,其他線程就可以讀取該實例的內(nèi)容。當(dāng)有多個線程可以訪問同一個實例時,需要正確執(zhí)行互斥處理。
線程的上下文切換快
進程和線程之間的另一個區(qū)別就是上下文切換的繁重程度。
當(dāng)運行中的進程進行切換時,進程要暫時保存自身的當(dāng)前狀態(tài)(上下文信息)。而接著開始運行的進程需要恢復(fù)之前保存的自身的上下文信息。
當(dāng)運行中的線程進行切換時,與進程一樣,也會進行上下文切換。但由于線程管理的上下文信息比進程少,所以一般來說,線程的上下文切換要比進程快。
當(dāng)執(zhí)行緊密關(guān)聯(lián)的多項工作時,通常線程比進程更加適合。
多線程程序的優(yōu)點和成本
優(yōu)點:
充分利用硬件資源如多核 CPU、I/O 設(shè)備、網(wǎng)絡(luò)設(shè)備并行工作。
提高 GUI 應(yīng)用程序響應(yīng)性,UI Thread 專注界面繪制、用戶交互,額外開啟線程執(zhí)行后臺任務(wù)。
網(wǎng)絡(luò)應(yīng)用程序簡化建模,每個客戶端請求使用多帶帶的線程進行處理。
缺點(成本):
創(chuàng)建線程需要消耗系統(tǒng)資源和時間,準(zhǔn)備線程私有的程序計數(shù)器和棧。
線程調(diào)度和切換同樣需要成本,線程切換出去時需要保存上下文狀態(tài)信息,以便再次切換回來時能夠恢復(fù)之前的上下文狀態(tài)。
相對而言,若是存在耗時任務(wù)需要放入子線程中實際執(zhí)行,線程使用成本可以不計。
多線程編程的重要性
硬件條件滿足多線程并行執(zhí)行的條件之外,還需要程序邏輯能夠保證多線程正確地運行,考慮到線程之間的互斥處理和同步處理。
Thread 類 線程的創(chuàng)建與啟動創(chuàng)建與啟動線程的兩種方法:
利用 Thread 類的子類實例化,創(chuàng)建并啟動線程。
利用 Runnable 接口的實現(xiàn)類實例化,創(chuàng)建并啟動線程。
線程的創(chuàng)建與啟動步驟——方法一:
聲明 Thread 的子類(extends Thread),并重寫 run() 方法。
創(chuàng)建該類的實例
調(diào)用該實例的 start() 方法啟動線程
Thread 實例和線程本身不是同一個東西,創(chuàng)建 Thread 實例,線程并未啟動,直到 start() 方法調(diào)用,同樣就算線程終止了,實例也不會消失。但是一個 Thread 實例只能創(chuàng)建一個線程,一旦調(diào)用 start() 方法,不管線程是否正常/異常結(jié)束,都無法再次通過調(diào)用 start() 方法創(chuàng)建新的線程。并且重復(fù)調(diào)用 start() 方法會拋出 IllegalThreadStateException 異常。
Thread run( ) 方法 和 start() 方法:
run() 方法是可以重復(fù)調(diào)用的,但是不會啟動新的線程,于當(dāng)前線程中執(zhí)行。run() 方法放置于 Runnable 接口旨在封裝操作。
start() 方法主要執(zhí)行以下操作:啟動新的線程,并在其中調(diào)用 run() 方法。
線程的創(chuàng)建與啟動步驟——方法二:
聲明類并實現(xiàn) Runnable 接口(implements Runnable),要求必須實現(xiàn) run() 方法。
創(chuàng)建該類的實例
以該實例作為參數(shù)創(chuàng)建 Thread 類的實例 Thread(Runnable target)
調(diào)用 Thread 類的實例的 start() 方法啟動線程
不管是利用 Thread 類的子類實例化的方法(1),還是利用 Runnable 接口的實現(xiàn)類實例化的方法(2),啟動新線程的方法最終都是 Thread 類的 start() 方法。
Java 中存在單繼承限制,如果類已經(jīng)有一個父類,則不能再繼承 Thread 類,這時可以通過實現(xiàn) Runnable 接口來實現(xiàn)創(chuàng)建并啟動新線程。
Thread 類本身實現(xiàn)了 Runnable 接口,并將 run() 方法的重寫(override)交由子類來完成。
線程的屬性id 和 name
通過 Thread(String name) 構(gòu)造方法或 void setName(String name),給 Thread 設(shè)置一個友好的名字,可以方便調(diào)試。
優(yōu)先級
Java 語言中,線程的優(yōu)先級從1到10,默認為5。但因程序?qū)嶋H運行的操作系統(tǒng)不同,優(yōu)先級會被映射到操作系統(tǒng)中的取值,因此 Java 語言中的優(yōu)先級主要是一種建議,多線程編程時不要過于依賴優(yōu)先級。
線程的狀態(tài)Thread.State 枚舉類型(Enum)包括:
NEW
線程實例化后,尚未調(diào)用 start() 方法啟動。
RUNNABLE
可運行狀態(tài),正在運行或準(zhǔn)備運行。
BLOCKED
阻塞狀態(tài),等待其他線程釋放實例的鎖。
WAITING
等待狀態(tài),無限等待其他線程執(zhí)行特定操作。
TIMED_WAITING
時限等待狀態(tài),等待其他線程執(zhí)行指定的有限時間的操作。
TERMINATED
線程運行結(jié)束
Thread 類的靜態(tài)方法 currentThread() 返回當(dāng)前正在執(zhí)行的線程對象。
sleep() 方法Thread 類的靜態(tài)方法 sleep() 能夠暫停(休眠)當(dāng)前線程(執(zhí)行該語句的線程)運行,放棄占用 CPU。線程休眠期間可以被中斷,中斷將會拋出 InterruptedException 異常。sleep() 方法的參數(shù)以毫秒作為單位,不過通常情況下,JVM 無法精確控制時間。
sleep() 方法調(diào)用需要放在 try catch 語句中,可能拋出 InterruptedException 異常。InterruptedException 異常能夠取消線程處理,可以使用 interrupt() 方法在中途喚醒休眠狀態(tài)的線程。
多線程示例程序中經(jīng)常使用 sleep() 方法模擬耗時任務(wù)處理過程。
yield() 方法Thread 類的靜態(tài)方法 yield() 能夠暫停當(dāng)前線程(執(zhí)行該語句的線程)運行,讓出 CPU 給其他線程優(yōu)先執(zhí)行。如果沒有正在等待的線程,或是線程的優(yōu)先級不高,當(dāng)前線程可能繼續(xù)運行,即 yield() 方法無法確保暫停當(dāng)前線程。yield() 方法類似 sleep() 方法,但是不能指定暫停時間。
join() 方法Thread 類的實例方法,持有 Thread 實例的線程,將會等待調(diào)用 join() 方法的 Thread 實例代表的線程結(jié)束。等待期間可以被中斷,中斷將會拋出 InterruptedException 異常。
示例程序:
public class HelloThread extends Thread { @Override public void run() { System.out.println("hello"); } } public class Main { public static void main(String[] args) throws InterruptedException { Thread thread = new HelloThread(); thread.start(); thread.join(); } }
main() 方法所在的主線程將會等待 HelloThread 子線程執(zhí)行 run() 方法結(jié)束后再執(zhí)行,退出程序。
并發(fā)編程特性原子性
可見性
有序性
原子性操作問題原子性概念來源于數(shù)據(jù)庫系統(tǒng),一個事務(wù)(Transaction)中的所有操作,要么全部完成,要么全部不完成,不會結(jié)束在中間某個環(huán)節(jié)。事務(wù)在執(zhí)行過程中發(fā)生錯誤,會被恢復(fù)(Rollback)到事務(wù)開始前的狀態(tài),就像這個事務(wù)從來沒有執(zhí)行過一樣。
并發(fā)編程的原子性指對于共享變量的操作是不可分的,Java 基本類型除 long、double 外的賦值操作是原子操作。
非原子操作例如:
counter++;
讀取 counter 的當(dāng)前值
在當(dāng)前值基礎(chǔ)上加1
將新值重新賦值給 counter
Java 語言的解決方式:
使用 synchronized 關(guān)鍵字
使用 java.util.concurrent.atomic 包
內(nèi)存可見性問題計算機結(jié)構(gòu)中,CPU 負責(zé)執(zhí)行指令,內(nèi)存負責(zé)讀寫數(shù)據(jù)。CPU 執(zhí)行速度遠超內(nèi)存讀寫速度,緩解兩者速度不一致引入了高速緩存。 預(yù)先拷貝內(nèi)存數(shù)據(jù)的副本到緩存中,便于 CPU 直接快速使用。
因此計算機中除內(nèi)存之外,數(shù)據(jù)還有可能保存在 CPU 寄存器和各級緩存當(dāng)中。這樣一來,當(dāng)訪問一個變量時,可能優(yōu)先從緩存中獲取,而非內(nèi)存;當(dāng)修改一個變量時,可能先將修改寫到緩存中,稍后才會同步更新到內(nèi)存中。
對于單線程程序來說沒有太大問題,但是多線程程序并行執(zhí)行時,內(nèi)存中的數(shù)據(jù)將會不一致,最新修改可能尚未同步到內(nèi)存中。需要提供一種機制保證多線程對應(yīng)的多核 CPU 緩存中的共享變量的副本彼此一致——緩存一致性協(xié)議。
Java 語言的解決方式:
使用 volatile 關(guān)鍵字
使用 synchronized 關(guān)鍵字
如果只是解決內(nèi)存可見性問題,使用 synchronized 關(guān)鍵字成本較高,考慮使用 volatile 關(guān)鍵字更輕量級的方式。
指令重排序問題有序性:即程序執(zhí)行的順序嚴(yán)格按照代碼的先后順序執(zhí)行。
Java 允許編譯器和處理器為了提高效率對指令進行重排序,重排序過程不會影響到單線程程序的執(zhí)行,卻會可能影響到多線程程序并發(fā)執(zhí)行時候的正確性。
volatile 關(guān)鍵字細節(jié)
Java 使用 volatile 關(guān)鍵字修飾變量,保證可見性、有序性。
保證變量的值一旦被修改后立即更新寫入內(nèi)存,同時默認從內(nèi)存讀取變量的值。(可見性)
禁止指令重排序(有序性)
但是 volatile 關(guān)鍵字無法保證對變量操作是原子性的。
線程的互斥處理(synchronized 關(guān)鍵字細節(jié))每個線程擁有獨立的程序計數(shù)器(指令執(zhí)行行號)、棧(方法參數(shù)、局部變量等信息),多個線程共享堆(對象),這些區(qū)域?qū)?yīng) JVM 內(nèi)存模型。當(dāng)多個線程操作堆區(qū)的對象時候,可能出現(xiàn)多線程共享內(nèi)存的問題。
競態(tài)條件銀行取款問題
if(可用余額大于等于取款金額) {可用余額減去取款金額}
多個線程同時操作時,余額確認(可用余額大于等于取款金額)和取款(可用余額減去取款金額)兩個操作可能穿插執(zhí)行,無法保證線程之間執(zhí)行順序。
線程 A | 線程 B |
---|---|
可用余額(1000)大于等于取款金額(1000)?是的 | 切換執(zhí)行線程 B |
線程 A 處于等待狀態(tài) | 可用余額(1000)大于等于取款金額(1000)?是的 |
線程 A 處于等待狀態(tài) | 可用余額減去取款金額(1000-1000 = 0) |
切換執(zhí)行線程 A | 線程 B 結(jié)束 |
可用余額減去取款金額(0 - 1000 = -1000) | 線程 B 結(jié)束 |
當(dāng)有多個線程同時操作同一個對象時,可能出現(xiàn)競態(tài)條件(race condition),無法預(yù)期最終執(zhí)行結(jié)果,與執(zhí)行操作的時序有關(guān),需要“交通管制”——線程的互斥處理。
Java 使用 synchronized 關(guān)鍵字執(zhí)行線程的互斥處理。synchronized 關(guān)鍵字可以修飾類的實例方法、靜態(tài)方法和代碼塊。
synchronized 關(guān)鍵字保護的是對象而非方法、代碼塊,使用鎖來執(zhí)行線程的互斥處理。
synchronized 修飾靜態(tài)方法和實例方法時保護的是不同的對象:
synchronized 修飾實例方法是使用該類的實例對象 this。
synchronized 修飾靜態(tài)方法是使用該類的類對象 class。
每個對象擁有一個獨立的鎖,同一對象內(nèi)的所有 synchronized 方法共用。
基于 synchronized 關(guān)鍵字保護的是對象原則,有如下推論:
一個實例中的 synchronized 方法每次只能由一個線程運行,而非 synchronized 方法則可以同時由多線程運行。
一個實例中的多個 synchronized 方法同樣無法多線程運行。
不同實例中的 synchronized 方法可以同時由多線程運行。
synchronized 修飾的靜態(tài)方法(this 對象)和實例方法(class 對象)之間,可以同時被多線程執(zhí)行。
synchronized 方法具有可重入性,即獲取鎖后可以在一個 synchronized 方法,調(diào)用其他需要同樣鎖的 synchronized 方法。
一般在保護實例變量時,將所有訪問該變量的方法設(shè)置為 synchronized 同步方法。
如果只是想讓方法中的某一部分由一個線程運行,而非整個方法,則可使用 synchronized 代碼塊,精確控制互斥處理的執(zhí)行范圍。
嘗試獲取對象鎖,如果獲取到鎖進入2,未獲取到鎖則加入鎖的等待隊列進入阻塞狀態(tài)等待被喚醒。
執(zhí)行 synchronized 方法
釋放對象鎖,如果等待隊列存在線程正在等待獲取鎖,將其喚醒,當(dāng)有多個線程處于等待隊列,無法明確喚醒某一個,由多個線程競爭獲取。
死鎖死鎖是指兩個或兩個以上的進程(線程)在執(zhí)行過程中,因爭奪資源而造成的一種互相等待的現(xiàn)象,若無外力作用,它們都將無法推進下去。
死鎖產(chǎn)生的四個必要條件
互斥條件:指進程對所分配到的資源進行排它性使用,即在一段時間內(nèi)某資源只由一個進程占用。如果此時還有其它進程請求資源,則請求者只能等待,直至占有資源的進程用畢釋放。
請求和保持條件:指進程已經(jīng)保持至少一個資源,但又提出了新的資源請求,而該資源已被其它進程占有,此時請求進程阻塞,但又對自己已獲得的其它資源保持不放。
不剝奪條件:指進程已獲得的資源,在未使用完之前,不能被剝奪,只能在使用完時由自己釋放。
循環(huán)等待條件:指在發(fā)生死鎖時,必然存在一個進程——資源的環(huán)形鏈,即進程集合 {P0,P1,P2,···,Pn} 中的 P0 正在等待一個 P1 占用的資源;P1 正在等待 P2 占用的資源,……,Pn 正在等待已被 P0 占用的資源。
產(chǎn)生死鎖必須同時滿足上述四個條件,只要其中任一條件不成立,死鎖可避免。
應(yīng)該盡量避免在持有一個鎖的同時,申請另一個鎖。如果確實需要多個鎖,應(yīng)該按照相同的順序獲取鎖。
線程的協(xié)作(wait()、notify() 方法細節(jié))多線程之間除了在競爭中做互斥處理,還需要相互協(xié)作。協(xié)作的前提是清楚共享的條件變量。
wait()、notify()、notifyAll() 都是 Object 類的實例方法,而不是 Thread 類中的方法。這三個方法與其說是針對線程的操作,倒不如說是針對實例的條件等待隊列的操作。
操作 obj 條件等待隊列中的線程(喚醒、等待):
obj.wait() 將當(dāng)前線程放入 obj 的條件等待隊列。
obj.notify() 從 obj 的條件等待隊列喚醒一個線程。
obj.notifyAll() 喚醒 obj 條件等待隊列中的所有線程。
wait() 等待方法每個對象擁有一個鎖和鎖的等待隊列,另外還有一個表示條件的等待隊列,用于線程間的協(xié)作。調(diào)用 wait() 方法會將當(dāng)前線程放入條件隊列等待,等待條件需要等待時間或者依靠其他線程改變(notify()/notifyAll() )。等待期間同樣可以被中斷,中斷將會拋出 InterruptedException 異常。
Object 類的 wait() 方法和 Thread 類的 sleep() 方法在控制線程上主要區(qū)別在于對象鎖是否釋放,從方法所屬類可以看出 Object 類的 wait() 方法包含對象鎖管理機制。
wait() 實例方法用于線程間通信協(xié)作
sleep() 靜態(tài)方法用于暫停當(dāng)前線程
兩者均會放棄占用 CPU
將當(dāng)前線程放入條件隊列等待,釋放對象鎖。
當(dāng)前線程進入 WAITING、TIMED_WAITING 狀態(tài)。
等待時間或者被其他線程喚醒(notify()/notifyAll() ),從條件隊列中移除等待線程。
喚醒的線程獲得對象鎖,進入 RUNNABLE 狀態(tài),從 wait() 方法返回,重新執(zhí)行等待條件檢查。
喚醒的線程無法獲得對象鎖,進入 BLOCKED 狀態(tài),加入對象鎖的等待隊列,繼續(xù)等待。
notify() 喚醒方法notify() 和 notifyAll() 方法的區(qū)別
notify() 方法會喚醒等待隊列中的一個線程。
notifyAll() 方法會喚醒等待隊列中所有線程。
通常使用 notifyAll() 方法,相比于 notify() 方法代碼更具健壯性,但是喚醒多個線程速度慢些。
注意:調(diào)用 notify() 方法之后,喚醒條件隊列中等待的線程,并將其移除隊列。被喚醒的線程并不會立即運行,因為執(zhí)行 notify() 方法的線程還持有著鎖,等待 notify() 方法所處的同步(synchronized)代碼塊執(zhí)行結(jié)束才釋放鎖。隨后等待的線程獲得鎖從 wait() 方法返回,重新執(zhí)行等待條件檢查。
總結(jié):
線程必須持有實例的鎖才能執(zhí)行上述方法(wait()、notify()、notifyAll())
wait()/notify() 方法只能在 synchronized 代碼塊內(nèi)被調(diào)用,如果調(diào)用 wait()/notify() 方法時,當(dāng)前線程沒有持有對象鎖,會拋出異常 java.lang.IllegalMonitorStateException。
生產(chǎn)者/消費者模式應(yīng)用生產(chǎn)者(Producer)生成數(shù)據(jù)的線程
消費者(Consumer)使用數(shù)據(jù)的線程
生產(chǎn)者線程和消費者線程通過共享隊列進行協(xié)作,
生產(chǎn)者/消費者模式在生產(chǎn)者和消費者之間加入了一個橋梁角色,該橋梁角色用于消除線程間處理速度的差異。
Channel 角色持有共享隊列 Data,對 Producer 角色和 Consumer 角色的訪問執(zhí)行互斥處理,并隱藏多線程實現(xiàn)。
線程的中斷線程正常結(jié)束于 run() 方法執(zhí)行完畢,但在實際應(yīng)用中多線程模式往往是死循環(huán),考慮到存在特殊情況需要取消/關(guān)閉線程。Java 使用中斷機制,通過協(xié)作方式傳遞信息,從而取消/關(guān)閉線程。
中斷的方法public static boolean interrupted() public boolean isInterrupted() public void interrupt()
interrupt() 和 isInterrupted() 是實例方法,通過線程對象調(diào)用。
interrupted() 是靜態(tài)方法,由當(dāng)前線程 Thread.currentThread() 實際執(zhí)行。
線程存在 interrupted 中斷狀態(tài)標(biāo)記,用于判斷線程是否中斷。
isInterrupted() 實例方法返回對應(yīng)線程的中斷狀態(tài)。
interrupted() 靜態(tài)方法返回當(dāng)前線程的中斷狀態(tài),存在副作用清空中斷狀態(tài)。
不同線程狀態(tài)的中斷反應(yīng)
NEW、TERMINATED
調(diào)用 interrupt() 方法不起任何作用
RUNNABLE
調(diào)用 interrupt() 方法,線程正在運行,且與 I/O 操作無關(guān),設(shè)置線程中斷狀態(tài)標(biāo)記而已。如果線程等待 I/O 操作,則會進行特殊處理。
BLOCKED
調(diào)用 interrupt() 方法無法中斷正在 BLOCKED 狀態(tài)的線程
WAITING、TIMED_WAITING
調(diào)用 interrupt() 方法設(shè)置線程中斷狀態(tài)標(biāo)記,拋出 InterruptedException 異常。這是一個受檢異常,線程必須進行處理。
中斷的使用
對于提供線程服務(wù)的模塊,應(yīng)該封裝取消/關(guān)閉線程方法對外提供接口,而不是交由調(diào)用者自行調(diào)用 interrupt() 方法。
線程狀態(tài)轉(zhuǎn)換綜合圖解結(jié)合線程的方法(Thread 類 + Object 類)來看線程的狀態(tài)轉(zhuǎn)換:
注:
Thread t = new Thread(); Thread 類調(diào)用靜態(tài)方法,t 對象調(diào)用實例方法。
Object o = new Object(); Object 類調(diào)用靜態(tài)方法,o 對象調(diào)用實例方法。
Running 表示運行中狀態(tài),并非 Thread.State 枚舉類型。
附錄 Runnable 接口和 Callable 接口Runnable 接口提供的 run() 方法返回值為 void
Callable 接口提供的 call() 方法返回值為泛型
Callable 接口常用與配合 Future、FutureTask 類獲取異步執(zhí)行結(jié)果。
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://www.ezyhdfw.cn/yun/71909.html
摘要:線程可以被稱為輕量級進程。一個守護線程是在后臺執(zhí)行并且不會阻止終止的線程。其他的線程狀態(tài)還有,和。上下文切換是多任務(wù)操作系統(tǒng)和多線程環(huán)境的基本特征。在的線程中并沒有可供任何對象使用的鎖和同步器。 原文:Java Multi-Threading and Concurrency Interview Questions with Answers 翻譯:并發(fā)編程網(wǎng) - 鄭旭東 校對:方騰飛 多...
摘要:多線程和并發(fā)問題是技術(shù)面試中面試官比較喜歡問的問題之一。線程可以被稱為輕量級進程。一個守護線程是在后臺執(zhí)行并且不會阻止終止的線程。其他的線程狀態(tài)還有,和。上下文切換是多任務(wù)操作系統(tǒng)和多線程環(huán)境的基本特征。 多線程和并發(fā)問題是 Java 技術(shù)面試中面試官比較喜歡問的問題之一。在這里,從面試的角度列出了大部分重要的問題,但是你仍然應(yīng)該牢固的掌握Java多線程基礎(chǔ)知識來對應(yīng)日后碰到的問題。(...
摘要:并發(fā)編程實戰(zhàn)水平很高,然而并不是本好書。一是多線程的控制,二是并發(fā)同步的管理。最后,使用和來關(guān)閉線程池,停止其中的線程。當(dāng)線程調(diào)用或等阻塞時,對這個線程調(diào)用會使線程醒來,并受到,且線程的中斷標(biāo)記被設(shè)置。 《Java并發(fā)編程實戰(zhàn)》水平很高,然而并不是本好書。組織混亂、長篇大論、難以消化,中文翻譯也較死板。這里是一篇批評此書的帖子,很是貼切。俗話說:看到有這么多人罵你,我就放心了。 然而知...
摘要:此對象在線程受阻塞時被記錄,以允許監(jiān)視工具和診斷工具確定線程受阻塞的原因。阻塞當(dāng)前線程,最長不超過納秒,返回條件在的基礎(chǔ)上增加了超時返回。喚醒線程喚醒處于阻塞狀態(tài)的線程。 LockSupport 用法簡介 LockSupport 和 CAS 是Java并發(fā)包中很多并發(fā)工具控制機制的基礎(chǔ),它們底層其實都是依賴Unsafe實現(xiàn)。 LockSupport是用來創(chuàng)建鎖和其他同步類的基本線程阻塞...
摘要:線程線程,是程序執(zhí)行流的最小單元。由于線程之間的相互制約,致使線程在運行中呈現(xiàn)出間斷性。線程的狀態(tài)機線程也有就緒阻塞和運行三種基本狀態(tài)。在單個程序中同時運行多個線程完成不同的工作,稱為多線程。可以視為不同線程競爭一把鎖。 進程線程協(xié)程 進程 進程是一個實體。每一個進程都有它自己的地址空間, 文本區(qū)域(text region) 數(shù)據(jù)區(qū)域(data region) 堆棧(stack re...
閱讀 2854·2021-11-02 14:42
閱讀 3224·2021-10-08 10:04
閱讀 1250·2019-08-30 15:55
閱讀 1086·2019-08-30 15:54
閱讀 2380·2019-08-30 15:43
閱讀 1739·2019-08-29 15:18
閱讀 927·2019-08-29 11:11
閱讀 2429·2019-08-26 13:52