日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

按照顺序执行_问一个多线程的问题:如何才能保证线程有序执行?

發(fā)布時間:2025/3/12 编程问答 22 豆豆
生活随笔 收集整理的這篇文章主要介紹了 按照顺序执行_问一个多线程的问题:如何才能保证线程有序执行? 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

面試的時候你是否經(jīng)常被問到這樣的問題:

你一般通過什么方式去控制線程的執(zhí)行順序?

碰到這樣的問題,我的內(nèi)心其實是很抵觸的!

開什么玩笑?我怎么會控制它呢?我為什么要控制它?

其實不用慌,這個問題并不難,且聽我慢慢道來......

一、那么,什么是線程、進(jìn)程?

要想控制多線程的順序,你首先應(yīng)該搞清楚線程和進(jìn)程到底是什么東西?

1、進(jìn)程

進(jìn)程其實是操作系統(tǒng)的基礎(chǔ),是系統(tǒng)中一次程序的執(zhí)行,也是一次程序和數(shù)據(jù)在機(jī)器上順序執(zhí)行時所發(fā)生的活動,又是系統(tǒng)進(jìn)行資源分配和調(diào)度的一個獨立單位。

其實說的通俗一點,可以這么理解,進(jìn)程就是Windows系統(tǒng)中執(zhí)行的一個exe程序,是操作系統(tǒng)管理的基本運行單元,看下面這個圖你就知道啥是進(jìn)程了!

2、線程

線程是比進(jìn)程還要小的一個單元,它是進(jìn)程中獨立運行的子任務(wù)。

你比如說一個微信.exe程序進(jìn)程中就有非常多的子線程在同時運行,例如音視頻線程、文件下載線程、信息傳輸線程等等,這些不同的任務(wù)如果都在一個線程去運行,那程序必定會特別慢,大家的體驗不會像現(xiàn)在那樣舒服,所以這里的每一個任務(wù)或功能都需要對應(yīng)一個后臺的線程在默默運行。

簡單來說,線程就是組成進(jìn)程的一條路徑,一個進(jìn)程可以包含一個或者多個線程。

二、什么是多線程環(huán)境?

關(guān)于多線程的環(huán)境,其實大家在使用Windows系統(tǒng)的時候就深有感觸。

想象你一邊在用IDE碼代碼,一邊要和朋友聊天,還一邊帶著耳機(jī)聽著音樂,你的系統(tǒng)為什么能夠同時提供給你那么多服務(wù)呢?

其實這就是一個典型的多線程環(huán)境,你的電腦的CPU正在不斷的從這些任務(wù)中飛速切換來處理程序中的各種事情,由于計算機(jī)的切換處理速度非常的快,所以你沒辦法在界面上進(jìn)行感知,給我們的感覺就是他們其實在同時為我們服務(wù)著,這也是多線程環(huán)境的一種優(yōu)勢!

用一張圖的方式來對比感受一下多線程的環(huán)境,例如:

在上圖中,單線程環(huán)境下一號、二號處理任務(wù)是完全獨立的兩個任務(wù),但是二號任務(wù)必須要等待1號任務(wù)處理完成才能執(zhí)行,也就是二號處理任務(wù)必須要在程序開始后的5秒后才能運行到,最終的運行時間為15秒。

但是在多線程環(huán)境下,一號、二號雖然也是完全獨立的任務(wù),處在同一個進(jìn)程中,但卻由不同的線程去處理,CPU可以在這兩個不同的線程之間進(jìn)行切換,所以二號處理任務(wù)不需要在一號處理完成之后再處理,而是做異步處理,最終的運行時間也差不多在10秒左右。

三、幾個關(guān)于CPU、線程執(zhí)行的知識點

1、在單CPU計算機(jī)中,CPU是無法被多個程序并行使用的。

2、操作系統(tǒng)中存在一種調(diào)度器,它可以負(fù)責(zé)拆分CPU為一段段時間的運行片,輪流分配給不同的進(jìn)程。

3、程序的運行不僅僅需要CPU,還需要很多其他資源,如內(nèi)存啊,顯卡啊,GPS啊,磁盤等等,這些統(tǒng)稱為程序的執(zhí)行環(huán)境,也就是程序上下文。

4、多個程序沒辦法同一個時間共享CPU,那怎么辦呢?這個時候比進(jìn)程更小的線程就出來了,通過在不同線程的切換來達(dá)到共享CPU、共享程序上下文的目的。

5、大家都知道,CPU有單核和多核區(qū)別,單核CPU其實就是多個線程會輪流得到那一個CPU核心的支持;在多核CPU中,一個核心可以服務(wù)于一個線程,例如我的電腦是4核的話,有四個線程A、B、C、D需要處理,那CPU會將他們分配到核心1、2、3、4,如果還有其他更多的線程,也必須要等待CPU的切換執(zhí)行。

通過上面幾個知識點,可以看出不管是在多核還是單核的系統(tǒng)中,CPU在多線程的環(huán)境中都是要不斷切換線程來處理任務(wù)的,當(dāng)然,CPU在切換任務(wù)時也不是順便切換,而是根據(jù)一定的算法來調(diào)度、切換線程,一般有這樣兩種模式:分時調(diào)度和搶占式調(diào)度。

