天天看點

Java面試題庫(線程安全)

作者:技能引路者

1. sleep和wait差別

來源不同:sleep是Thread類中的靜态方法,而wait是Object類中的執行個體方法。

使用方式不同:sleep不需要和synchronized關鍵字一起使用,直接調用即可。而wait必須在synchronized塊中調用,且必須擁有synchronized鎖定的對象的鎖,否則會抛出IllegalMonitorStateException異常。

釋放鎖的不同:當線程調用sleep方法時,不會釋放鎖,線程仍然占有鎖。而當線程調用wait方法時,會釋放對象的鎖,進入等待狀态。隻有當其他線程調用notify或notifyAll方法并且該線程獲得了鎖時,線程才能從wait狀态中解除。

調用方式不同:wait的調用可以通過notify或notifyAll來解除,而sleep則需要等待指定的時間過去後自動結束。

2. 如何中斷一個線程的執行?interrupt方法有什麼作用?

Java 中斷一個線程的執行可以通過調用 Thread 類提供的 interrupt() 方法來實作,該方法有以下作用:

中斷線程的阻塞狀态:如果線程正在調用 Object.wait()、Thread.sleep() 或者 Thread.join() 等方法進入阻塞狀态,那麼調用該線程的 interrupt() 方法将會使線程抛出 InterruptedException 異常,進而中斷線程的阻塞狀态。

中斷線程的運作狀态:如果線程處于運作狀态,那麼調用該線程的 interrupt() 方法将會使線程的中斷标志(interrupt status)被置位,表明該線程已經被中斷了。

需要注意的是,調用 interrupt() 方法隻是向線程發送中斷信号,如果線程不在響應中斷信号的情況下,該線程仍然可以繼續執行。是以,開發者需要線上程的執行過程中定期檢查線程的中斷狀态,并且在合适的時候退出線程的執行。

3. 如何保證線程安全?

線程安全可以通過同步機制來保證。可以使用synchronized關鍵字對代碼塊或方法進行同步,或者使用Lock接口的實作類對代碼塊或方法進行同步。此外,還可以使用線程安全的集合類,如ConcurrentHashMap、ConcurrentLinkedQueue等。

4. 如何在多線程環境中保證線程的執行順序?

在多線程環境中保證線程的執行順序可以使用 synchronized 關鍵字或 Lock 接口的鎖定機制來保證線程的有序執行。

使用 CountDownLatch 或 CyclicBarrier 等同步工具來協調線程執行順序,這些工具可以讓一個或多個線程等待其他線程的操作完成以後再執行。

使用 join() 方法在一個線程中等待其他線程完成後再執行下一步操作。

使用 wait() 和 notify()/notifyAll() 方法實作線程之間的通信和協調,確定線程按照指定的順序執行。

5. Java中有哪些鎖?

Java中常用的鎖有synchronized鎖、ReentrantLock鎖和StampedLock鎖。synchronized鎖是Java中最基本的鎖機制,而ReentrantLock鎖和StampedLock鎖則提供了更進階别的功能。

6. synchronized和Lock有什麼差別?它們都能用于什麼情況?

synchronized是Java内置的鎖機制,而Lock是Java提供的一個接口,提供了更多的靈活鎖定機制。synchronized鎖定粒度比較粗,隻能鎖定整個方法或代碼塊,而Lock可以控制鎖的範圍。

7. 什麼是死鎖?如何避免死鎖?

死鎖是指兩個或兩個以上的線程互相等待對方釋放鎖,進而導緻程式無法繼續執行的現象。死鎖是一種非常嚴重的線程安全問題。

避免死鎖可以采用以下一些政策:

  • 避免使用多個鎖;
  • 按照相同的順序擷取鎖;
  • 使用定時鎖等待;
  • 使用死鎖檢測和恢複工具。

8. 什麼是線程安全的集合?ConcurrentHashMap如何實作線程安全?

線程安全的集合是指支援在多線程環境下安全地并發通路的集合類。在Java中,常用的線程安全的集合類有ConcurrentHashMap、ConcurrentLinkedQueue、CopyOnWriteArrayList等。

ConcurrentHashMap是線程安全的HashMap實作,它采用了分段鎖機制來保證線程安全。具體來說,ConcurrentHashMap将整個HashMap分成多個段,每個段使用一個鎖來控制并發通路,不同的線程可以同時通路不同段的資料,進而提高了并發處理性能。

9. Stream并行執行是否線程安全?

Stream并行執行是線程安全的,但需要保證Stream中的操作是無狀态的。這意味着,Stream中的每個操作都不會依賴于前面的操作結果,而且每個操作對同一個元素的結果是一樣的。

10. 如何實作可重入鎖?

可重入鎖可以通過在鎖中維護一個owner變量,記錄目前持有鎖的線程,然後在擷取鎖時,判斷目前線程是否已經持有鎖,如果已經持有,則可以直接傳回,否則需要先等待其他線程釋放鎖後再擷取。ReentrantLock是一種可重入鎖的實作。

11. Java中的讀寫鎖

Java讀寫鎖(ReadWriteLock)是一種特殊的鎖機制。它與普通的鎖最大的不同在于,讀寫鎖中有兩種鎖,分别是讀鎖和寫鎖。在讀寫鎖中,多個線程可以同時持有讀鎖,但是隻有一個線程可以持有寫鎖。讀寫鎖的主要目的是優化對于程式中存在大量讀操作但很少寫操作的情況,進而提高程式的執行效率。

在ReadWriteLock中,可以通過以下方法擷取或釋放鎖:

readLock():擷取讀鎖;

writeLock():擷取寫鎖;

unlock():釋放鎖。

12. Java中的ThreadLocal有什麼作用?如何使用它?

ThreadLocal是一種提供線程局部變量的機制。它可以讓每個線程都有自己的變量副本副本,進而避免了多線程情況下變量競争的問題,保證了線程安全。

通過ThreadLocal實作線程間變量的隔離,每個線程可以單獨控制自己的變量,對于其他線程的變量通路不受影響。

在Java中,可以通過ThreadLocal類建立ThreadLocal變量,并通過調用它的set()和get()方法來設定和擷取目前線程的變量副本。

13. 什麼是守護線程?它和普通線程有什麼差別?

守護線程是一種特殊的線程,它的存在不會阻止JVM的退出。當JVM中隻有守護線程時,JVM會自動退出。

普通線程則是一種使用者線程,線程執行完畢後會等待其他線程結束,如果全部線程都結束後JVM仍未退出,則JVM會等待非守護線程執行完畢後再退出。

14. 什麼是volatile關鍵字?它有什麼作用?

volatile是一種線程同步機制,用于保證共享變量的可見性和禁止指令重排序。

如果某個變量被聲明為volatile,則任何線程對此變量的修改都會立即更新到主記憶體,任何線程讀取該變量時都會讀取到最新的值。

volatile還可以禁止指令重排序,保證指令執行的順序與程式中的順序一緻,進而避免由于指令重排序而導緻的線程安全問題。

15. 如何保證線程的同步?如何避免線程的競态條件?

使用synchronized關鍵字實作互斥鎖,保證多個線程對共享資源的通路是互斥的。

使用volatile關鍵字保證共享變量的可見性和有序性。

使用Lock類實作更細粒度的鎖,避免使用synchronized帶來的性能問題和死鎖等問題。

使用Atomic類提供的原子操作,避免資料競争等問題。

通過對多個共享資源進行排序,避免出現死鎖等情況。

繼續閱讀