這篇文章主要講解了“多線程編程的三種實(shí)現(xiàn)方式是什么”,文中的講解內(nèi)容簡單清晰,易于學(xué)習(xí)與理解,下面請大家跟著小編的思路慢慢深入,一起來研究和學(xué)習(xí)“多線程編程的三種實(shí)現(xiàn)方式是什么”吧!
在南靖等地區(qū),都構(gòu)建了全面的區(qū)域性戰(zhàn)略布局,加強(qiáng)發(fā)展的系統(tǒng)性、市場前瞻性、產(chǎn)品創(chuàng)新能力,以專注、極致的服務(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)營銷推廣,成都外貿(mào)網(wǎng)站制作,南靖網(wǎng)站建設(shè)費(fèi)用合理。
進(jìn)程:是程序的一次動(dòng)態(tài)執(zhí)行過程,它經(jīng)歷了從代碼加載、執(zhí)行到執(zhí)行完畢的一個(gè)完整過程,這個(gè)過程就是進(jìn)程產(chǎn)生、發(fā)展到最終消亡的過程;
多進(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)行起來的可執(zhí)行程序;
線程是程序執(zhí)行的基本單位,是輕量級(jí)的進(jìn)程,每個(gè)進(jìn)程中都有唯一的主線程,且只能有一個(gè),主線程和進(jìn)程是相互依存的關(guān)系,主線程結(jié)束,進(jìn)程也會(huì)結(jié)束。

具體實(shí)例(word):
每次啟動(dòng)Word對于操作系統(tǒng)而言就相當(dāng)于啟動(dòng)了一個(gè)系統(tǒng)的進(jìn)程,而在這個(gè)進(jìn)程之上又有許多其他程序在運(yùn)行(拼寫檢查等),那么對于這些程序就是一個(gè)個(gè)多線程。如果Word關(guān)閉了,則這些拼寫檢查的線程也肯定會(huì)消失,但是如果拼寫檢查的線程消失了,并不一定會(huì)讓W(xué)ord的進(jìn)程消失;
多插一句:如果打開兩個(gè)word文檔,則表示當(dāng)前操作系統(tǒng)創(chuàng)建了兩個(gè)進(jìn)程。
實(shí)現(xiàn)多線程需要一個(gè)線程的主體類,這個(gè)類可以繼承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的對象被用來創(chuàng)建線程時(shí),啟動(dòng)線程會(huì)導(dǎo)致對象的run方法在單獨(dú)執(zhí)行的線程中被調(diào)用。 |
void | start() | 使線程開始執(zhí)行;Java虛擬機(jī)調(diào)用這個(gè)線程的run方法。 |
當(dāng)產(chǎn)生多個(gè)對象時(shí),這些對象就會(huì)并發(fā)的執(zhí)行run()方法中的代碼;
雖然多線程的執(zhí)行方法都在run()方法中定義,但是在實(shí)際進(jìn)行多線程啟動(dòng)時(shí)并不能直接調(diào)用此方法,由于多線程時(shí)需要并發(fā)執(zhí)行的,所以需要通過操作系統(tǒng)的資源調(diào)度才能執(zhí)行,這樣多線程的啟動(dòng)就必須利用Thread類中的start()方法完成,調(diào)用此方法會(huì)間接的調(diào)用run()方法。
實(shí)例:
package Java從入門到項(xiàng)目實(shí)戰(zhàn).多線程編程.Java多線程實(shí)現(xiàn);
class MyThread extends Thread{ //單繼承
private String title;
public MyThread(String title){
this.title = title;
}
//覆寫線程的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í)例化線程對象并啟動(dòng)
new MyThread("線程B").start();
new MyThread("線程C").start();
//對照
/*沒有開啟多線程*/
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類繼承而來的start()方法后,實(shí)際上他執(zhí)行的還是覆寫后的run()方法,那為什么不直接調(diào)用run()?
簡單的說下:是因?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)簡稱: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ā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)的單繼承問題;并且增加了函數(shù)式接口;
| Modifier and Type | Method | Description |
|---|---|---|
void | run() | 當(dāng)一個(gè)實(shí)現(xiàn)接口Runnable的對象被用來創(chuàng)建線程時(shí),啟動(dòng)線程會(huì)導(dǎo)致對象的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() { //線程方法覆寫
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)方式二:
//通過Lambal表達(dá)式定義線程主體
for(int x = 0; x < 3;x++){
String title = "線程對象-"+x;
//實(shí)際上Thread傳入的類型是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類的時(shí)候?qū)嶋H上覆寫的還是Runnable接口的run()方法。
實(shí)現(xiàn)并發(fā)訪問資源:
package Java從入門到項(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("賣票,ticket = "+this.ticket--);
}
}*/
//票數(shù)亂數(shù)
if(this.ticket > 0){
System.out.println("賣票,ticket = "+this.ticket--);
}
}
}
}
public class 并發(fā)資源訪問 {
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接口來實(shí)現(xiàn)多線程?
因?yàn)槭褂肅allable接口實(shí)現(xiàn)彌補(bǔ)了Runnable實(shí)現(xiàn)多線程沒有返回值的問題。
繼承結(jié)構(gòu)如下:
@FunctionalInterface
public interface Callable<V>{
public V call() throws Exception{
}
}定義的時(shí)候可以設(shè)置一個(gè)泛型,此泛型的類型就是call()方法的返回的數(shù)據(jù)類型,好處:可以避免向下轉(zhuǎn)型的安全隱患。
線程類主體完成后,需要啟動(dòng)多線程的話還是需要通過Thread類實(shí)現(xiàn)的,又因?yàn)槲覀兊腃allable接口與Thread沒有聯(lián)系,所以我們需要FutureTask類實(shí)現(xiàn)兩者之間的聯(lián)系;如圖所示:

通過FutureTask類繼承結(jié)構(gòu)可以發(fā)現(xiàn)它是Runnable接口的子類;
代碼實(shí)現(xiàn)如下:
package Java從入門到項(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<String> {
@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類中,這樣就可以與Runnable接口關(guān)聯(lián)
FutureTask<String> task = new FutureTask<String>(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)過本文的學(xué)習(xí)后,相信大家對多線程編程的三種實(shí)現(xiàn)方式是什么這一問題有了更深刻的體會(huì),具體使用情況還需要大家實(shí)踐驗(yàn)證。這里是創(chuàng)新互聯(lián),小編將為大家推送更多相關(guān)知識(shí)點(diǎn)的文章,歡迎關(guān)注!
網(wǎng)站名稱:多線程編程的三種實(shí)現(xiàn)方式是什么
URL鏈接:http://www.chinadenli.net/article24/ispjje.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供網(wǎng)站維護(hù)、網(wǎng)站設(shè)計(jì)、手機(jī)網(wǎng)站建設(shè)、自適應(yīng)網(wǎng)站、Google、動(dòng)態(tài)網(wǎng)站
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來源: 創(chuàng)新互聯(lián)