溫馨提示×

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

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

Java中怎么實(shí)現(xiàn)讓線程按照自己指定的順序執(zhí)行

發(fā)布時(shí)間:2022-06-30 14:20:19 來(lái)源:億速云 閱讀:195 作者:iii 欄目:開發(fā)技術(shù)

這篇“Java中怎么實(shí)現(xiàn)讓線程按照自己指定的順序執(zhí)行”文章的知識(shí)點(diǎn)大部分人都不太理解,所以小編給大家總結(jié)了以下內(nèi)容,內(nèi)容詳細(xì),步驟清晰,具有一定的借鑒價(jià)值,希望大家閱讀完這篇文章能有所收獲,下面我們一起來(lái)看看這篇“Java中怎么實(shí)現(xiàn)讓線程按照自己指定的順序執(zhí)行”文章吧。

如何讓線程按照自己指定的順序執(zhí)行

我們?cè)谌粘5亩嗑€程開發(fā)中,可能有時(shí)會(huì)想讓每個(gè)線程都按照我們指定的順序來(lái)運(yùn)行,而不是讓CPU隨機(jī)調(diào)度,這樣可能會(huì)讓我們?cè)谌粘5拈_發(fā)工作中帶來(lái)不必要的麻煩。

既然有了這個(gè)需求,也就引入了本文的標(biāo)題,讓線程按照自己指定的順序來(lái)運(yùn)行。

有興趣的同學(xué)可以猜想下列代碼可能運(yùn)行的結(jié)果:

Java中怎么實(shí)現(xiàn)讓線程按照自己指定的順序執(zhí)行

按照正常的理解思路,上面代碼的執(zhí)行順序依次應(yīng)該為:t1 → t2 → t3,而實(shí)際效果則不是理想的狀態(tài)。

下圖為運(yùn)行效果:

Java中怎么實(shí)現(xiàn)讓線程按照自己指定的順序執(zhí)行

認(rèn)識(shí)Join

join可能對(duì)于一些同學(xué)來(lái)說(shuō)并不陌生,此處我就不詳細(xì)介紹Join是什么了,有疑問(wèn)的同學(xué)可以自行baidu和google。

這里我將直接介紹如何使用join來(lái)達(dá)到我們希望看到的效果!

Java中怎么實(shí)現(xiàn)讓線程按照自己指定的順序執(zhí)行

這里主要是利用Join的阻塞效果,來(lái)達(dá)到我們的使用目的??瓷蠄D的運(yùn)行結(jié)果可以得知,程序已經(jīng)按照我們指定的順序執(zhí)行結(jié)束了,并得到了我們想要的結(jié)果。

其實(shí)這里可以深入的思考一下,為什么join可以達(dá)到我們想要的效果呢?接下來(lái)我們來(lái)看下源碼:

進(jìn)入join源碼后,首先看到的是一個(gè)傳入0參數(shù)的join方法,此處選擇繼續(xù)進(jìn)入。

Java中怎么實(shí)現(xiàn)讓線程按照自己指定的順序執(zhí)行

首先可以看到j(luò)oin方法是線程安全的,其次可以結(jié)合上圖一起看,當(dāng)傳入?yún)?shù)為0時(shí),會(huì)命中一個(gè)wait(0)的方法,有經(jīng)驗(yàn)的同學(xué)應(yīng)該能直接看懂,這里表示等待。

但是需要說(shuō)明的是,這里的等待絕對(duì)不是等待調(diào)用者,而是阻塞的主線程,t1,t2,t3只是子線程,當(dāng)子線程運(yùn)行完畢后,主線程結(jié)束等待。

這里演示了join的工作方式,也證實(shí)了join能讓我們?cè)诔绦蛑羞_(dá)到自己想要的效果。

Java中怎么實(shí)現(xiàn)讓線程按照自己指定的順序執(zhí)行

除了join能在程序中幫助我們控制線程的順序外,還有另外的方式,比如我們利用線程池實(shí)現(xiàn)試一試。

利用Executors線程池

Executors是JDK中java.util.concurrent包下線程池操作類,可以方便的為我們提供線程池的操作。

這里我們使用Executors中的newSingleThreadExecutor()方法,創(chuàng)建一個(gè)單線程的線程池。

Java中怎么實(shí)現(xiàn)讓線程按照自己指定的順序執(zhí)行

根據(jù)上圖可以得知,利用newSingleThreadExecutor()方法依然能夠達(dá)到我們期待的效果,其實(shí)原理很簡(jiǎn)單,方法內(nèi)部是一個(gè)基于FIFO的隊(duì)列,也就是說(shuō),當(dāng)我們依次將t1,t2,t3加入隊(duì)列中時(shí),實(shí)際在就緒狀態(tài)的只有t1這個(gè)線程,t2,t3則會(huì)被添加到隊(duì)列中,當(dāng)t1執(zhí)行完畢后,則會(huì)繼續(xù)執(zhí)行隊(duì)列中的其他線程。

線程的優(yōu)先級(jí)及執(zhí)行順序

