synchronized [ˈsɪŋkrənaɪzd] v.同步 35. 並行和併發有什麼區別? 36. 進程和線程的區別? 37. 守護線程是什麼? 38. 建立線程有哪幾種方式? 39. 說一下 runnable 和 callable 有什麼區別? 40. 線程有哪些狀態? 41. sleep() 和 wait() 有什麼區別? 42. notify()和 notifyAll()有什麼區別? 43. 線程的 run()和 start()有什麼區別? 44. 建立線程池有哪幾種方式? 45. 線程池都有哪些狀態? 46. 線程池中 submit()和 execute()方法有什麼區別? 47. 在 java 程序中怎麼保證多線程的運行安全?(synchronized,happens-before原則) 48. 多線程鎖的升級原理是什麼? 49. 什麼是死鎖? 50. 怎麼防止死鎖?(死鎖的四個必要條件) 51. ThreadLocal 是什麼?有哪些使用場景? 52.說一下 synchronized 底層實現原理? 53. synchronized 和 volatile 的區別是什麼? 54. synchronized 和 Lock 有什麼區別? 55. synchronized 和 ReentrantLock 區別是什麼? 56. 說一下 atomic 的原理?
多線程java
35. 並行和併發有什麼區別?程序員
因此併發編程的目標是充分的利用處理器的每個核,以達到醉高的處理性能。算法
36. 進程和線程的區別?編程
簡而言之,進程是程序運行和資源分配的基本單位,一個程序至少有一個進程,一個進程至少有一個或多個線程。進程在執行過程當中擁有獨li的內存單元,而多個線程共享內存資源,減小切換次數,從而效率更高。線程是進程的一個實體,同一進程中的多個線程之間能夠併發執行,是cpu調度和分派的基本單位,是比程序更小的能獨li運行的基本單位。緩存
37. 守護線程是什麼?安全
守護線程(即daemon thread),是個服務線程,準確地來講就是服務其餘的線程,這是它的做用——而其餘的線程只有一種,那就是用戶線程。因此java裏線程分2種,
一、守護線程,好比垃圾回收線程,就是最典型的守護線程。
二、用戶線程,就是應用程序裏的自定義線程。
當全部非守護線程結束時,沒有了被守護者,守護線程也就沒有工做可作了,也就沒有繼續運行程序的必要了,程序也就終止了,同時會傻死全部守護線程。 也就是說,只要有任何非守護線程還在運行,程序就不會終止。多線程
38. 建立線程有哪幾種方式?併發
①. 繼承Thread類建立線程類app
public class FirstThreadTest extends Thread { int i=0 //重寫run方法,run方法的方法體就是線程執行體 public void run() { for (; i < 100; i++) { System.out.println(getName() + ":" + i); } } public static void main(String[] args) { for (int i = 0; i < 100; i++) { //Thread.currentThread()方法返回當前正在執行的線程對象。 //GetName()方法返回調用該方法的線程的名字。 System.out.println(Thread.currentThread().getName() + ":" + i); if (i == 50) { //建立Thread子類的實例,即建立了線程對象 new FirstThreadTest().start(); new FirstThreadTest().start(); } } }
②. 經過Runnable接口建立線程類異步
public class RunnableThreadTest implements Runnable{ private int i; public void run(){ for(i = 0;i <100;i++) { System.out.println(Thread.currentThread().getName()+":"+i); } } public static void main(String[] args) { for(int i = 0;i < 100;i++) { System.out.println(Thread.currentThread().getName()+":"+i); if(i==20){ //建立 Runnable接口實現類的實例 RunnableThreadTest rtt = new RunnableThreadTest(); new Thread(rtt,"新線程1").start(); new Thread(rtt,"新線程2").start(); } } } }
③. 經過Callable和Future建立線程
package com.nf147.Constroller; import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; import java.util.concurrent.FutureTask; public class CallableThreadTest implements Callable<Integer> { public static void main(String[] args) { CallableThreadTest ctt = new CallableThreadTest(); FutureTask<Integer> ft = new FutureTask<>(ctt); for (int i = 0; i < 100; i++) { System.out.println(Thread.currentThread().getName() + " 的循環變量i的值" + i); if (i == 20) { new Thread(ft, "有返回值的線程").start(); } } try { System.out.println("子線程的返回值:" + ft.get()); } catch (InterruptedException e) { e.printStackTrace(); } catch (ExecutionException e) { e.printStackTrace(); } } //重寫call()方法,該call()方法將做爲線程執行體,而且有返回值 @Override public Integer call() throws Exception { int i = 0; for (; i < 100; i++) { System.out.println(Thread.currentThread().getName() + " " + i); } return i; } }
建立線程的三種方式的對比
採用實現Runnable、Callable接口的方式建立多線程時,優點是:
線程類只是實現了Runnable接口或Callable接口,還能夠繼承其餘類。
在這種方式下,多個線程能夠共享同一個目標對象,因此很是適合多個相同線程來處理同一份資源的狀況,從而能夠將CPU、代碼和數據分開,造成清晰的模型,較好地體現了面向對象的思想
39. 說一下 runnable 和 callable 有什麼區別?
有點深的問題了,也看出一個Java程序員學習知識的廣度。
40. 線程有哪些狀態?
線程一般都有五種狀態,建立、就緒、運行、阻塞和死亡。
41. sleep() 和 wait() 有什麼區別?
sleep():方法是線程類(Thread)的靜態方法,讓調用線程進入睡眠狀態,讓出執行機會給其餘線程,等到休眠時間結束後,線程進入就緒狀態和其餘線程一塊兒競爭cpu的執行時間。由於sleep() 是static靜態的方法,他不能改變對象的機鎖,當一個synchronized塊中調用了sleep() 方法,線程雖然進入休眠,可是對象的機鎖沒有被釋放,其餘線程依然沒法訪問這個對象。
wait():wait()是Object類的方法,當一個線程執行到wait方法時,它就進入到一個和該對象相關的等待池,同時釋放對象的機鎖,使得其餘線程可以訪問,能夠經過notify,notifyAll方法來喚醒等待的線程
42. notify()和 notifyAll()有什麼區別?
43. 線程的 run()和 start()有什麼區別?
每一個線程都是經過某個特定Thread對象所對應的方法run()來完成其操做的,方法run()稱爲線程體。經過調用Thread類的start()方法來啓動一個線程。
start()方法來啓動一個線程,真正實現了多線程運行。這時無需等待run方法體代碼執行完畢,能夠直接繼續執行下面的代碼; 這時此線程是處於就緒狀態, 並無運行。 而後經過此Thread類調用方法run()來完成其運行狀態, 這裏方法run()稱爲線程體,它包含了要執行的這個線程的內容, Run方法運行結束, 此線程終止。而後CPU再調度其它線程。
run()方法是在本線程裏的,只是線程裏的一個函數,而不是多線程的。 若是直接調用run(),其實就至關因而調用了一個普通函數而已,直接待用run()方法必須等待run()方法執行完畢才能執行下面的代碼,因此執行路徑仍是隻有一條,根本就沒有線程的特徵,因此在多線程執行時要使用start()方法而不是run()方法。
44. 建立線程池有哪幾種方式?
①. newFixedThreadPool(int nThreads)
建立一個固定長度的線程池,每當提交一個任務就建立一個線程,直到達到線程池的最達數量,這時線程規模將再也不變化,當線程發生未預期的錯誤而結束時,線程池會補充一個新的線程。
②. newCachedThreadPool()
建立一個可緩存的線程池,若是線程池的規模超過了處理需求,將自動回收空閒線程,而當需求增長時,則能夠自動添加新線程,線程池的規模不存在任何限zhi。
③. newSingleThreadExecutor()
這是一個單線程的Executor,它建立單個工做線程來執行任務,若是這個線程異常結束,會建立一個新的來替代它;它的特色是能確保依照任務在隊列中的順序來串行執行。
④. newScheduledThreadPool(int corePoolSize)
建立了一個固定長度的線程池,並且以延遲或定時的方式來執行任務,相似於Timer。
45. 線程池都有哪些狀態?
線程池有5種狀態:Running、ShutDown(中止)、Stop、Tidying(整理)、Terminated(終止)。
線程池在 ShutDown 狀態,任務隊列爲空且執行中任務爲空,線程池就會由 ShutDown 轉變爲 TIDYING 狀態。
線程池在 Stop 狀態,線程池中執行中任務爲空時,就會由 Stop 轉變爲 Tidying 狀態。
46. 線程池中 submit()和 execute()方法有什麼區別?
47. 在 java 程序中怎麼保證多線程的運行安全?
線程安全在三個方面體現:
解決辦法:
Happens-Before 規則以下:
48. 多線程鎖的升級原理是什麼?
在Java中,鎖共有4種狀態,級別從低到高依次爲:無鎖,偏向鎖,輕量級鎖和重量級鎖狀態,這幾個狀態會隨着競爭狀況逐漸升級。鎖能夠升級但不能降級。
無鎖:沒有對資源進行鎖定,全部的線程都能訪問並修改同一個資源,但同時只有一個線程能修改爲功,其餘修改失敗的線程會不斷重試直到修改爲功。
偏向鎖:對象的代碼一直被同一線程執行,不存在多個線程競爭,該線程在後續的執行中自動獲取偏向鎖,指的就是偏向第1個加鎖線程,該線程是不會主動釋放偏向鎖的,只有當其餘線程嘗試競爭偏向鎖纔會被釋放。
偏向鎖的撤銷,須要在某個時間點上沒有字節碼正在執行時,先暫停擁有偏向鎖的線程,而後判斷鎖對象是否處於被鎖定狀態。若是線程不處於活動狀態,則將對象頭設置成無鎖狀態,並撤銷偏向鎖;
若是線程處於活動狀態,升級爲輕量級鎖的狀態。
輕量級鎖:輕量級鎖是指當鎖是偏向鎖的時候,被第2個線程 B 所訪問,此時偏向鎖就會升級爲輕量級鎖.
線程 B 會經過自旋的形式嘗試獲取鎖,線程不會阻塞,從而提升性能。當前只有一個等待線程,則該線程將經過自旋進行等待。
可是當自旋超過必定的次數時,輕量級鎖便會升級爲重量級鎖;當一個線程已持有鎖,另外一個線程在自旋,而此時又有第三個線程來訪時,輕量級鎖也會升級爲重量級鎖。
重量級鎖:指當有一個線程獲取鎖以後,其他全部等待獲取該鎖的線程都會處於阻塞狀態。操做系統實現線程之間的切換須要從用戶態切換到內核態,切換成本很是高。
鎖升級的圖示過程:
49. 什麼是死鎖?
死鎖是指兩個或兩個以上的進程在執行過程當中,因爲競爭資源或者因爲彼此通訊而形成的一種阻塞的現象,若無外力做用,它們都將沒法推動下去。此時稱系統處於死鎖狀態或系統產生了死鎖,這些永遠在互相等待的進程稱爲死鎖進程。是操做系統層面的一個錯誤,是進程死鎖的簡稱,最先在 1965 年由 Dijkstra 在研究銀行家算法時提出的,它是計算機操做系統乃至整個併發程序設計領域最難處理的問題之一。
50. 怎麼防止死鎖?
死鎖的四個必要條件:
這四個條件是死鎖的必要條件,只要系統發生死鎖,這些條件必然成立,而只要上述條件之一不知足,就不會發生死鎖。
理解了死鎖的緣由,尤爲是產生死鎖的四個必要條件,就能夠儘量地避免、預防和 解除死鎖。
因此,在系統設計、進程調度等方面注意如何不讓這四個必要條件成立,如何確 定資源的合理分配算法,避免進程永jiu佔據系統資源。
此外,也要防止進程在處於等待狀態的狀況下佔用資源。所以,對資源的分配要給予合理的規劃。
51. ThreadLocal 是什麼?有哪些使用場景?
Java提供ThreadLocal類來支持線程局部變量,是一種實現線程安全的方式。任何線程局部變量一旦在工做完成後沒有釋放,Java 應用就存在內存泄露的風險。
threadlocal而是一個線程內部的存儲類,能夠在指定線程內存儲數據,數據存儲之後,只有指定線程能夠獲得存儲數據
大體意思就是ThreadLocal提供了線程內存儲變量的能力,這些變量不一樣之處在於每個線程讀取的變量是對應的互相獨li的。經過get和set方法就能夠獲得當前線程對應的值。
ThreadLocal和Synchronized都是爲了解決多線程中相同變量的訪問衝突問題,不一樣的點是
52.說一下 synchronized 底層實現原理?
synchronized能夠保證方法或者代碼塊在運行時,同一時刻只有一個方法能夠進入到臨界區,同時它還能夠保證共享變量的內存可見性。
Java中每個對象均可以做爲鎖,這是synchronized實現同步的基礎:
jvm基於進入和退出Monitor對象來實現方法同步和代碼塊同步
這裏要注意:
public class SynchronizedDemo { public synchronized void f(){ //爲方法加鎖 System.out.println("Hello world"); } public void g(){ synchronized (this){ //爲代碼塊加鎖 System.out.println("Hello world"); } } public static void main(String[] args) { } }
53. synchronized 和 volatile 的區別是什麼?
volatile([ˈvɑːlətl] adj.不穩定的)
54. synchronized 和 Lock 有什麼區別?
55. synchronized 和 ReentrantLock 區別是什麼?
synchronized是和if、else、for、while同樣的關鍵字,ReentrantLock是類,這是兩者的本質區別。既然ReentrantLock是類,那麼它就提供了比synchronized更多更靈活的特性,能夠被繼承、能夠有方法、能夠有各類各樣的類變量,ReentrantLock比synchronized的擴展性體如今幾點上:
另外,兩者的鎖機制其實也是不同的:ReentrantLock底層調用的是Unsafe的park方法加鎖,synchronized操做的應該是對象頭中mark word。
56. 說一下 atomic 的原理?
Atomic包中的類基本的特性就是在多線程環境下,當有多個線程同時對單個(包括基本類型及引用類型)變量進行操做時,具備排他性,即當多個線程同時對該變量的值進行更新時,僅有一個線程能成功,而未成功的線程能夠向自旋鎖同樣,繼續嘗試,一直等到執行成功。
Atomic系列的類中的核心方法都會調用unsafe類中的幾個本地方法。咱們須要先知道一個東西就是Unsafe類,全名爲:sun.misc.Unsafe,這個類包含了大量的對C代碼的操做,包括不少直接內存分配以及原子操做的調用,而它之因此標記爲非安全的,是告訴你這個裏面大量的方法調用都會存在安全隱患,須要當心使用,不然會致使嚴重的後果,例如在經過unsafe分配內存的時候,若是本身指定某些區域可能會致使一些相似C++同樣的指針越界到其餘進程的問題。