關(guān)于線程的那些事……

前言
從今天開始我們要再次重新學(xué)習(xí)多線程的相關(guān)內(nèi)容,至于為什么要學(xué)習(xí)多線程,原因很簡(jiǎn)單,java是一門流行的web端開發(fā)語(yǔ)言,而web應(yīng)用中有一個(gè)核心的要素就是效率,也就是快速響應(yīng)用戶的需求,但是隨著業(yè)務(wù)的不斷發(fā)展,業(yè)務(wù)環(huán)境的復(fù)雜化,單一流程的應(yīng)用很難滿足高效率的需求,所以多線程就有了用武之地。
線程
基本知識(shí)點(diǎn)
什么是線程
線程是進(jìn)程中獨(dú)立運(yùn)行的子任務(wù),也是程序運(yùn)行的最小單位。通常情況下,一個(gè)進(jìn)程可以包括多個(gè)線程。如果你有仔細(xì)觀察過(guò)電腦任務(wù)管理的詳細(xì)信息的話,你一定對(duì)下面這張圖片不陌生:

從這張圖中我們可以看出計(jì)算機(jī)的進(jìn)程數(shù)、線程數(shù)等數(shù)據(jù),這里的線程數(shù)就包括java軟件運(yùn)行時(shí)的線程,另外,我們從這張圖還可以看出來(lái),線程數(shù)遠(yuǎn)遠(yuǎn)大于進(jìn)程數(shù),這也從側(cè)面佐證了一個(gè)進(jìn)程可以包含多個(gè)線程。
串行與并行
說(shuō)到多線程就避不過(guò)串行和并行的話題,串行就是程序的每一行代碼依次執(zhí)行,在大多數(shù)的場(chǎng)景下,后面執(zhí)行的代碼,要依托于前面代碼的執(zhí)行結(jié)果,或者說(shuō)是后面的代碼必須在前面的代碼執(zhí)行完成之后才能被執(zhí)行;而并行就是代碼直接沒(méi)有任何依賴關(guān)系,代碼與代碼之間也沒(méi)有任何的運(yùn)行順序,兩段代碼可以同時(shí)運(yùn)行,當(dāng)然,這樣說(shuō)雖然也不完全對(duì),但也算說(shuō)清楚了并行與串行的應(yīng)用場(chǎng)景。
說(shuō)了這么多,下面我們說(shuō)一些干貨:
串行就是我們常說(shuō)的單線程,必須按照指定的順序運(yùn)行,所以效率低下,但同時(shí)卻可以確保順序 并行就是我們常說(shuō)的多線程,線程與線程之間的執(zhí)行是沒(méi)有順序可言的,所以會(huì)存在線程安全問(wèn)題,但是效率比較高
舉一個(gè)很形象的例子來(lái)說(shuō)明并行和串行,假設(shè)你有十件事需要做,按照串行的方式的話,你必須得一件一件地做事,一件事沒(méi)有完成的時(shí)候,是不可以進(jìn)行下一件事的;按照并行邏輯的話,你可以同時(shí)做這十件事,只要你有時(shí)間,你就可以選擇任意一件事來(lái)做,當(dāng)然如果你要是會(huì)分身術(shù)的話,那就叫真并發(fā)運(yùn)行了(這就特別類似單核CPU和多核CPU,單核的時(shí)候只能來(lái)回切換以提高利用效率,多核的時(shí)候就真的可以同時(shí)運(yùn)行多個(gè)任務(wù))
創(chuàng)建方式
關(guān)于線程的創(chuàng)建方式有三種,一種是直接通過(guò)繼承Thread類的方式。
Thread
這也是最原始的創(chuàng)建方式:
public?class?MyThread?extends?Thread?{
????@Override
????public?void?run()?{
????????System.out.println("run?方法開始執(zhí)行了");
????}
????public?static?void?main(String[]?args)?{
????????new?MyThread().start();
????}
}
這種方式的缺點(diǎn)很明顯,因?yàn)樵?code style="overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(255, 100, 65);">java中,一個(gè)類只能繼承一個(gè)類,所以如果一個(gè)類已經(jīng)繼承了父類,它就再?zèng)]辦法通過(guò)繼承Thread來(lái)實(shí)現(xiàn)多線程了,于是就有了第二種方式——Runnable接口
Runnable
runnable接口就比Thread類要靈活的多,因?yàn)?code style="overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(255, 100, 65);">java的接口是運(yùn)行多實(shí)現(xiàn)的,所以一個(gè)類實(shí)現(xiàn)了其他接口以后,依然可以實(shí)現(xiàn)Runnable接口:
public?class?RunnableDemo?extends?Observable?implements?Runnable?{
????@Override
????public?void?run()?{
????????System.out.println("我是繼承了Thread,并實(shí)現(xiàn)了Runnable的類");
????}
????public?static?void?main(String[]?args)?{
????????new?Thread(new?RunnableDemo()).start();
????}
}
但是runnable本身是沒(méi)法靠自己?jiǎn)?dòng)的,它必須通過(guò)Thread或者線程池來(lái)啟動(dòng),如果直接調(diào)用run方法,也只能是像普通方法一樣執(zhí)行。
雖然Runable比Thread要靈活,它也能實(shí)現(xiàn)我們絕大多數(shù)的應(yīng)用場(chǎng)景,但是在某些應(yīng)用場(chǎng)景下,它也顯得很無(wú)能為力,比如run方法需要返回值,這時(shí)候callable應(yīng)運(yùn)而生。
Callable
相比于Thread和Runnable,Callable就是小萌新,因?yàn)樗?code style="overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(255, 100, 65);">JDK1.5才引入的,而前兩個(gè)是從JDK1.0就已經(jīng)存在了:

由于比較萌新,所以Callable的運(yùn)行方式也比較特殊,只能通過(guò)線程池啟動(dòng):
public?class?CallableDemo?implements?Callable<String>?{
????@Override
????public?String?call()?throws?Exception?{
????????return?"hello?callable";
????}
????public?static?void?main(String[]?args)?throws?ExecutionException,?InterruptedException?{
????????Future?submit?=?Executors.newSingleThreadExecutor().submit(new?CallableDemo());
????????String?s?=?submit.get();
????????System.out.println(s);
????}
}
結(jié)語(yǔ)
單就線程的知識(shí)點(diǎn)來(lái)說(shuō),這塊還是比較簡(jiǎn)單的,大多都是一些基礎(chǔ)的概念,但還是要扎實(shí)理解其中的一些要點(diǎn),這里我們做一個(gè)簡(jiǎn)單的梳理:
線程是程序運(yùn)行的最小單元 線程可以理解為在進(jìn)程中獨(dú)立運(yùn)行的子任務(wù) 一個(gè)進(jìn)程可以包含多個(gè)線程 多線程的特點(diǎn)是在同一時(shí)間執(zhí)行多個(gè)任務(wù) 多線程就是通過(guò)使用異步技術(shù),提高處理器的利用效率
最后,希望各位小伙伴記住一句話:不要為了使用多線程而使用多線程,要結(jié)合實(shí)際業(yè)務(wù)場(chǎng)景分析。好了,今天就到這里吧,各位小伙伴,晚安吧!
- END -