白话说编程之java线程
白話說編程之java線程
- 線程和進程:
- 進程:
- 線程:
- 線程和進程的區(qū)別:
- 詳解多線程:
- 并發(fā)
- 為什么使用并發(fā)
- 并發(fā)的執(zhí)行原理
- 并行
- 線程的五種狀態(tài):
- 創(chuàng)建狀態(tài):
- 就緒狀態(tài):
- 運行狀態(tài):
- 阻塞狀態(tài):
- 死亡狀態(tài):
- 線程的創(chuàng)建方式:
- 繼承Thread
- 實現(xiàn)Runnable
- 匿名內(nèi)部類方式
- 迷惑問題
- 繼承THread類方法和實現(xiàn)Runnable接口 這兩種方式選擇哪一種好呢?
- 繼器啟動線程是調(diào)用run方法還是start方法
- 線程的分類:
- 用戶線程(也叫前臺線程):
- 守護線程(也叫后臺線程):
- 分享一波:程序員賺外快-必看的巔峰干貨
線程和進程:
在說多線程之前,我們先來研究一下線程,說到線程,我們又不得不說到進程,因為很多初學(xué)者會把線程和進程分不清,搞混淆。
進程:
是操作系統(tǒng)系統(tǒng)運行的最小單元。怎么理解這句話,可以這樣去對比,相信大家都見過積木玩具,可以搭建成很多的大型成品(操作系統(tǒng)Windows/Linux等等),而每一個積木都是組成這個成品的一個組件(也就是進程單元)這是操作系統(tǒng)和進程的關(guān)系(操作系統(tǒng)的組成很復(fù)雜,不是像積木簡單的組合就能完成的,但是最底層原理我們可以這么想象是沒有問題的)。
線程:
線程是一組指令的集合,它可以獨立的運行在一個進程里。關(guān)于指令的集合:就是指我們編程里寫的一個類,里面用到的關(guān)鍵字、方法名、變量名等等都是指令(你們可以這樣去理解,完全沒有問題,這里聲明一下真正的指令是jvm編譯成.class文件后,.class中的二進制碼才是真正的指令,但是二進制碼對于人類來說太多太難記,所以就用關(guān)鍵字來代表二進制的含義)。在這里我們又可以把線程去當(dāng)成一個積木,而進程是一個個積木所組成的成品。
線程和進程的區(qū)別:
通過上面的例子,不難理解進程和線程之間的關(guān)系,進程包含線程,線程是進程的一個單元。所以在這里我們要注意一下,在進程中至少包含一個線程(主線程)。(這樣講,一個積木都沒有還會有成品嗎)
總結(jié):進程是所有線程的集合,每一個線程是進程中的一條執(zhí)行路徑。
詳解多線程:
在上面的例子中,我們知道線程和進程的區(qū)別,對于多線程的具體作用我們在這里詳細解釋。
并發(fā)
并發(fā):多個線程在一個單核cpu上進行資源搶占并運行,就是并發(fā)。
多線程在cpu中是并發(fā)運行的(下面會詳細解釋并發(fā),還有和并行的區(qū)別)
首先我們要知道在cpu(這里指的是單核cpu)中在某一個時間片,只能有一個線程在cpu中運行。一個cpu在同一時間只能執(zhí)行一個線程。
為什么使用并發(fā)
在一個進程中有多個線程需要執(zhí)行,這些線程會搶占cpu的時間片來運行自身。有人會問,為什么不等一個線程執(zhí)行完之后再去執(zhí)行另一個線程呢?思考一下,我們在使用電腦的時候,可以同時看文檔,聽音樂。如果cpu設(shè)計成一個線程執(zhí)行完之后再去執(zhí)行另一個線程,你就只能聽完音樂,在去看文檔,在聽音樂的過程中你的鼠標都移動不了(鼠標也是一個單獨線程),你們覺得這樣的體驗好嗎,所以cpu肯定不能這樣設(shè)計。
并發(fā)的執(zhí)行原理
操作系統(tǒng)是以搶占式的方法來調(diào)度線程的(也有其他方法,我們目前先學(xué)這一種)。就是線程自己去強cpu的資源,誰先搶到誰就在cpu上運行一個時間片(這個時間片很短很短)。這里的線程會有優(yōu)先級的特點,優(yōu)先級高的線程搶到cpu的概率大,概率大,概率大(是概率大,不代表一定能搶到)運行完成之后釋放cpu資源,回去重新?lián)屨糲pu。因為運行的時間很短,所以在人為感官上覺得這些線程始再同時運行的。
其實上面多個線程搶占cpu資源就是多線程的并發(fā)。
注意:這里是一個cpu。隨著需求的不斷增高,科技的不斷發(fā)展,單核cpu的性能已經(jīng)不能滿足效率。于是就出現(xiàn)了多核cpu,也就出現(xiàn)了并行
并行
并行:在同一時間點,多個線程同時運行在多核cpu的多個核上,這叫并行。和并發(fā)不同的是:同一時間,在并行中,線程可以同時運行,而并發(fā)則只能有一個線程運行。
線程的五種狀態(tài):
創(chuàng)建狀態(tài):
當(dāng)用new操作符創(chuàng)建一個線程時, 例如new Thread?,線程還沒有開始運行,此時線程處在新建狀態(tài)。 當(dāng)一個線程處于新生狀態(tài)時,程序還沒有開始運行線程中的代碼
就緒狀態(tài):
一個新創(chuàng)建的線程并不自動開始運行,要執(zhí)行線程,必須調(diào)用線程的start()方法。當(dāng)線程對象調(diào)用start()方法即啟動了線程,start()方法創(chuàng)建線程運行的系統(tǒng)資源,并調(diào)度線程運行run()方法。當(dāng)start()方法返回后,線程就處于就緒狀態(tài)。
處于就緒狀態(tài)的線程并不一定立即運行run()方法,線程還必須同其他線程競爭CPU時間,只有獲得CPU時間才可以運行線程。因為在單CPU的計算機系統(tǒng)中,不可能同時運行多個線程,一個時刻僅有一個線程處于運行狀態(tài)。因此此時可能有多個線程處于就緒狀態(tài)。對多個處于就緒狀態(tài)的線程是由Java運行時系統(tǒng)的線程調(diào)度程序(thread scheduler)來調(diào)度的。
運行狀態(tài):
當(dāng)線程獲得CPU時間后,它才進入運行狀態(tài),真正開始執(zhí)行run()方法.
阻塞狀態(tài):
線程運行過程中,可能由于各種原因進入阻塞狀態(tài):
1>線程通過調(diào)用sleep方法進入睡眠狀態(tài);
2>線程調(diào)用一個在I/O上被阻塞的操作,即該操作在輸入輸出操作完成之前不會返回到它的調(diào)用者;
3>線程試圖得到一個鎖,而該鎖正被其他線程持有;
4>線程在等待某個觸發(fā)條件;
死亡狀態(tài):
有兩個原因會導(dǎo)致線程死亡:
1> run方法正常退出而自然死亡,
2> 一個未捕獲的異常終止了run方法而使線程猝死。
為了確定線程在當(dāng)前是否存活著(就是要么是可運行的,要么是被阻塞了),需要使用isAlive方法。如果是可運行或被阻塞,這個方法返回true; 如果線程仍舊是new狀態(tài)且不是可運行的, 或者線程死亡了,則返回false.
如圖所示:
線程的創(chuàng)建方式:
繼承Thread
實現(xiàn)Runnable
匿名內(nèi)部類方式
上面只要會繼承THread類方法和實現(xiàn)Runnable接口這兩種就行,還有其他的線程池創(chuàng)建等等,在后面的章節(jié)說
迷惑問題
繼承THread類方法和實現(xiàn)Runnable接口 這兩種方式選擇哪一種好呢?
在java語言中,有一個特點,就是單繼承,多實現(xiàn)。實現(xiàn)了接口還可以繼續(xù)繼承,繼承了類不能再繼承。所以一般情況下使用實現(xiàn)Runnable會有更好的拓展性。
繼器啟動線程是調(diào)用run方法還是start方法
Run方法僅僅只是線程所要執(zhí)行的代碼塊部分,如果調(diào)用run方法,就和調(diào)用其他普通方法一樣,從上到下,順序執(zhí)行。沒有了多線程的特點。所以使用start方法使線程進入就緒狀態(tài)。
線程的分類:
用戶線程(也叫前臺線程):
用戶自定義創(chuàng)建的線程,用戶線程的狀態(tài)不受其他線程的影響。別的線程掛了就掛了,影響不到他,因為他們是互相獨立的。
守護線程(也叫后臺線程):
守護線程受用戶線程的影響,當(dāng)用戶線程銷毀后,守護線程也會跟著銷毀。比如GC
分享一波:程序員賺外快-必看的巔峰干貨
創(chuàng)作挑戰(zhàn)賽新人創(chuàng)作獎勵來咯,堅持創(chuàng)作打卡瓜分現(xiàn)金大獎總結(jié)
以上是生活随笔為你收集整理的白话说编程之java线程的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: idea中Error:java: Com
- 下一篇: 线程带来的风险