更新時間:2020-07-30 15:53:45 來源:動力節(jié)點 瀏覽3542次
1、多線程有什么用?
一個可能在很多人看來很扯淡的一個問題:我會用多線程就好了,還管它有什么用?在我看來,這個回答更扯淡。所謂”知其然知其所以然”,”會用”只是”知其然”,”為什么用”才是”知其所以然”,只有達到”知其然知其所以然”的程度才可以說是把一個知識點運用自如。OK,下面說說我對這個問題的看法:
(1)發(fā)揮多核CPU的優(yōu)勢
隨著工業(yè)的進步,現(xiàn)在的筆記本、臺式機乃至商用的應用服務器至少也都是雙核的,4核、8核甚至16核的也都不少見,如果是單線程的程序,那么在雙核CPU上就浪費了50%,在4核CPU上就浪費了75%。單核CPU上所謂的”多線程”那是假的多線程,同一時間處理器只會處理一段邏輯,只不過線程之間切換得比較快,看著像多個線程”同時”運行罷了。多核CPU上的多線程才是真正的多線程,它能讓你的多段邏輯同時工作,多線程,可以真正發(fā)揮出多核CPU的優(yōu)勢來,達到充分利用CPU的目的。
(2)防止阻塞
從程序運行效率的角度來看,單核CPU不但不會發(fā)揮出多線程的優(yōu)勢,反而會因為在單核CPU上運行多線程導致線程上下文的切換,而降低程序整體的效率。但是單核CPU我們還是要應用多線程,就是為了防止阻塞。試想,如果單核CPU使用單線程,那么只要這個線程阻塞了,比方說遠程讀取某個數(shù)據(jù)吧,對端遲遲未返回又沒有設置超時時間,那么你的整個程序在數(shù)據(jù)返回回來之前就停止運行了。多線程可以防止這個問題,多條線程同時運行,哪怕一條線程的代碼執(zhí)行讀取數(shù)據(jù)阻塞,也不會影響其它任務的執(zhí)行。
(3)便于建模
這是另外一個沒有這么明顯的優(yōu)點了。假設有一個大的任務A,單線程編程,那么就要考慮很多,建立整個程序模型比較麻煩。但是如果把這個大的任務A分解成幾個小任務,任務B、任務C、任務D,分別建立程序模型,并通過多線程分別運行這幾個任務,那就簡單很多了。
2、創(chuàng)建線程的方式
比較常見的一個問題了,一般就是兩種:
(1)繼承Thread類
(2)實現(xiàn)Runnable接口
至于哪個好,不用說肯定是后者好,因為實現(xiàn)接口的方式比繼承類的方式更靈活,也能減少程序之間的耦合度,面向接口編程也是設計模式6大原則的核心。
3、start()方法和run()方法的區(qū)別
只有調(diào)用了start()方法,才會表現(xiàn)出多線程的特性,不同線程的run()方法里面的代碼交替執(zhí)行。如果只是調(diào)用run()方法,那么代碼還是同步執(zhí)行的,必須等待一個線程的run()方法里面的代碼全部執(zhí)行完畢之后,另外一個線程才可以執(zhí)行其run()方法里面的代碼。
4、Runnable接口和Callable接口的區(qū)別
有點深的問題了,也看出一個Java程序員學習知識的廣度。
Runnable接口中的run()方法的返回值是void,它做的事情只是純粹地去執(zhí)行run()方法中的代碼而已;Callable接口中的call()方法是有返回值的,是一個泛型,和Future、FutureTask配合可以用來獲取異步執(zhí)行的結(jié)果。
這其實是很有用的一個特性,因為多線程相比單線程更難、更復雜的一個重要原因就是因為多線程充滿著未知性,某條線程是否執(zhí)行了?某條線程執(zhí)行了多久?某條線程執(zhí)行的時候我們期望的數(shù)據(jù)是否已經(jīng)賦值完畢?無法得知,我們能做的只是等待這條多線程的任務執(zhí)行完畢而已。而Callable+Future/FutureTask卻可以獲取多線程運行的結(jié)果,可以在等待時間太長沒獲取到需要的數(shù)據(jù)的情況下取消該線程的任務,真的是非常有用。
5、CyclicBarrier和CountDownLatch的區(qū)別
兩個看上去有點像的類,都在java.util.concurrent下,都可以用來表示代碼運行到某個點上,二者的區(qū)別在于:
(1)CyclicBarrier的某個線程運行到某個點上之后,該線程即停止運行,直到所有的線程都到達了這個點,所有線程才重新運行;CountDownLatch則不是,某線程運行到某個點上之后,只是給某個數(shù)值-1而已,該線程繼續(xù)運行
(2)CyclicBarrier只能喚起一個任務,CountDownLatch可以喚起多個任務
(3)CyclicBarrier可重用,CountDownLatch不可重用,計數(shù)值為0該CountDownLatch就不可再用了
6、volatile關鍵字的作用
一個非常重要的問題,是每個學習、應用多線程的Java程序員都必須掌握的。理解volatile關鍵字的作用的前提是要理解Java內(nèi)存模型,這里就不講Java內(nèi)存模型了,可以參見第31點,volatile關鍵字的作用主要有兩個:
(1)多線程主要圍繞可見性和原子性兩個特性而展開,使用volatile關鍵字修飾的變量,保證了其在多線程之間的可見性,即每次讀取到volatile變量,一定是最新的數(shù)據(jù)
(2)代碼底層執(zhí)行不像我們看到的高級語言—-Java程序這么簡單,它的執(zhí)行是Java代碼–>字節(jié)碼–>根據(jù)字節(jié)碼執(zhí)行對應的C/C++代碼–>C/C++代碼被編譯成匯編語言–>和硬件電路交互,現(xiàn)實中,為了獲取更好的性能JVM可能會對指令進行重排序,多線程下可能會出現(xiàn)一些意想不到的問題。使用volatile則會對禁止語義重排序,當然這也一定程度上降低了代碼執(zhí)行效率
從實踐角度而言,volatile的一個重要作用就是和CAS結(jié)合,保證了原子性,詳細的可以參見java.util.concurrent.atomic包下的類,比如AtomicInteger。
以上就是動力節(jié)點java培訓機構(gòu)的小編針對“常用到的Java多線程編程練習題”的內(nèi)容進行的回答,希望對大家有所幫助,如有疑問,請在線咨詢,有專業(yè)老師隨時為你服務。