一、怎么防止死鎖?
死鎖的四個必要條件:
互斥條件:進程對所分配到的資源不允許其他進程進行訪問,若其他進程訪問該資源,只能等待,直至占有該資源的進程使用完成后釋放該資源
請求和保持條件:進程獲得一定的資源之后,又對其他資源發(fā)出請求,但是該資源可能被其他進程占有,此事請求阻塞,但又對自己獲得的資源保持不放
不可剝奪條件:是指進程已獲得的資源,在未完成使用之前,不可被剝奪,只能在使用完后自己釋放
環(huán)路等待條件:是指進程發(fā)生死鎖后,若干進程之間形成一種頭尾相接的循環(huán)等待資源關(guān)系
這四個條件是死鎖的必要條件,只要系統(tǒng)發(fā)生死鎖,這些條件必然成立,而只要上述條件之 一不滿足,就不會發(fā)生死鎖。
理解了死鎖的原因,尤其是產(chǎn)生死鎖的四個必要條件,就可以最大可能地避免、預(yù)防和解除死鎖。
所以,在系統(tǒng)設(shè)計、進程調(diào)度等方面注意如何不讓這四個必要條件成立,如何確 定資源的合理分配算法,避免進程永久占據(jù)系統(tǒng)資源。
此外,也要防止進程在處于等待狀態(tài)的情況下占用資源。因此,對資源的分配要給予合理的規(guī)劃。
(視頻教程推薦:java視頻)
二、ThreadLocal 是什么?有哪些使用場景?
線程局部變量是局限于線程內(nèi)部的變量,屬于線程自身所有,不在多個線程間共享。Java提供ThreadLocal類來支持線程局部變量,是一種實現(xiàn)線程安全的方式。但是在管理環(huán)境下(如 web 服務(wù)器)使用線程局部變量的時候要特別小心,在這種情況下,工作線程的生命周期比任何應(yīng)用變量的生命周期都要長。任何線程局部變量一旦在工作完成后沒有釋放,Java 應(yīng)用就存在內(nèi)存泄露的風險。
三、說一下 synchronized 底層實現(xiàn)原理?
synchronized可以保證方法或者代碼塊在運行時,同一時刻只有一個方法可以進入到臨界區(qū),同時它還可以保證共享變量的內(nèi)存可見性。
Java中每一個對象都可以作為鎖,這是synchronized實現(xiàn)同步的基礎(chǔ):
普通同步方法,鎖是當前實例對象
靜態(tài)同步方法,鎖是當前類的class對象
同步方法塊,鎖是括號里面的對象
四、synchronized 和 volatile 的區(qū)別是什么?
volatile本質(zhì)是在告訴jvm當前變量在寄存器(工作內(nèi)存)中的值是不確定的,需要從主存中讀?。?synchronized則是鎖定當前變量,只有當前線程可以訪問該變量,其他線程被阻塞住。
volatile僅能使用在變量級別;synchronized則可以使用在變量、方法、和類級別的。
volatile僅能實現(xiàn)變量的修改可見性,不能保證原子性;而synchronized則可以保證變量的修改可見性和原子性。
volatile不會造成線程的阻塞;synchronized可能會造成線程的阻塞。
volatile標記的變量不會被編譯器優(yōu)化;synchronized標記的變量可以被編譯器優(yōu)化。
五、synchronized 和 Lock 有什么區(qū)別?
首先synchronized是java內(nèi)置關(guān)鍵字,在jvm層面,Lock是個java類;
synchronized無法判斷是否獲取鎖的狀態(tài),Lock可以判斷是否獲取到鎖;
synchronized會自動釋放鎖(a 線程執(zhí)行完同步代碼會釋放鎖 ;b 線程執(zhí)行過程中發(fā)生異常會釋放鎖),Lock需在finally中手工釋放鎖(unlock()方法釋放鎖),否則容易造成線程死鎖;
用synchronized關(guān)鍵字的兩個線程1和線程2,如果當前線程1獲得鎖,線程2線程等待。如果線程1阻塞,線程2則會一直等待下去,而Lock鎖就不一定會等待下去,如果嘗試獲取不到鎖,線程可以不用一直等待就結(jié)束了;
synchronized的鎖可重入、不可中斷、非公平,而Lock鎖可重入、可判斷、可公平(兩者皆可);
Lock鎖適合大量同步的代碼的同步問題,synchronized鎖適合代碼少量的同步問題。
(相關(guān)教程推薦:java開發(fā)入門)
六、synchronized 和 ReentrantLock 區(qū)別是什么?
synchronized是和if、else、for、while一樣的關(guān)鍵字,ReentrantLock是類,這是二者的本質(zhì)區(qū)別。既然ReentrantLock是類,那么它就提供了比synchronized