如何寫出面試官欣賞的Java單例?java程式媛之家2019-03-01 00:03:02

2、當一個執行緒進入某個物件的一個synchronized的例項方法後,其它執行緒是否可進入此物件的其它方法?

如果其他方法沒有synchronized的話,其他執行緒是可以進入的。

所以要開放一個執行緒安全的物件時,得保證每個方法都是執行緒安全的。

3、樂觀鎖和悲觀鎖的理解及如何實現?

悲觀鎖:總是假設最壞的情況,每次去拿資料的時候都認為別人會修改,所以每次在拿資料的時候都會上鎖,這樣別人想拿這個資料就會阻塞直到它拿到鎖。傳統的關係型資料庫裡邊就用到了很多這種鎖機制,比如行鎖,表鎖等,讀鎖,寫鎖等,都是在做操作之前先上鎖。再比如Java裡面的同步原語synchronized關鍵字的實現也是悲觀鎖。

樂觀鎖:每次去拿資料的時候都認為別人不會修改,所以不會上鎖,但是在更新的時候會判斷一下在此期間別人有沒有去更新這個資料,可以使用版本號等機制。樂觀鎖適用於多讀的應用型別,這樣可以提高吞吐量,像資料庫提供的類似於write_condition機制,其實都是提供的樂觀鎖。在Java中java。util。concurrent。atomic包下面的原子變數類就是使用了樂觀鎖的一種實現方式CAS實現的。

4、SynchronizedMap 和 ConcurrentHashMap有什麼區別?

SynchronizedMap一次鎖住整張表來保證執行緒安全,所以每次只能有一個執行緒來訪為map。

ConcurrentHashMap使用分段鎖來保證在多執行緒下的效能。ConcurrentHashMap中則是一次鎖住一個桶。ConcurrentHashMap預設將hash表分為16個桶,諸如get,put,remove等常用操作只鎖當前需要用到的桶。這樣,原來只能一個執行緒進入,現在卻能同時有16個寫執行緒執行,併發效能的提升是顯而易見的。

另外ConcurrentHashMap使用了一種不同的迭代方式。在這種迭代方式中,當iterator被建立後集合再發生改變就不再是丟擲ConcurrentModificationException,取而代之的是在改變時new新的資料從而不影響原有的資料 ,iterator完成後再將頭指標替換為新的資料 ,這樣iterator執行緒可以使用原來老的資料,而寫執行緒也可以併發的完成改變。

5、CopyOnWriteArrayList可以用於什麼應用場景?

CopyOnWriteArrayList(免鎖容器)的好處之一是當多個迭代器同時遍歷和修改這個列表時,不會丟擲ConcurrentModificationException。在CopyOnWriteArrayList中,寫入將導致建立整個底層陣列的副本,而源陣列將保留在原地,使得複製的陣列在被修改時,讀取操作可以安全地執行。

由於寫操作的時候,需要複製陣列,會消耗記憶體,如果原陣列的內容比較多的情況下,可能導致young gc或者full gc;

不能用於實時讀的場景,像複製陣列、新增元素都需要時間,所以呼叫一個set操作後,讀取到資料可能還是舊的,雖然CopyOnWriteArrayList 能做到最終一致性,但是還是沒法滿足實時性要求;

CopyOnWriteArrayList透露的思想

讀寫分離,讀和寫分開

最終一致性

使用另外開闢空間的思路,來解決併發衝突

6、什麼叫執行緒安全?servlet是執行緒安全嗎?

執行緒安全是程式設計中的術語,指某個函式、函式庫在多執行緒環境中被呼叫時,能夠正確地處理多個執行緒之間的共享變數,使程式功能正確完成。

Servlet不是執行緒安全的,servlet是單例項多執行緒的,當多個執行緒同時訪問同一個方法,是不能保證共享變數的執行緒安全性的。

Struts2的action是多例項多執行緒的,是執行緒安全的,每個請求過來都會new一個新的action分配給這個請求,請求完成後銷燬。

SpringMVC的Controller是執行緒安全的嗎?不是的,和Servlet類似的處理流程

Struts2好處是不用考慮執行緒安全問題;Servlet和SpringMVC需要考慮執行緒安全問題,但是效能可以提升不用處理太多的gc,可以使用ThreadLocal來處理多執行緒的問題。

7、volatile有什麼用?能否用一句話說明下volatile的應用場景?

volatile保證記憶體可見性和禁止指令重排。

volatile用於多執行緒環境下的單次操作(單次讀或者單次寫)。

8、為什麼程式碼會重排序?

在執行程式時,為了提供效能,處理器和編譯器常常會對指令進行重排序,但是不能隨意重排序,不是你想怎麼排序就怎麼排序,它需要滿足以下兩個條件:

在單執行緒環境下不能改變程式執行的結果;

存在資料依賴關係的不允許重排序

