這篇文章主要講解了“多線程編程的三種實(shí)現(xiàn)方式是什么”,文中的講解內(nèi)容簡(jiǎn)單清晰,易于學(xué)習(xí)與理解,下面請(qǐng)大家跟著小編的思路慢慢深入,一起來(lái)研究和學(xué)習(xí)“多線程編程的三種實(shí)現(xiàn)方式是什么”吧!
在南靖等地區(qū),都構(gòu)建了全面的區(qū)域性戰(zhàn)略布局,加強(qiáng)發(fā)展的系統(tǒng)性、市場(chǎng)前瞻性、產(chǎn)品創(chuàng)新能力,以專(zhuān)注、極致的服務(wù)理念,為客戶提供網(wǎng)站設(shè)計(jì)、成都網(wǎng)站建設(shè) 網(wǎng)站設(shè)計(jì)制作按需規(guī)劃網(wǎng)站,公司網(wǎng)站建設(shè),企業(yè)網(wǎng)站建設(shè),成都品牌網(wǎng)站建設(shè),全網(wǎng)營(yíng)銷(xiāo)推廣,成都外貿(mào)網(wǎng)站制作,南靖網(wǎng)站建設(shè)費(fèi)用合理。
進(jìn)程:是程序的一次動(dòng)態(tài)執(zhí)行過(guò)程,它經(jīng)歷了從代碼加載、執(zhí)行到執(zhí)行完畢的一個(gè)完整過(guò)程,這個(gè)過(guò)程就是進(jìn)程產(chǎn)生、發(fā)展到最終消亡的過(guò)程;
多進(jìn)程:操作系統(tǒng)能同時(shí)運(yùn)行多個(gè)進(jìn)程(程序),由于CPU
具備分時(shí)機(jī)制,在每個(gè)進(jìn)程都能循環(huán)獲得自己的CPU時(shí)間片;由于CPU執(zhí)行的速度非???,使得所有的程序好像是在同時(shí)運(yùn)行一樣。
進(jìn)程是資源調(diào)度的基本單位,運(yùn)行一個(gè)可執(zhí)行程序會(huì)創(chuàng)建一個(gè)或多個(gè)線程,進(jìn)程就是運(yùn)行起來(lái)的可執(zhí)行程序;
線程是程序執(zhí)行的基本單位,是輕量級(jí)的進(jìn)程,每個(gè)進(jìn)程中都有唯一的主線程,且只能有一個(gè),主線程和進(jìn)程是相互依存的關(guān)系,主線程結(jié)束,進(jìn)程也會(huì)結(jié)束。
具體實(shí)例(word):
每次啟動(dòng)Word對(duì)于操作系統(tǒng)而言就相當(dāng)于啟動(dòng)了一個(gè)系統(tǒng)的進(jìn)程,而在這個(gè)進(jìn)程之上又有許多其他程序在運(yùn)行(拼寫(xiě)檢查等),那么對(duì)于這些程序就是一個(gè)個(gè)多線程。如果Word關(guān)閉了,則這些拼寫(xiě)檢查的線程也肯定會(huì)消失,但是如果拼寫(xiě)檢查的線程消失了,并不一定會(huì)讓W(xué)ord的進(jìn)程消失;
多插一句:如果打開(kāi)兩個(gè)word文檔,則表示當(dāng)前操作系統(tǒng)創(chuàng)建了兩個(gè)進(jìn)程。
實(shí)現(xiàn)多線程需要一個(gè)線程的主體類(lèi),這個(gè)類(lèi)可以繼承Thread
、實(shí)現(xiàn)Runnable
以及Callable
接口完成定義;
繼承結(jié)構(gòu)如下:
public class Thread extends Object implements Runnable
實(shí)現(xiàn)接口Runnable
,所以必須實(shí)現(xiàn)接口中的抽象方法:
Modifier and Type | Method | Description |
---|---|---|
void | run() | 當(dāng)一個(gè)實(shí)現(xiàn)接口Runnable的對(duì)象被用來(lái)創(chuàng)建線程時(shí),啟動(dòng)線程會(huì)導(dǎo)致對(duì)象的run方法在單獨(dú)執(zhí)行的線程中被調(diào)用。 |
void | start() | 使線程開(kāi)始執(zhí)行;Java虛擬機(jī)調(diào)用這個(gè)線程的run方法。 |
當(dāng)產(chǎn)生多個(gè)對(duì)象時(shí),這些對(duì)象就會(huì)并發(fā)的執(zhí)行run()方法中的代碼;
雖然多線程的執(zhí)行方法都在run()方法中定義,但是在實(shí)際進(jìn)行多線程啟動(dòng)時(shí)并不能直接調(diào)用此方法,由于多線程時(shí)需要并發(fā)執(zhí)行的,所以需要通過(guò)操作系統(tǒng)的資源調(diào)度才能執(zhí)行,這樣多線程的啟動(dòng)就必須利用Thread類(lèi)中的start()方法完成,調(diào)用此方法會(huì)間接的調(diào)用run()方法。
實(shí)例:
package Java從入門(mén)到項(xiàng)目實(shí)戰(zhàn).多線程編程.Java多線程實(shí)現(xiàn); class MyThread extends Thread{ //單繼承 private String title; public MyThread(String title){ this.title = title; } //覆寫(xiě)線程的run方法 @Override public void run() { for (int i = 0 ; i < 10; i++){ System.out.println(this.title+"運(yùn)行,i =" +i); } } } public class Main{ public static void main(String[] args){ new MyThread("線程A").start(); //實(shí)例化線程對(duì)象并啟動(dòng) new MyThread("線程B").start(); new MyThread("線程C").start(); //對(duì)照 /*沒(méi)有開(kāi)啟多線程*/ new MyThread("線程A").run(); new MyThread("線程B").run(); new MyThread("線程C").run(); } }
由效果圖可以看出,三個(gè)線程在交替執(zhí)行:
假如面試題:
為什么線程啟動(dòng)的時(shí)候必須調(diào)用start()方法而不是直接調(diào)用run()方法?
在本程序中,程序調(diào)用了Thread類(lèi)繼承而來(lái)的start()方法后,實(shí)際上他執(zhí)行的還是覆寫(xiě)后的run()方法,那為什么不直接調(diào)用run()?
簡(jiǎn)單的說(shuō)下:是因?yàn)槎嗑€程需要調(diào)用操作系統(tǒng)的資源,在start()下有一個(gè)關(guān)鍵的部分start0()方法,并且在start0()方法上使用了navite關(guān)鍵字定義;
public synchronized void start() { if (threadStatus != 0) throw new IllegalThreadStateException(); group.add(this); boolean started = false; try { start0(); started = true; } finally { try { if (!started) { group.threadStartFailed(this); } } catch (Throwable ignore) { } } } private native void start0(); //navite
什么是navite?
navite是指:Java本機(jī)接口(Java Native Interface)簡(jiǎn)稱(chēng):JNI;使用Java調(diào)用本機(jī)操作系統(tǒng)的函數(shù)功能完成一些特殊操作;
在Java中將start0()方法體交給JVM進(jìn)行實(shí)現(xiàn),所以這樣就會(huì)出現(xiàn)在windows或者在Linux中實(shí)現(xiàn)的start0()的是不同,不關(guān)系過(guò)程,只關(guān)心結(jié)果(是否調(diào)用了本機(jī)的操作系統(tǒng)的函數(shù));
start0()作用:交由JVM進(jìn)行匹配不同的操作系統(tǒng),實(shí)現(xiàn)start0()方法體,功能:實(shí)現(xiàn)本機(jī)函數(shù)的調(diào)用;
具體百度、Google吧。
出現(xiàn)的原因:為了解決Thread實(shí)現(xiàn)多線程出現(xiàn)的單繼承問(wèn)題;并且增加了函數(shù)式接口;
Modifier and Type | Method | Description |
---|---|---|
void | run() | 當(dāng)一個(gè)實(shí)現(xiàn)接口Runnable的對(duì)象被用來(lái)創(chuàng)建線程時(shí),啟動(dòng)線程會(huì)導(dǎo)致對(duì)象的run方法在單獨(dú)執(zhí)行的線程中被調(diào)用。 |
實(shí)現(xiàn)代碼:
class MyThread implements Runnable{ private String title; public MyThread(String title){ this.title = title; } @Override public void run() { //線程方法覆寫(xiě) for (int i = 0; i< 10;i++){ System.out.println(this.title+"運(yùn)行,i"+i); } } }
啟動(dòng)方式一:
Thread threadA = new Thread(new MyThread("線程A")); Thread threadB = new Thread(new MyThread("線程B")); Thread threadC = new Thread(new MyThread("線程C")); Thread threadD = new Thread(new MyThread("線程D")); Thread threadE = new Thread(new MyThread("線程E")); threadA.start(); threadB.start(); threadC.start(); threadD.start(); threadE.start();
啟動(dòng)方式二:
//通過(guò)Lambal表達(dá)式定義線程主體 for(int x = 0; x < 3;x++){ String title = "線程對(duì)象-"+x; //實(shí)際上Thread傳入的類(lèi)型是Runnable new Thread(()->{ //Lambda實(shí)現(xiàn)線程主體 for(int y = 0; y < 20; y++){ System.out.println(title+"運(yùn)行,y"+y); } }).start(); }
Thread與Runnable的聯(lián)系:
繼承結(jié)構(gòu):
public class Thread extends Object implements Runnable
在之前繼承Thread類(lèi)的時(shí)候?qū)嶋H上覆寫(xiě)的還是Runnable接口的run()方法。
實(shí)現(xiàn)并發(fā)訪問(wèn)資源:
package Java從入門(mén)到項(xiàng)目實(shí)戰(zhàn).多線程編程.Java多線程實(shí)現(xiàn); class MyThreadConcurrent implements Runnable { private int ticket = 5; @Override public void run() { for (int i = 0; i < 100; i++) { //同步操作--》從5-1票數(shù) /*synchronized(this){ if(this.ticket > 0){ System.out.println("賣(mài)票,ticket = "+this.ticket--); } }*/ //票數(shù)亂數(shù) if(this.ticket > 0){ System.out.println("賣(mài)票,ticket = "+this.ticket--); } } } } public class 并發(fā)資源訪問(wèn) { public static void main(String[] args) { MyThreadConcurrent thread = new MyThreadConcurrent(); new Thread(thread).start(); //第一個(gè)線程 new Thread(thread).start(); //第二個(gè)線程 new Thread(thread).start(); //第三個(gè)線程 } }
總結(jié)一句話:Thread有單繼承的局限性以及在有些情況下結(jié)構(gòu)的不合理性;所以后面多線程的實(shí)現(xiàn)使用的都是Runnable接口。
為什么要使用Callable接口來(lái)實(shí)現(xiàn)多線程?
因?yàn)槭褂肅allable接口實(shí)現(xiàn)彌補(bǔ)了Runnable實(shí)現(xiàn)多線程沒(méi)有返回值的問(wèn)題。
繼承結(jié)構(gòu)如下:
@FunctionalInterface public interface Callable{ public V call() throws Exception{ } }
定義的時(shí)候可以設(shè)置一個(gè)泛型,此泛型的類(lèi)型就是call()方法的返回的數(shù)據(jù)類(lèi)型,好處:可以避免向下轉(zhuǎn)型的安全隱患。
線程類(lèi)主體完成后,需要啟動(dòng)多線程的話還是需要通過(guò)Thread類(lèi)實(shí)現(xiàn)的,又因?yàn)槲覀兊腃allable接口與Thread沒(méi)有聯(lián)系,所以我們需要FutureTask類(lèi)實(shí)現(xiàn)兩者之間的聯(lián)系;如圖所示:
通過(guò)FutureTask類(lèi)繼承結(jié)構(gòu)可以發(fā)現(xiàn)它是Runnable接口的子類(lèi);
代碼實(shí)現(xiàn)如下:
package Java從入門(mén)到項(xiàng)目實(shí)戰(zhàn).多線程編程.Java多線程實(shí)現(xiàn); import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; import java.util.concurrent.FutureTask; class CallableThread implements Callable{ @Override public String call() throws Exception { for (int i = 0; i < 10; i++) { System.out.println("線程執(zhí)行 x = "+i); } return "xbhog"; } } public class Callable接口實(shí)現(xiàn)多線程 { public static void main(String[] args) throws ExecutionException, InterruptedException { //將Callable實(shí)例化包裝在FutureTask類(lèi)中,這樣就可以與Runnable接口關(guān)聯(lián) FutureTask task = new FutureTask (new CallableThread()); //線程啟動(dòng) new Thread(task).start(); //獲取call()的返回值 System.out.println("【線程返回?cái)?shù)據(jù)】:"+task.get()); } }
感謝各位的閱讀,以上就是“多線程編程的三種實(shí)現(xiàn)方式是什么”的內(nèi)容了,經(jīng)過(guò)本文的學(xué)習(xí)后,相信大家對(duì)多線程編程的三種實(shí)現(xiàn)方式是什么這一問(wèn)題有了更深刻的體會(huì),具體使用情況還需要大家實(shí)踐驗(yàn)證。這里是創(chuàng)新互聯(lián),小編將為大家推送更多相關(guān)知識(shí)點(diǎn)的文章,歡迎關(guān)注!