在學(xué)習(xí)運(yùn)算符時(shí),讀者知道各個(gè)運(yùn)算符之間有優(yōu)先級(jí),了解運(yùn)算符的優(yōu)先級(jí)對(duì)程序幵發(fā)有很好的作用。線程也是如此,每個(gè)線程都具有優(yōu)先級(jí),Java 虛擬機(jī)根據(jù)線程的優(yōu)先級(jí)決定線程的執(zhí)行順序,這樣使多線程合理共享 CPU 資源而不會(huì)產(chǎn)生沖突。

優(yōu)先級(jí)概述

在 Java 語(yǔ)言中,線程的優(yōu)先級(jí)范圍是 1~10,值必須在 1~10,否則會(huì)出現(xiàn)異常;優(yōu)先級(jí)的默認(rèn)值為 5。優(yōu)先級(jí)較高的線程會(huì)被優(yōu)先執(zhí)行,當(dāng)執(zhí)行完畢,才會(huì)輪到優(yōu)先級(jí)較低的線程執(zhí)行。如果優(yōu)先級(jí)相同,那么就采用輪流執(zhí)行的方式。

可以使用 Thread 類中的 setPriority() 方法來(lái)設(shè)置線程的優(yōu)先級(jí)。語(yǔ)法如下:

public final void setPriority(int newPriority);

如果要獲取當(dāng)前線程的優(yōu)先級(jí),可以直接調(diào)用 getPriority() 方法。語(yǔ)法如下:

public final int getPriority();

使用優(yōu)先級(jí)

簡(jiǎn)單了解過(guò)優(yōu)先級(jí)之后,下面通過(guò)一個(gè)簡(jiǎn)單的例子來(lái)演示如何使用優(yōu)先級(jí)。

例 1

分別使用 Thread 類和 Runnable 接口創(chuàng)建線程,并為它們指定優(yōu)先級(jí)。

public class FirstThreadInput extends Thread
{
    public void run()
    {
        System.out.println("調(diào)用FirstThreadInput類的run()重寫方法");    //輸出字符串
        for(int i=0;i<5;i++)
        {
            System.out.println("FirstThreadInput線程中i="+i);    //輸出信息
            try
            {
                Thread.sleep((int) Math.random()*100);    //線程休眠
            }
            catch(Exception e){}
        }
    }
}

(2) 創(chuàng)建實(shí)現(xiàn) Runnable 接口的 SecondThreadInput 類,實(shí)現(xiàn) run() 方法。代碼如下:

public class SecondThreadInput implements Runnable
{
    public void run()
    {
        System.out.println("調(diào)用SecondThreadInput類的run()重寫方法");    //輸出字符串
        for(int i=0;i<5;i++)
        {
            System.out.println("SecondThreadInput線程中i="+i);    //輸出信息
            try
            {
                Thread.sleep((int) Math.random()*100);    //線程休眠
            }
            catch(Exception e){}
        }
    }
}

(3) 創(chuàng)建 TestThreadInput 測(cè)試類,分別使用 Thread 類的子類和 Runnable 接口的對(duì)象創(chuàng)建線程,然后調(diào)用 setPriority() 方法將這兩個(gè)線程的優(yōu)先級(jí)設(shè)置為 4,最后啟動(dòng)線程。代碼如下:

public class TestThreadInput
{
    public static void main(String[] args)
    {
        FirstThreadInput fti=new FirstThreadInput();
        Thread sti=new Thread(new SecondThreadInput());
        fti.setPriority(4);
        sti.setPriority(4);
        fti.start();
        sti.start();
    }
}

(4) 運(yùn)行上述代碼,運(yùn)行結(jié)果如下所示。

調(diào)用FirstThreadInput類的run()重寫方法
調(diào)用SecondThreadInput類的run()重寫方法
FirstThreadInput線程中i=0
SecondThreadInput線程中i=0
FirstThreadInput線程中i=1
FirstThreadInput線程中i=2
SecondThreadInput線程中i=1
FirstThreadInput線程中i=3
SecondThreadInput線程中i=2
FirstThreadInput線程中i=4
SecondThreadInput線程中i=3
SecondThreadInput線程中i=4

由于該例子將兩個(gè)線程的優(yōu)先級(jí)都設(shè)置為 4,因此它們交互占用 CPU ,宏觀上處于并行運(yùn)行狀態(tài)。

重新更改 ThreadInput 類的代碼、設(shè)置優(yōu)先級(jí)。代碼如下:

fti.setPriority(1);
sti.setPriority(10);

重新運(yùn)行上述代碼,如下所示。

調(diào)用FirstThreadInput類的run()重寫方法
調(diào)用SecondThreadInput類的run()重寫方法
FirstThreadInput線程中i=0
SecondThreadInput線程中i=0
SecondThreadInput線程中i=1
SecondThreadInput線程中i=2
SecondThreadInput線程中i=3
SecondThreadInput線程中i=4
FirstThreadInput線程中i=1
FirstThreadInput線程中i=2
FirstThreadInput線程中i=3
FirstThreadInput線程中i=4

以上就是關(guān)于“Java中怎么實(shí)現(xiàn)讓線程按照自己指定的順序執(zhí)行”這篇文章的內(nèi)容,相信大家都有了一定的了解,希望小編分享的內(nèi)容對(duì)大家有幫助,若想了解更多相關(guān)的知識(shí)內(nèi)容,請(qǐng)關(guān)注億速云行業(yè)資訊頻道。

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

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

AI