關于線程的那些事……

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

從這張圖中我們可以看出計算機的進程數、線程數等數據,這里的線程數就包括java軟件運行時的線程,另外,我們從這張圖還可以看出來,線程數遠遠大于進程數,這也從側面佐證了一個進程可以包含多個線程。
串行與并行
說到多線程就避不過串行和并行的話題,串行就是程序的每一行代碼依次執(zhí)行,在大多數的場景下,后面執(zhí)行的代碼,要依托于前面代碼的執(zhí)行結果,或者說是后面的代碼必須在前面的代碼執(zhí)行完成之后才能被執(zhí)行;而并行就是代碼直接沒有任何依賴關系,代碼與代碼之間也沒有任何的運行順序,兩段代碼可以同時運行,當然,這樣說雖然也不完全對,但也算說清楚了并行與串行的應用場景。
說了這么多,下面我們說一些干貨:
串行就是我們常說的單線程,必須按照指定的順序運行,所以效率低下,但同時卻可以確保順序 并行就是我們常說的多線程,線程與線程之間的執(zhí)行是沒有順序可言的,所以會存在線程安全問題,但是效率比較高
舉一個很形象的例子來說明并行和串行,假設你有十件事需要做,按照串行的方式的話,你必須得一件一件地做事,一件事沒有完成的時候,是不可以進行下一件事的;按照并行邏輯的話,你可以同時做這十件事,只要你有時間,你就可以選擇任意一件事來做,當然如果你要是會分身術的話,那就叫真并發(fā)運行了(這就特別類似單核CPU和多核CPU,單核的時候只能來回切換以提高利用效率,多核的時候就真的可以同時運行多個任務)
創(chuàng)建方式
關于線程的創(chuàng)建方式有三種,一種是直接通過繼承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();
????}
}
這種方式的缺點很明顯,因為在java中,一個類只能繼承一個類,所以如果一個類已經繼承了父類,它就再沒辦法通過繼承Thread來實現多線程了,于是就有了第二種方式——Runnable接口
Runnable
runnable接口就比Thread類要靈活的多,因為java的接口是運行多實現的,所以一個類實現了其他接口以后,依然可以實現Runnable接口:
public?class?RunnableDemo?extends?Observable?implements?Runnable?{
????@Override
????public?void?run()?{
????????System.out.println("我是繼承了Thread,并實現了Runnable的類");
????}
????public?static?void?main(String[]?args)?{
????????new?Thread(new?RunnableDemo()).start();
????}
}
但是runnable本身是沒法靠自己啟動的,它必須通過Thread或者線程池來啟動,如果直接調用run方法,也只能是像普通方法一樣執(zhí)行。
雖然Runable比Thread要靈活,它也能實現我們絕大多數的應用場景,但是在某些應用場景下,它也顯得很無能為力,比如run方法需要返回值,這時候callable應運而生。
Callable
相比于Thread和Runnable,Callable就是小萌新,因為它是JDK1.5才引入的,而前兩個是從JDK1.0就已經存在了:

由于比較萌新,所以Callable的運行方式也比較特殊,只能通過線程池啟動:
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);
????}
}
結語
單就線程的知識點來說,這塊還是比較簡單的,大多都是一些基礎的概念,但還是要扎實理解其中的一些要點,這里我們做一個簡單的梳理:
線程是程序運行的最小單元 線程可以理解為在進程中獨立運行的子任務 一個進程可以包含多個線程 多線程的特點是在同一時間執(zhí)行多個任務 多線程就是通過使用異步技術,提高處理器的利用效率
最后,希望各位小伙伴記住一句話:不要為了使用多線程而使用多線程,要結合實際業(yè)務場景分析。好了,今天就到這里吧,各位小伙伴,晚安吧!
- END -