需要注意的是:重排序不會影響單執行緒環境的執行結果,但是會破壞多執行緒的執行語義。

9、在java中wait和sleep方法的不同?

最大的不同是在等待時wait會釋放鎖,而sleep一直持有鎖。Wait通常被用於執行緒間互動,sleep通常被用於暫停執行。

直接瞭解的深入一點吧:

在Java中執行緒的狀態一共被分成6種:

初始態:

建立一個Thread物件,但還未呼叫start()啟動執行緒時,執行緒處於初始態。

執行態:

在Java中,執行態包括就緒態和執行態。

就緒態該狀態下的執行緒已經獲得執行所需的所有資源,只要CPU分配執行權就能執行。所有就緒態的執行緒存放在就緒佇列中。

執行態獲得CPU執行權,正在執行的執行緒。由於一個CPU同一時刻只能執行一條執行緒,因此每個CPU每個時刻只有一條執行態的執行緒。

阻塞態:

當一條正在執行的執行緒請求某一資源失敗時,就會進入阻塞態。而在Java中,阻塞態專指請求鎖失敗時進入的狀態。由一個阻塞佇列存放所有阻塞態的執行緒。處於阻塞態的執行緒會不斷請求資源,一旦請求成功,就會進入就緒佇列,等待執行。PS:鎖、IO、Socket等都資源。

等待態:

當前執行緒中呼叫wait、join、park函式時,當前執行緒就會進入等待態。也有一個等待佇列存放所有等待態的執行緒。執行緒處於等待態表示它需要等待其他執行緒的指示才能繼續執行。進入等待態的執行緒會釋放CPU執行權,並釋放資源(如:鎖)

超時等待態:

當執行中的執行緒呼叫sleep(time)、wait、join、parkNanos、parkUntil時,就會進入該狀態;它和等待態一樣,並不是因為請求不到資源,而是主動進入,並且進入後需要其他執行緒喚醒;進入該狀態後釋放CPU執行權 和 佔有的資源。與等待態的區別:到了超時時間後自動進入阻塞佇列,開始競爭鎖。

終止態:

執行緒執行結束後的狀態。

注意:

wait()方法會釋放CPU執行權和佔有的鎖。

sleep(long)方法僅釋放CPU使用權,鎖仍然佔用;執行緒被放入超時等待佇列,與yield相比,它會使執行緒較長時間得不到執行。

yield()方法僅釋放CPU執行權,鎖仍然佔用,執行緒會被放入就緒佇列,會在短時間內再次執行。

wait和notify必須配套使用,即必須使用同一把鎖呼叫;

wait和notify必須放在一個同步塊中呼叫wait和notify的物件必須是他們所處同步塊的鎖物件。

10、一個執行緒執行時發生異常會怎樣?

如果異常沒有被捕獲該執行緒將會停止執行。Thread。UncaughtExceptionHandler是用於處理未捕獲異常造成執行緒突然中斷情況的一個內嵌介面。當一個未捕獲異常將造成執行緒中斷的時候JVM會使用Thread。getUncaughtExceptionHandler()來查詢執行緒的UncaughtExceptionHandler並將執行緒和異常作為引數傳遞給handler的uncaughtException()方法進行處理。

11、如何在兩個執行緒間共享資料?

在兩個執行緒間共享變數即可實現共享。

一般來說,共享變數要求變數本身是執行緒安全的,然後線上程內使用的時候,如果有對共享變數的複合操作,那麼也得保證複合操作的執行緒安全性。

12、Java中notify 和 notifyAll有什麼區別?

notify() 方法不能喚醒某個具體的執行緒,所以只有一個執行緒在等待的時候它才有用武之地。而notifyAll()喚醒所有執行緒並允許他們爭奪鎖確保了至少有一個執行緒能繼續執行。

13、為什麼wait, notify 和 notifyAll這些方法不在thread類裡面?

一個很明顯的原因是JAVA提供的鎖是物件級的而不是執行緒級的,每個物件都有鎖,透過執行緒獲得。由於wait,notify和notifyAll都是鎖級別的操作,所以把他們定義在Object類中因為鎖屬於物件。

如何寫出面試官欣賞的Java單例?CrazyGIS2020-04-12 15:55:02

1。比較常見且相對完美的答案,可以採用DCL(Double Check Lock)單例。

如何寫出面試官欣賞的Java單例?

2。另一種完美的寫法就是靜態內部類的單例。

如何寫出面試官欣賞的Java單例?

3。最後一種是Java集合框架的作者Joshua Bloch,在《effective java》中推薦的寫法,“單元素的列舉型別已經成為實現Singleton的最佳方法”。

如何寫出面試官欣賞的Java單例?

這種方法不僅可以保證執行緒安全,還可以防止序列化和反射。

以上三種方式,第一種比較常見且常用。後兩種不太常見,但卻是完美的實現方法,相信你寫出來可以讓面試官眼前一亮!