溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點(diǎn)擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

多線程編程的三種實(shí)現(xiàn)方式是什么

發(fā)布時(shí)間:2021-10-15 09:14:00 來源:億速云 閱讀:128 作者:iii 欄目:編程語言

這篇文章主要講解了“多線程編程的三種實(shí)現(xiàn)方式是什么”,文中的講解內(nèi)容簡單清晰,易于學(xué)習(xí)與理解,下面請大家跟著小編的思路慢慢深入,一起來研究和學(xué)習(xí)“多線程編程的三種實(shí)現(xiàn)方式是什么”吧!

多線程編程

進(jìn)程與線程的理解:

進(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)行一樣。

多線程編程的三種實(shí)現(xiàn)方式是什么

進(jìn)程與線程的區(qū)別與聯(lián)系:

  1. 進(jìn)程是資源調(diào)度的基本單位,運(yùn)行一個(gè)可執(zhí)行程序會(huì)創(chuàng)建一個(gè)或多個(gè)線程,進(jìn)程就是運(yùn)行起來的可執(zhí)行程序;

  2. 線程是程序執(zhí)行的基本單位,是輕量級的進(jìn)程,每個(gè)進(jìn)程中都有唯一的主線程,且只能有一個(gè),主線程和進(jìn)程是相互依存的關(guān)系,主線程結(jié)束,進(jìn)程也會(huì)結(jié)束。

多線程編程的三種實(shí)現(xiàn)方式是什么

具體實(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):

實(shí)現(xiàn)多線程需要一個(gè)線程的主體類,這個(gè)類可以繼承Thread、實(shí)現(xiàn)Runnable以及Callable接口完成定義;

Thread實(shí)現(xiàn)多線程:

繼承結(jié)構(gòu)如下:

public class Thread extends Object implements Runnable

實(shí)現(xiàn)接口Runnable,所以必須實(shí)現(xiàn)接口中的抽象方法:

Modifier and TypeMethodDescription
voidrun()當(dāng)一個(gè)實(shí)現(xiàn)接口Runnable的對象被用來創(chuàng)建線程時(shí),啟動(dòng)線程會(huì)導(dǎo)致對象的run方法在單獨(dú)執(zhí)行的線程中被調(diào)用。
voidstart()使線程開始執(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í)行:

多線程編程的三種實(shí)現(xiàn)方式是什么

假如面試題:

為什么線程啟動(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吧。

Runnable接口實(shí)現(xiàn)多線程:

出現(xiàn)的原因:為了解決Thread實(shí)現(xiàn)多線程出現(xiàn)的單繼承問題;并且增加了函數(shù)式接口;

Modifier and TypeMethodDescription
voidrun()當(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)多線程:

為什么要使用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)系;如圖所示:

多線程編程的三種實(shí)現(xià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)證。這里是億速云,小編將為大家推送更多相關(guān)知識(shí)點(diǎn)的文章,歡迎關(guān)注!

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI