Java并发篇_线程详解
線程(thread) 是操作系統(tǒng)能夠進(jìn)行運(yùn)算調(diào)度的最小單位。它被包含在進(jìn)程之中,是進(jìn)程中的實際運(yùn)作單位。一條線程指的是進(jìn)程中一個單一順序的控制流,一個進(jìn)程中可以并發(fā)多個線程,每條線程并行執(zhí)行不同的任務(wù)。
一、線程的分類
我們知道計算機(jī)可以分為硬件和軟件兩大塊,硬件是基礎(chǔ),軟件提供實現(xiàn)不同功能的手段;而軟件又可以分為操作系統(tǒng)和應(yīng)用程序,操作系統(tǒng)專注于對硬件的交互管理并提供一個運(yùn)行環(huán)境給應(yīng)用程序使用,應(yīng)用程序則是能實現(xiàn)若干功能的并且運(yùn)行在操作系統(tǒng)環(huán)境中的軟件。
同樣,線程按照操作系統(tǒng)和應(yīng)用程序兩層次可以分為內(nèi)核線程(Kernel-Level Thread)和用戶線程(User Thread)。
- 內(nèi)核線程(Kernel-Level Thread,KLT) 就是直接由操作系統(tǒng)內(nèi)核(Kernel,下稱內(nèi)核)支持的線程,這種線程由內(nèi)核來完成線程切換
- 用戶線程(User Thread,UT) 從廣義上來講,一個線程只要不是內(nèi)核線程,就可以認(rèn)為是用戶線程;而狹義上的用戶線程指的是完全建立在用戶空間的線程庫上,系統(tǒng)內(nèi)核不感知線程存在的實現(xiàn)。用戶線程的建立、同步、銷毀和調(diào)度完全在用戶態(tài)中完成,不需要內(nèi)核的幫助
二、Java線程的實現(xiàn)
Java創(chuàng)建線程的兩種方式:實現(xiàn)Runnable接口,繼承Thread類
- 實現(xiàn)Runnable接口:寫一個類實現(xiàn)Runnable接口,實現(xiàn)里面的run方法,用new Thread(Runnable target).start()方法來啟動
- 增強(qiáng)了程序的健壯性,代碼能夠被多個線程共享,代碼與數(shù)據(jù)是獨(dú)立的
- 線程體run()方法所在的類還可以從其他類繼承一些有用的屬性和方法,避免了由于Java的單繼承特性帶來的局限
- 有利于保持程序風(fēng)格的一致性
- 繼承Thread類:寫一個類繼承自Thread類,然后重寫里面的run方法,用start方法啟動線程
- Java中只支持單繼承,Thread子類無法再從其他類繼承
- 編寫簡單,run()方法的當(dāng)前對象就是線程對象,可直接操縱
三、Java的線程優(yōu)先級
Java使用的線程調(diào)度方式就是搶占式調(diào)度
雖然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線程優(yōu)先級與Windows線程優(yōu)先級之間的對應(yīng)關(guān)系,Windows平臺的JDK中使用了除THREAD_PRIORITY_IDLE之外的其余6種線程優(yōu)先級。
| 1. Thread.MIN_PRIORITY | THREAD_PRIORITY_LOWEST |
| 2. | THREAD_PRIORITY_LOWEST |
| 3. | THREAD_PRIORITY_BELOW_NORMAL |
| 4. | THREAD_PRIORITY_BELOW_NORMAL |
| 5. Thread.NORM_PRIORITY | THREAD_PRIORITY_NORMAL |
| 6. | THREAD_PRIORITY_ABOVE_NORMAL |
| 7. | THREAD_PRIORITY_ABOVE_NORMAL |
| 8. | THREAD_PRIORITY_HIGHEST |
| 9. | THREAD_PRIORITY_HIGHEST |
| 10. Thread.MAX_PRIORITY | THREAD_PRIORITY_CRITICAL |
其實,即使設(shè)置了線程的優(yōu)先級,一樣無法確保這個線程一定先執(zhí)行,因為它有很大的隨機(jī)性。它并無法控制執(zhí)行哪個線程,因為線程的執(zhí)行,是搶占資源后才能執(zhí)行的操作,而搶占到資源時,最多是給于線程優(yōu)先級較高的線程一點機(jī)會而已,能不能抓住可是不一定的。
說到底就一句話:線程優(yōu)化級較高的線程不一定先執(zhí)行
四、Java線程生命周期
線程的生命周期包含5個階段,包括:新建、就緒、運(yùn)行、阻塞、銷毀。
- 新建:就是剛使用new方法,new出來的線程;
- 就緒:就是調(diào)用的線程的start()方法后,這時候線程處于等待CPU分配資源階段,誰先搶的CPU資源,誰開始執(zhí)行;
- 運(yùn)行:當(dāng)就緒的線程被調(diào)度并獲得CPU資源時,便進(jìn)入運(yùn)行狀態(tài),run方法定義了線程的操作和功能;
- 阻塞:在運(yùn)行狀態(tài)的時候,可能因為某些原因?qū)е逻\(yùn)行狀態(tài)的線程變成了阻塞狀態(tài),比如sleep()、wait()之后線程就處于了阻塞狀態(tài),這個時候需要其他機(jī)制將處于阻塞狀態(tài)的線程喚醒,比如調(diào)用notify或者notifyAll()方法。喚醒的線程不會立刻執(zhí)行run方法,它們要再次等待CPU分配資源進(jìn)入運(yùn)行狀態(tài);
- 銷毀:如果線程正常執(zhí)行完畢后或線程被提前強(qiáng)制性的終止或出現(xiàn)異常導(dǎo)致結(jié)束,那么線程就要被銷毀,釋放資源;
完整的生命周期圖如下:
?
總結(jié)
以上是生活随笔為你收集整理的Java并发篇_线程详解的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Git 存储原理及相关实现
- 下一篇: Redis(三):Redis基础知识与常