前言
本來想著給自己放鬆一下,刷刷部落格,突然被幾道面試題難倒!說一說自己對於 synchronized 關鍵字的瞭解?說說自己是怎麼使用 synchronized 關鍵字?什麼是執行緒安全?Vector是一個執行緒安全類嗎?volatile關鍵字的作用?似乎有點模糊了,那就大概看一下面試題吧。好記性不如爛鍵盤
*** 12萬字的java面試題整理 ***
*** java核心面試知識整理 ***
*** Java高頻面試講解(知識涵蓋齊全) ***
說一說自己對於 synchronized 關鍵字的瞭解?
synchronized關鍵字解決的是多個執行緒之間訪問資源的同步性,synchronized關鍵字可以保證被它修飾的方法或者程式碼塊在任意時刻只能有一個執行緒執行。
另外,在 Java 早期版本中,synchronized屬於重量級鎖,效率低下,因為監視器鎖(monitor)是依賴於底層的作業系統的Mutex Lock 來實現的,Java 的執行緒是對映到作業系統的原生執行緒之上的。如果要掛起或者喚醒一個執行緒,都需要作業系統幫忙完成,而作業系統實現執行緒之間的切換時需要從使用者態轉換到核心態,這個狀態之間的轉換需要相對比較長的時間,時間成本相對較高,這也是為什麼早期的synchronized 效率低的原因。
慶幸的是在 Java 6 之後 Java 官方對從 JVM 層面對synchronized 較大最佳化,所以現在的 synchronized 鎖效率也最佳化得很不錯了。JDK1.6對鎖的實現引入了大量的最佳化,如自旋鎖、適應性自旋鎖、鎖消除、鎖粗化、偏向鎖、輕量級鎖等技術來減少鎖操作的開銷。
說說自己是怎麼使用 synchronized 關鍵字?
- 修飾例項方法: 作用於當前物件例項加鎖,進入同步程式碼前要獲得當前物件例項的鎖
- 修飾靜態方法:也就是給當前類加鎖,會作用於類的所有物件例項,因為靜態成員不屬於任何一個例項物件,是類
成員( static 表明這是該類的一個靜態資源,不管new了多少個物件,只有一份)。
所以如果一個執行緒A呼叫一個例項物件的非靜態 synchronized 方法,而執行緒B需要呼叫這個例項物件所屬類的靜態 synchronized 方法,是允許的,不會發生互斥現象,因為訪問靜態 synchronized 方法佔用的
鎖是當前類的鎖,而訪問非靜態 synchronized 方法佔用的鎖是當前例項物件鎖。 - 修飾程式碼塊: 指定加鎖物件,對給定物件加鎖,進入同步程式碼庫前要獲得給定物件的鎖。
總結: synchronized 關鍵字加到 static 靜態方法和 synchronized(class)程式碼塊上都是是給 Class 類上鎖。synchronized關鍵字加到例項方法上是給物件例項上鎖。儘量不要使用 synchronized(String a) 因為JVM中,字串常量池具有快取功能!
什麼是執行緒安全?Vector是一個執行緒安全類嗎?
如果你的程式碼所在的程序中有多個執行緒在同時執行,而這些執行緒可能會同時執行這段程式碼。如果每次執行結果和單執行緒執行的結果是一樣的,而且其他的變數 的值也和預期的是一樣的,就是執行緒安全的。
一個執行緒安全的計數器類的同一個例項物件在被多個執行緒使用的情況下也不會出現計算失誤。很顯然你可以將集合類分成兩組,執行緒安全和非執行緒安全的。
Vector 是用同步方法來實現執行緒安全的, 而和它相似的ArrayList不是執行緒安全的。
volatile關鍵字的作用?
一旦一個共享變數(類的成員變數、類的靜態成員變數)被volatile修飾之後,那麼就具備了兩層語義:
- 保證了不同執行緒對這個變數進行操作時的可見性,即一個執行緒修改了某個變數的值,這新值對其他執行緒來說是立即可見的。
- 禁止進行指令重排序。
- volatile本質是在告訴jvm當前變數在暫存器(工作記憶體)中的值是不確定的,需要從主存中讀取;synchronized則是鎖定當前變數,只有當前執行緒可以訪問該變數,其他執行緒被阻塞住。
- volatile僅能使用在變數級別;synchronized則可以使用在變數、方法、和類級別的。
- volatile僅能實現變數的修改可見性,並不能保證原子性;synchronized則可以保證變數的修改可見性和原子性。
- volatile不會造成執行緒的阻塞;synchronized可能會造成執行緒的阻塞。
volatile標記的變數不會被編譯器最佳化;synchronized標記的變數可以被編譯器最佳化。