java中怎么實(shí)現(xiàn)多線程 ,針對(duì)這個(gè)問題,這篇文章詳細(xì)介紹了相對(duì)應(yīng)的分析和解答,希望可以幫助更多想解決這個(gè)問題的小伙伴找到更簡(jiǎn)單易行的方法。
公司主營(yíng)業(yè)務(wù):成都做網(wǎng)站、網(wǎng)站制作、移動(dòng)網(wǎng)站開發(fā)等業(yè)務(wù)。幫助企業(yè)客戶真正實(shí)現(xiàn)互聯(lián)網(wǎng)宣傳,提高企業(yè)的競(jìng)爭(zhēng)能力。創(chuàng)新互聯(lián)是一支青春激揚(yáng)、勤奮敬業(yè)、活力青春激揚(yáng)、勤奮敬業(yè)、活力澎湃、和諧高效的團(tuán)隊(duì)。公司秉承以“開放、自由、嚴(yán)謹(jǐn)、自律”為核心的企業(yè)文化,感謝他們對(duì)我們的高要求,感謝他們從不同領(lǐng)域給我們帶來的挑戰(zhàn),讓我們激情的團(tuán)隊(duì)有機(jī)會(huì)用頭腦與智慧不斷的給客戶帶來驚喜。創(chuàng)新互聯(lián)推出簡(jiǎn)陽免費(fèi)做網(wǎng)站回饋大家。
理解多線程先要理解線程,理解線程先要理解進(jìn)程。
一個(gè)正在執(zhí)行的程序。
每個(gè)進(jìn)程的執(zhí)行都有一個(gè)執(zhí)行的順序,順序是一個(gè)執(zhí)行路徑,也叫一個(gè)控制單元。
進(jìn)程中獨(dú)立的控制單元稱為線程。
線程控制進(jìn)程的執(zhí)行。
進(jìn)程中只要有一個(gè)線程在執(zhí)行,進(jìn)程就不會(huì)結(jié)束。
一個(gè)進(jìn)程中至少存在一個(gè)線程。
Java 虛擬機(jī)啟動(dòng)時(shí),會(huì)有一個(gè) java.exe 的執(zhí)行程序,也就是一個(gè)進(jìn)程。
這個(gè)進(jìn)程中至少存在一個(gè)線程負(fù)責(zé) java 程序的執(zhí)行,這個(gè)線程的運(yùn)行代碼存在 main 方法中,這個(gè)線程稱之為主線程。
JVM 啟動(dòng)時(shí)除了執(zhí)行一個(gè)主線程,還會(huì)啟動(dòng)負(fù)責(zé)垃圾回收機(jī)制的線程。
在一個(gè)進(jìn)程中有多個(gè)線程執(zhí)行的方式,稱為多線程。
多線程能讓程序產(chǎn)生同時(shí)運(yùn)行的效果,可以提高程序執(zhí)行的效率。
java.exe 進(jìn)程執(zhí)行主程序時(shí),如果程序的代碼非常多,在堆內(nèi)存中會(huì)產(chǎn)生很多對(duì)象,而對(duì)象調(diào)用完后就會(huì)變成垃圾。如果垃圾過多的話,可能會(huì)導(dǎo)致堆內(nèi)存出現(xiàn)內(nèi)存不足的現(xiàn)象,影響程序的運(yùn)行。這種情況下,如果只有一個(gè)線程在運(yùn)行處理的話,程序執(zhí)行的效率非常低;如果有多個(gè)線程在幫助處理的話,程序執(zhí)行的效率將大大的提高。
例如:垃圾回收機(jī)制的線程在幫助進(jìn)行垃圾回收的話,那堆內(nèi)存空間的釋放將快很多。
例如:
PC 上有很多程序“同時(shí)”進(jìn)行,看起來好像是 CPU “同時(shí)”處理所有程序似的,其實(shí)在同一時(shí)刻,單核的 CPU 只能運(yùn)行一個(gè)程序,看起來“同時(shí)”運(yùn)行的效果,實(shí)際上只是 CPU 在多個(gè)線程之間做快速切換的動(dòng)作而已。
CPU 執(zhí)行哪個(gè)程序,或者說是哪個(gè)程序搶到了 CPU 的執(zhí)行權(quán),哪個(gè)程序就執(zhí)行,CPU 不會(huì)只執(zhí)行一個(gè)線程,執(zhí)行完一個(gè)后,會(huì)執(zhí)行另一個(gè),或者說是另一個(gè)線程搶走了 CPU 的執(zhí)行權(quán)。至于如何執(zhí)行是由 CPU 所決定。
CPU 執(zhí)行哪個(gè)程序,是毫無規(guī)律的,這是多線程的特性:隨機(jī)性。
創(chuàng)建線程的方式:繼承和實(shí)現(xiàn)。
Java 中已經(jīng)提供了對(duì)線程描述的類 —— Thread。繼承 Thread 類,重寫(覆蓋)run 方法,創(chuàng)建線程。
步驟:
啟動(dòng)線程,調(diào)用 run 方法。
注:如果對(duì)象直接調(diào)用 run 方法,那么就只有一個(gè)線程在執(zhí)行,自定義的線程并沒有啟動(dòng)。
相當(dāng)于創(chuàng)建線程。
自定義代碼存儲(chǔ)在 run 方法中,讓線程執(zhí)行。
定義類繼承 Thread;
重寫(覆蓋)Thread 中的 run 方法;
創(chuàng)建自定義類的實(shí)例對(duì)象;
實(shí)例對(duì)象調(diào)用線程的 start 方法。
重寫(覆蓋)run 方法的原因:Thread 類用于描述線程,類中定義了一個(gè)功能,用于存儲(chǔ)線程要執(zhí)行的代碼,存儲(chǔ)這個(gè)功能的就是 run 方法??偠灾?,Thread 中的 run 方法用于存儲(chǔ)線程要執(zhí)行的代碼。
例如:
結(jié)果如下
注:線程是隨機(jī)、交替執(zhí)行的,每次運(yùn)行的結(jié)果都不同
使用繼承 Thread 創(chuàng)建線程的方式有弊端,就是如果類繼承了其它的父類,就無法使用 Thread 來創(chuàng)建線程,于是便有了通過實(shí)現(xiàn) Runnable 接口來創(chuàng)建線程。實(shí)現(xiàn) Runnable 接口,重寫(覆蓋)run 方法,創(chuàng)建線程。
步驟:
start 方法會(huì)自動(dòng)調(diào)用 Runnable 子類的 run 方法。
將 Runnable 的子類對(duì)象傳遞給 Thread 的構(gòu)造函數(shù)的原因:
自定義的 run 方法所屬的對(duì)象是 Runnable 的子類對(duì)象,要讓線程去指定對(duì)象的 run 方法,就必須明確 run 方法所屬的對(duì)象。
自定義代碼存儲(chǔ)在 run 方法中,讓線程執(zhí)行。
定義類實(shí)現(xiàn) Runnable;
重寫(覆蓋)Runnable 中的 run 方法;
通過 Thread 類創(chuàng)建線程對(duì)象。
將 Runnable 的子類對(duì)象作為實(shí)際參數(shù)傳遞給 Thread 的構(gòu)造函數(shù);
調(diào)用 Thread 中的 start 方法啟動(dòng)線程。
好處:避免了單繼承的局限性。(定義線程時(shí),建議優(yōu)先使用)
例如:
結(jié)果如下:
注:線程是隨機(jī)、交替執(zhí)行的,每次運(yùn)行的結(jié)果都不同。
繼承:線程代碼存儲(chǔ)在 Thread 子類的 run 方法中。
實(shí)現(xiàn):線程代碼存儲(chǔ)在 Runnable 子類的 run 方法中。
被創(chuàng)建:等待啟動(dòng),調(diào)用 start 啟動(dòng)。
運(yùn)行狀態(tài):具有執(zhí)行資格和執(zhí)行權(quán)。
臨時(shí)狀態(tài)(阻塞):具有執(zhí)行資格,但沒有執(zhí)行權(quán)。
凍結(jié)狀態(tài):遇到 sleep(time) 方法和 wait() 方法時(shí),失去執(zhí)行資格和執(zhí)行權(quán);sleep 方法的時(shí)間結(jié)束或調(diào)用 notify() 方法時(shí),獲得執(zhí)行資格,變?yōu)榕R時(shí)狀態(tài)(阻塞)。
消亡狀態(tài):調(diào)用 stop() 方法或 run 方法結(jié)束。
注:線程從創(chuàng)建狀態(tài)到了運(yùn)行狀態(tài)后,再次調(diào)用 start() 方法時(shí),已經(jīng)沒有任何意義,Java 運(yùn)行時(shí)會(huì)提示線程狀態(tài)異常。
當(dāng)多條語句操作同一個(gè)線程的共享數(shù)據(jù)時(shí),一個(gè)線程對(duì)多條語句只執(zhí)行了一部分,沒執(zhí)行完成時(shí),另外的線程參與執(zhí)行,會(huì)導(dǎo)致共享數(shù)據(jù)的錯(cuò)誤異常,也就是線程的安全問題。
總而言之:
線程的隨機(jī)性。
多個(gè)線程訪問出現(xiàn)延遲。
注:線程的安全問題在理想狀態(tài)下,一般不容易出現(xiàn),但是一旦出現(xiàn)線程的安全問題,將會(huì)對(duì)程序軟件造成非常大的影響。
對(duì)于線程的安全問題,在對(duì)多條操作共享數(shù)據(jù)的語句時(shí),只讓一個(gè)線程執(zhí)行完,再讓下個(gè)線程去執(zhí)行,每條線程在執(zhí)行的過程中,其它線程都不可以參與執(zhí)行。
Java 中提供了專業(yè)的解決辦法 —— synchronized(同步)。
解決的方式:同步代碼塊和同步函數(shù)。(均是使用關(guān)鍵字 synchronized 實(shí)現(xiàn))
格式:
synchronized(對(duì)象){ 需要被同步的代碼; }
同步之所以可以解決線程的安全問題,根本原因在于對(duì)象上,對(duì)象如果加了同步鎖,持有鎖的線程可以在同步中執(zhí)行,沒持有鎖的線程即使獲取 CPU 的執(zhí)行權(quán),也無法進(jìn)入去執(zhí)行,因?yàn)闆]有獲取到同步鎖。
例如:
同步代碼塊
前提:
必須有兩個(gè)或以上的線程;
必須是多個(gè)線程使用同一個(gè)鎖。
利與弊:
利:解決了多線程的安全問題。
弊:多個(gè)線程均需要判斷鎖,消耗資源,影響效率。
如何尋找多線程的安全問題?
明確共享數(shù)據(jù);
明確哪些代碼是多線程運(yùn)行的代碼;
明確多線程運(yùn)行的代碼中哪些語句是操作共享數(shù)據(jù)的。
同步函數(shù)被靜態(tài)所修飾后,使用的同步鎖不再是 this,因?yàn)殪o態(tài)函數(shù)中不可以定義 this,靜態(tài)進(jìn)入內(nèi)存時(shí),內(nèi)存中沒有本類對(duì)象,但一定存在類所對(duì)應(yīng)的字節(jié)碼文件對(duì)象。
例如:類名.class(對(duì)象的類型是 Class)
靜態(tài)函數(shù)所使用的同步鎖就是所在類的字節(jié)碼文件對(duì)象。
類名.class
例如:
同步中嵌套同步時(shí),有可能出現(xiàn)死鎖現(xiàn)象。
例如:
說明:程序卡死,無法繼續(xù)執(zhí)行。
多個(gè)線程操作同一個(gè)資源,但是操作的動(dòng)作不相同,就是線程間通信。
同步操作同一個(gè)資源
例如:
問題點(diǎn):
需要喚醒對(duì)方線程時(shí),如果只用 notify(),容易出現(xiàn)只喚醒本方線程的情況,會(huì)導(dǎo)致程序中所有線程都處于等待狀態(tài)。
wait():釋放 CPU 的執(zhí)行權(quán),釋放同步鎖。
sleep():釋放 CPU 的執(zhí)行權(quán),不釋放同步鎖。
例如:同一個(gè)鎖上 wait 的線程,只能被同一個(gè)鎖上的 notify 喚醒。
這些方法存在于同步中;
使用這些方法時(shí)必須要有標(biāo)識(shí)所屬的同步鎖;
鎖可以是任意的對(duì)象,任意對(duì)象調(diào)用的方法一定要定義在 Object 類中。
wait()、notify()、notifyAll() 用來操作線程的,為什么是定義在 Object 類中呢?
wait() 和 sleep() 有什么區(qū)別呢?
為什么要定義 notifyAll()?
JDK 5 及以上版本中提供了多線程同步鎖的升級(jí)解決方案
將 synchronized(同步)替換成 Lock,將 Object 類中的 wait()、notify()、notifyAll() 替換成 Condition 對(duì)象。
Condition 對(duì)象可通過 Lock(鎖)進(jìn)行獲取,并且支持多個(gè)相關(guān)的 Condition 對(duì)象。
例如:
說明:只要在主函數(shù)或者其它線程中,對(duì)標(biāo)記 flag 賦值 false,就可以讓 run() 方法結(jié)束,線程停止。
特殊情況:當(dāng)線程處于凍結(jié)狀態(tài)時(shí),無法讀取到 run() 方法中的代碼,線程就無法停止。
需要對(duì)線程的凍結(jié)狀態(tài)進(jìn)行清除,強(qiáng)制讓線程恢復(fù)運(yùn)行,Thread 類中提供了 interrupt();
例如:
某些代碼需要同時(shí)執(zhí)行時(shí),可用單獨(dú)的線程封裝,多線程運(yùn)行執(zhí)行。
例如
join();
當(dāng) A 線程執(zhí)行到了 B 線程的 join(); 方法時(shí),A 線程等待,B 線程執(zhí)行完后,A 線程才繼續(xù)執(zhí)行(此時(shí)的 B 線程與其它線程交替執(zhí)行)。
臨時(shí)加入線程去執(zhí)行:
setPriority();
MIN_PRIORITY:最低優(yōu)先級(jí) 1
MAX_PRIORITY:最高優(yōu)先級(jí) 10
NORM_PRIORITY:默認(rèn)優(yōu)先級(jí)
設(shè)置優(yōu)先級(jí):
yield();
可以暫停當(dāng)前線程,讓其它線程執(zhí)行。
關(guān)于java中怎么實(shí)現(xiàn)多線程 問題的解答就分享到這里了,希望以上內(nèi)容可以對(duì)大家有一定的幫助,如果你還有很多疑惑沒有解開,可以關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道了解更多相關(guān)知識(shí)。
網(wǎng)頁名稱:java中怎么實(shí)現(xiàn)多線程
鏈接URL:http://aaarwkj.com/article28/iggpjp.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供品牌網(wǎng)站制作、外貿(mào)網(wǎng)站建設(shè)、網(wǎng)站排名、網(wǎng)站改版、網(wǎng)站營(yíng)銷、網(wǎng)站制作
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來源: 創(chuàng)新互聯(lián)