分時調(diào)度就是按照順序平均分配;

搶占式調(diào)度就是按照優(yōu)先級來進(jìn)行分配。

具體的算法邏輯在這里就不再詳細(xì)描述,有疑問的小伙伴們可以再繼續(xù)往下深入探索......

四、如何去控制多線程的執(zhí)行順序?

通過一個簡單的程序,體驗一下線程是否會隨機(jī)被執(zhí)行,手動創(chuàng)建5個Thread對象,然后讓他們按照順序開啟,如下面代碼:

/*** 多線程Test*/ public class Main {static Thread thread1 = new Thread(new Runnable() {@Overridepublic void run() {System.out.println("thread01");}});static Thread thread2 = new Thread(new Runnable() {@Overridepublic void run() {System.out.println("thread02");}});static Thread thread3 = new Thread(new Runnable() {@Overridepublic void run() {System.out.println("thread03");}});static Thread thread4 = new Thread(new Runnable() {@Overridepublic void run() {System.out.println("thread04");}});static Thread thread5 = new Thread(new Runnable() {@Overridepublic void run() {System.out.println("thread05");}});public static void main(String[] args) {thread1.start();thread2.start();thread3.start();thread4.start();thread5.start();} }

最后執(zhí)行的結(jié)果大家一定已經(jīng)猜到了,多次執(zhí)行,它的順序并不是固定的,而是隨機(jī)在改變的,例如:

那么在多線程的環(huán)境中,我們有時候不想讓CPU根據(jù)算法隨機(jī)選取任務(wù)執(zhí)行,而是想控制多線程的執(zhí)行順序,那應(yīng)該如何操作呢?

目前我知道的主要有兩種方法:

1、Join方法

我們直接通過在每個Thread對象后面使用join方法就可以實現(xiàn)線程的順序執(zhí)行,代碼如下:

public static void main(String[] args) throws Exception {thread1.start();thread1.join();thread2.start();thread2.join();thread3.start();thread3.join();thread4.start();thread4.join();thread5.start();thread5.join();}

多次執(zhí)行結(jié)果都為下面這種情況:

用join方法來保證線程順序,其實就是讓main這個主線程等待子線程結(jié)束,然后主線程再執(zhí)行接下來的其他線程任務(wù),點進(jìn)去join方法我們可以了解的更透徹:

/*** Waits at most {@code millis} milliseconds for this thread to* die. A timeout of {@code 0} means to wait forever.*/public final synchronized void join(long millis)throws InterruptedException {long base = System.currentTimeMillis();long now = 0;if (millis < 0) {throw new IllegalArgumentException("timeout value is negative");}if (millis == 0) {while (isAlive()) {wait(0);}} else {while (isAlive()) {long delay = millis - now;if (delay <= 0) {break;}wait(delay);now = System.currentTimeMillis() - base;}}}

源碼中的參數(shù)millis默認(rèn)值是0,從英文注釋翻譯后可以找到,0秒意味著永遠(yuǎn)等待,也就是thread1執(zhí)行不完,那主線程你就要一直等著,一直wait,而代碼中wait方法其實就是屬于Object的方法,負(fù)責(zé)線程的休眠等待,當(dāng)main主線程調(diào)用thread1.join的時候,main主線程會獲得線程對象thread1的鎖(wait 意味著拿到該對象的鎖),調(diào)用該對象的wait(等待時間),直到該對象喚醒main主線程 ,比如退出后。這就意味著main 線程調(diào)用thread1.join時,必須能夠拿到線程t對象的鎖。

2、ExecutorService方式

首先看一下代碼,我們?nèi)绾瓮ㄟ^這種方式實現(xiàn)線程順序執(zhí)行:

static ExecutorService executorService = Executors.newSingleThreadScheduledExecutor();public static void main(String[] args) throws Exception {executorService.submit(thread1);executorService.submit(thread2);executorService.submit(thread3);executorService.submit(thread4);executorService.submit(thread5);executorService.shutdown();}

最終的多次執(zhí)行結(jié)果均為有序的,如下圖:

解釋一下,這種方式的原理其實就是將線程用排隊的方式扔進(jìn)一個線程池里,讓所有的任務(wù)以單線程的模式,按照FIFO先進(jìn)先出、LIFO后進(jìn)先出、優(yōu)先級等特定順序執(zhí)行,但是這種方式也是存在缺點的,就是當(dāng)一個線程被阻塞時,其它的線程都會受到影響被阻塞,不過依然都會按照自身調(diào)度來執(zhí)行,只是會存在阻塞延遲。

五、總結(jié)

總之,如果面試官真的問到大家如何控制多線程執(zhí)行順序的方法,就按照上面的兩種方式回答即可,當(dāng)然,面試官既然問到這個問題,就并不只是看大家是否知道這一個問題的具體答案,可能會刨根問底的讓你回答更深入的一些多線程問題,所以在日常的學(xué)習(xí)過程中一定要重在積累,勤于探索,上面提到的也只是我研究到的皮毛。

最后真心希望,在以后的技術(shù)之路跟大家一起成長!

總結(jié)

以上是生活随笔為你收集整理的按照顺序执行_问一个多线程的问题:如何才能保证线程有序执行?的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。