這篇文章主要介紹“系統(tǒng)線程的實現(xiàn)原理是什么”,在日常操作中,相信很多人在系統(tǒng)線程的實現(xiàn)原理是什么問題上存在疑惑,小編查閱了各式資料,整理出簡單好用的操作方法,希望對大家解答”系統(tǒng)線程的實現(xiàn)原理是什么”的疑惑有所幫助!接下來,請跟著小編一起來學(xué)習(xí)吧!
成都創(chuàng)新互聯(lián)是一家集網(wǎng)站建設(shè),南安企業(yè)網(wǎng)站建設(shè),南安品牌網(wǎng)站建設(shè),網(wǎng)站定制,南安網(wǎng)站建設(shè)報價,網(wǎng)絡(luò)營銷,網(wǎng)絡(luò)優(yōu)化,南安網(wǎng)站推廣為一體的創(chuàng)新建站企業(yè),幫助傳統(tǒng)企業(yè)提升企業(yè)形象加強企業(yè)競爭力??沙浞譂M足這一群體相比中小企業(yè)更為豐富、高端、多元的互聯(lián)網(wǎng)需求。同時我們時刻保持專業(yè)、時尚、前沿,時刻以成就客戶成長自我,堅持不斷學(xué)習(xí)、思考、沉淀、凈化自己,讓我們?yōu)楦嗟钠髽I(yè)打造出實用型網(wǎng)站。
使用內(nèi)核線程(1:1 模型)
使用用戶線程(1:N 模型)
使用用戶線程 + 輕量級進程(LWP)(N:M 模型)
我們先復(fù)習(xí)下操作系統(tǒng)中的幾個關(guān)鍵概念:
進程 P:用戶進程
下面依次介紹三種線程模型:
內(nèi)核線程模型即完全依賴操作系統(tǒng)內(nèi)核提供的內(nèi)核線程(Kernel-Level Thread ,KLT)來實現(xiàn)多線程。在此模型下,線程的切換調(diào)度由系統(tǒng)內(nèi)核完成,系統(tǒng)內(nèi)核負(fù)責(zé)將多個線程執(zhí)行的任務(wù)映射到各個CPU中去執(zhí)行。
程序一般不會直接去使用內(nèi)核線程,而是去使用內(nèi)核線程的一種高級接口——輕量級進程(Light Weight Process,LWP),輕量級進程就是我們通常意義上所講的線程,由于每個輕量級進程都由一個內(nèi)核線程支持,因此只有先支持內(nèi)核線程,才能有輕量級進程。這種輕量級進程與內(nèi)核線程之間1:1的關(guān)系稱為一對一的線程模型。
從廣義上來講,一個線程只要不是內(nèi)核線程,就可以認(rèn)為是用戶線程(User Thread,UT),因此,從這個定義上來講,輕量級進程也屬于用戶線程,但輕量級進程的實現(xiàn)始終是建立在內(nèi)核之上的,許多操作都要進行系統(tǒng)調(diào)用,效率會受到限制。
使用用戶線程的優(yōu)勢在于不需要系統(tǒng)內(nèi)核支援,劣勢也在于沒有系統(tǒng)內(nèi)核的支援,所有的線程操作都需要用戶程序自己處理。線程的創(chuàng)建、切換和調(diào)度都是需要考慮的問題,而且由于操作系統(tǒng)只把處理器資源分配到進程,那諸如“阻塞如何處理”、“多處理器系統(tǒng)中如何將線程映射到其他處理器上”這類問題解決起來將會異常困難,甚至不可能完成。
因而使用用戶線程實現(xiàn)的程序一般都比較復(fù)雜,此處所講的“復(fù)雜”與“程序自己完成線程操作”,并不限制程序中必須編寫了復(fù)雜的實現(xiàn)用戶線程的代碼,使用用戶線程的程序,很多都依賴特定的線程庫來完成基本的線程操作,這些復(fù)雜性都封裝在線程庫之中,除了以前在不支持多線程的操作系統(tǒng)中(如DOS)的多線程程序與少數(shù)有特殊需求的程序外,現(xiàn)在使用用戶線程的程序越來越少了,Java、Ruby等語言都曾經(jīng)使用過用戶線程,最終又都放棄使用它。
線程除了依賴內(nèi)核線程實現(xiàn)和完全由用戶程序自己實現(xiàn)之外,還有一種將內(nèi)核線程與用戶線程一起使用的實現(xiàn)方式。在這種混合實現(xiàn)下,既存在用戶線程,也存在輕量級進程。
用戶線程還是完全建立在用戶空間中,因此用戶線程的創(chuàng)建、切換、析構(gòu)等操作依然廉價,并且可以支持大規(guī)模的用戶線程并發(fā)。而操作系統(tǒng)提供支持的輕量級進程則作為用戶線程和內(nèi)核線程之間的橋梁,這樣可以使用內(nèi)核提供的線程調(diào)度功能及處理器映射,并且用戶線程的系統(tǒng)調(diào)用要通過輕量級線程來完成,大大降低了整個進程被完全阻塞的風(fēng)險。
在這種混合模式中,用戶線程與輕量級進程的數(shù)量比是不定的,即為N:M的關(guān)系。許多UNIX系列的操作系統(tǒng),如Solaris、HP-UX等都提供了N:M的線程模型實現(xiàn)。
對于Sun JDK來說,它的Windows版與Linux版都是使用一對一的線程模型實現(xiàn)的,一條Java線程就映射到一條輕量級進程之中,因為Windows和Linux系統(tǒng)提供的線程模型就是一對一的。在Solaris平臺中,由于操作系統(tǒng)的線程特性可以同時支持一對一(通過Bound Threads或Alternate Libthread實現(xiàn))及多對多(通過LWP/Thread Based Synchronization實現(xiàn))的線程模型,因此在Solaris版的JDK中也對應(yīng)提供了兩個平臺專有的虛擬機參數(shù):-XX:+UseLWPSynchronization(默認(rèn)值)和-XX:+UseBoundThreads來明確指定虛擬機使用哪種線程模型。
操作系統(tǒng)的線程調(diào)度方式
線程調(diào)度是指系統(tǒng)為線程分配處理器使用權(quán)的過程。
主要的線程調(diào)度方式有兩種,分別是 協(xié)同式線程調(diào)度(Cooperative Threads-Scheduling)和 搶占式線程調(diào)度(Preemptive Threads-Scheduling)
搶占式調(diào)度
如果使用搶占式調(diào)度的多線程系統(tǒng),那么每個線程將由系統(tǒng)來分配執(zhí)行時間,線程的切換不由線程本身來決定(在Java中,Thread.yield()可以讓出執(zhí)行時間,但是要獲取執(zhí)行時間的話,線程本身是沒有什么辦法的)。
在這種實現(xiàn)線程調(diào)度的方式下,線程的執(zhí)行時間是系統(tǒng)可控的,也不會有一個線程導(dǎo)致整個進程阻塞的問題。
Java使用的線程調(diào)度方式就是搶占式調(diào)度。在JDK后續(xù)版本中有可能會提供協(xié)程(Coroutines)方式來進行多任務(wù)處理。
與前面所說的Windows 3.x的例子相對,在Windows 9x/NT內(nèi)核中就是使用搶占式來實現(xiàn)多進程的,當(dāng)一個進程出了問題,我們還可以使用任務(wù)管理器把這個進程“殺掉”,而不至于導(dǎo)致系統(tǒng)崩潰。
線程優(yōu)先級
雖然Java線程調(diào)度是系統(tǒng)自動完成的,但是我們還是可以“建議”系統(tǒng)給某些線程多分配一點執(zhí)行時間,另外的一些線程則可以少分配一點——這項操作可以通過設(shè)置線程優(yōu)先級來完成。
Java語言一共設(shè)置了10個級別的線程優(yōu)先級(Thread.MIN_PRIORITY至Thread.MAX_PRIORITY),在兩個線程同時處于Ready狀態(tài)時,優(yōu)先級越高的線程越容易被系統(tǒng)選擇執(zhí)行。
不過,線程優(yōu)先級并不是太靠譜,原因是Java的線程是通過映射到系統(tǒng)的原生線程上來實現(xiàn)的,所以線程調(diào)度最終還是取決于操作系統(tǒng),雖然現(xiàn)在很多操作系統(tǒng)都提供線程優(yōu)先級的概念,但是并不見得能與Java線程的優(yōu)先級一一對應(yīng)。
如Solaris中有2147483648(232)種優(yōu)先級,但Windows中就只有7種,比Java線程優(yōu)先級多的系統(tǒng)還好說,中間留下一點空位就可以了,但比Java線程優(yōu)先級少的系統(tǒng),就不得不出現(xiàn)幾個優(yōu)先級相同的情況了。
Java語言定義了5種線程狀態(tài),在任意一個時間點,一個線程只能有且只有其中的一種狀態(tài),這5種狀態(tài)分別如下:
新建(New):創(chuàng)建后尚未啟動的線程處于這種狀態(tài)。
運行(Runable):Runable包括了操作系統(tǒng)線程狀態(tài)中的Running和Ready,也就是處于此狀態(tài)的線程有可能正在執(zhí)行,也有可能正在等待著CPU為它分配執(zhí)行時間。
無限期等待(Waiting):處于這種狀態(tài)的線程不會被分配CPU執(zhí)行時間,它們要等待被其他線程顯式地喚醒。
以下方法會讓線程陷入無限期的等待狀態(tài):沒有設(shè)置Timeout參數(shù)的Object.wait()方法。沒有設(shè)置Timeout參數(shù)的Thread.join()方法。LockSupport.park()方法。
限期等待(Timed Waiting):處于這種狀態(tài)的線程也不會被分配CPU執(zhí)行時間,不過無須等待被其他線程顯式地喚醒,在一定時間之后它們會由系統(tǒng)自動喚醒。
以下方法會讓線程進入限期等待狀態(tài):Thread.sleep()方法。設(shè)置了Timeout參數(shù)的Object.wait()方法。設(shè)置了Timeout參數(shù)的Thread.join()方法。LockSupport.parkNanos()方法。LockSupport.parkUntil()方法。
阻塞(Blocked):線程被阻塞了,“阻塞狀態(tài)”與“等待狀態(tài)”的區(qū)別是:“阻塞狀態(tài)”在等待著獲取到一個排他鎖,這個事件將在另外一個線程放棄這個鎖的時候發(fā)生;而“等待狀態(tài)”則是在等待一段時間,或者喚醒動作的發(fā)生。在程序等待進入同步區(qū)域的時候,線程將進入這種狀態(tài)。
結(jié)束(Terminated):已終止線程的線程狀態(tài),線程已經(jīng)結(jié)束執(zhí)行。
Java 多線程實現(xiàn)
實現(xiàn)1:繼承Thread類
// 繼承 Threadpublic class MyThread extends Thread { @Override public void run() { System.out.println("MyThread run..."); }}
實現(xiàn)2:實現(xiàn) Runnable 接口
public class MyRunnable implements Runnable { @Override public void run() { System.out.println("MyRunnable run..."); }}
實現(xiàn)3:實現(xiàn) Callable 接口,使用 FutureTask 獲取異步返回值
public static void main(String[] args) throws ExecutionException, InterruptedException { class MyCallable implements Callable{ @Override public String call() throws Exception { return "MyCallable"; } } FutureTask task = new FutureTask<>(new MyCallable()); Thread c = new Thread(task); c.start(); System.out.println(task.get()); }
實現(xiàn)4:JDK8以上版本使用 CompletableFuture 進行異步計算。
在Java8中,提供了非常強大的Future的擴展功能,可以幫助我們簡化異步編程的復(fù)雜性,并且提供了函數(shù)式編程的能力,可以通過回調(diào)的方式處理計算結(jié)果,也提供了轉(zhuǎn)換和組合 CompletableFuture 的方法。
public class CompletableFutureTest {
public static void main(String[] args) {
ExecutorService threadPool = Executors.newFixedThreadPool(2);
// JDK1.8 提供的 CompletableFuture
CompletableFuture
futureTask = CompletableFuture.supplyAsync(new Supplier () { @Override
public String get() {
System.out.println("task start");
try {
Thread.sleep(10000);
} catch (Exception e) {
e.printStackTrace();
return "execute failure";
}
System.out.println("task end");
return "execute success";
}
}, threadPool);
// 異步獲取 futureTask 的執(zhí)行結(jié)果,此處代碼可以跟其他流程代碼放在一起
futureTask.thenAccept(e-> System.out.println("future task result:" + e));
System.out.println("main thread end");
}
}
輸出結(jié)果:
task start
main thread end
task end
future task result:execute success
實現(xiàn)5:使用線程池,ThreadPoolExecutor 類
。
public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueueworkQueue, ThreadFactory threadFactory) { this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory, defaultHandler);} Future submit(Callable task);Future> submit(Runnable task);
到此,關(guān)于“系統(tǒng)線程的實現(xiàn)原理是什么”的學(xué)習(xí)就結(jié)束了,希望能夠解決大家的疑惑。理論與實踐的搭配能更好的幫助大家學(xué)習(xí),快去試試吧!若想繼續(xù)學(xué)習(xí)更多相關(guān)知識,請繼續(xù)關(guān)注創(chuàng)新互聯(lián)網(wǎng)站,小編會繼續(xù)努力為大家?guī)砀鄬嵱玫奈恼拢?/p>
本文名稱:系統(tǒng)線程的實現(xiàn)原理是什么
當(dāng)前地址:http://weahome.cn/article/iipgsg.html