Spring中的Bean預設是單例還是多例?如何保證併發安全?
程序(Process):
獨佔資源的程式執行單位,每個獨立執行的程式都對應一個程序,程序指正在執行的程式。確切的來說,當一個程式進入記憶體執行,即變成一個程序,程序是處於執行過程中的程式,並且具有一定獨立功能。
執行緒(Thread):
執行緒是程序中的一個執行單元,負責當前程序中程式的執行,一個程序中至少有一個執行緒。一個程序中是可以有多個執行緒的,這個應用程式也可以稱之為多執行緒程式。
二者區別:
一個程式執行後至少有一個程序,一個程序中可以包含多個執行緒
有三種方式可以用來建立執行緒:
繼承Thread類
實現Runnable介面
應用程式可以使用Executor框架來建立執行緒池
實現Runnable介面這種方式更受歡迎,因為這不需要繼承Thread類。在應用設計中已經繼承了別的物件的情況下,這需要多繼承(而Java不支援多繼承),只能實現介面。同時,執行緒池也是非常高效的,很容易實現和使用。
什麼是死鎖(deadlock)?
死鎖概念及產生原理
概念:多個併發程序因爭奪系統資源而產生相互等待的現象。
原理:當一組程序中的每個程序都在等待某個事件發生,而只有這組程序中的其他程序才能觸發該事件,這就稱這組程序發生了死鎖。
本質原因:
1)、系統資源有限。
2)、程序推進順序不合理。
如何確保N個執行緒可以訪問N個資源同時又不導致死鎖?
使用多執行緒的時候,一種非常簡單的避免死鎖的方式就是:指定獲取鎖的順序,並強制執行緒按照指定的順序獲取鎖。因此,如果所有的執行緒都是以同樣的順序加鎖和釋放鎖,就不會出現死鎖了。
死鎖產生的4個必要條件(全部滿足才會造成死鎖)
1、互斥:某種資源一次只允許一個程序訪問,即該資源一旦分配給某個程序,其他程序就不能再訪問,直到該程序訪問結束。
2、佔有且等待:一個程序本身佔有資源(一種或多種),同時還有資源未得到滿足,正在等待其他程序釋放該資源。
3、不可搶佔:別人已經佔有了某項資源,你不能因為自己也需要該資源,就去把別人的資源搶過來。
4、迴圈等待:存在一個程序鏈,使得每個程序都佔有下一個程序所需的至少一種資源。
避免死鎖的方法
1、死鎖預防 ----- 確保系統永遠不會進入死鎖狀態
產生死鎖需要四個條件,那麼,只要這四個條件中至少有一個條件得不到滿足,就不可能發生死鎖了。由於互斥條件是非共享資源所必須的,不僅不能改變,還應加以保證,所以,主要是破壞產生死鎖的其他三個條件。
A、破壞“佔有且等待”條件
B、破壞“不可搶佔”條件
C、破壞“迴圈等待”條件
2、避免死鎖 ----- 在使用前進行判斷,只允許不會產生死鎖的程序申請資源
死鎖避免是利用額外的檢驗資訊,在分配資源時判斷是否會出現死鎖,只在不會出現死鎖的情況下才分配資源。
兩種避免辦法:
1、如果一個程序的請求會導致死鎖,則不啟動該程序
2、如果一個程序的增加資源請求會導致死鎖 ,則拒絕該申請。
避免死鎖的具體實現通常利用銀行家演算法
死鎖避免的優點:
不需要死鎖預防中的搶佔和重新執行程序,並且比死鎖預防的限制要少。
死鎖避免的限制:
必須事先宣告每個程序請求的最大資源量
考慮的程序必須無關的,也就是說,它們執行的順序必須沒有任何同步要求的限制
分配的資源數目必須是固定的。
在佔有資源時,程序不能退出
死鎖的解除
1、搶佔資源:從一個或多個程序中搶佔足夠數量的資源分配給死鎖程序,以解除死鎖狀態。
2、終止(或撤銷)程序:終止或撤銷系統中的一個或多個死鎖程序,直至打破死鎖狀態。
a、終止所有的死鎖程序。這種方式簡單粗暴,但是代價很大,很有可能會導致一些已經運行了很久的程序前功盡棄。
b、逐個終止程序,直至死鎖狀態解除。該方法的代價也很大,因為每終止一個程序就需要使用死鎖檢測來檢測系統當前是否處於死鎖狀態。
執行緒排程的兩種方式
執行緒排程是指按照特定機制為多個執行緒分配CPU的使用權.
分時排程:所有執行緒輪流使用 CPU 的使用權,平均分配每個執行緒佔用 CPU 的時間。
搶佔式排程:優先讓優先順序高的執行緒使用 CPU,如果執行緒的優先順序相同,那麼會隨機選擇一個(執行緒隨機性),java虛擬機器採用搶佔式排程模型。
執行緒生命週期
即執行緒在JVM中執行經歷的過程,經歷五個階段:建立、就緒、執行、阻塞、終止。
Sleep() 和wait() 有什麼區別?
sleep 是執行緒類(Thread)的方法,導致此執行緒暫停執行指定時間,把執行機會給其他執行緒,但是監控狀態依然保持,到時後會自動恢復。呼叫sleep 不會釋放物件鎖。wait 是Object 類的方法,對此物件呼叫wait 方法導致本執行緒放棄物件鎖,進入等待此物件的等待鎖定池,只有針對此物件發出notify 方法(或notifyAll)後本執行緒才進入物件鎖定池準備獲得物件鎖進入執行狀態。
什麼是執行緒池
執行緒池 ,其實就是一個容納多個執行緒的容器,其中的執行緒可以反覆使用,省去了頻繁建立執行緒物件的操作,無需反覆建立執行緒而消耗過多資源。