JavaRush /Java Blog /Random-TW /第 26 級。有關該級別主題的面試問題的答案。第 2 部分:問題 6-9、11-12
zor07
等級 31
Санкт-Петербург

第 26 級。有關該級別主題的面試問題的答案。第 2 部分:問題 6-9、11-12

在 Random-TW 群組發布
第 26 級。有關該級別主題的面試問題的答案。 第 2 部分. 問題 6-9、11-12 - 1

6.什麼是坎卡倫西?

並發是 Java 中的一個類別庫,其中包含針對跨多個執行緒工作而最佳化的特殊類別。這些類別被收集在一個包中java.util.concurrent。它們可以根據功能進行如下示意性劃分: 第 26 級。有關該級別主題的面試問題的答案。 第 2 部分. 問題 6-9、11-12 - 2並發集合- 一組在多線程環境中比java.util包中的標準通用集合更有效地工作的集合。不是Collections.synchronizedList使用阻塞存取整個集合的基本包裝器,而是使用資料段上的鎖,或使用無等待演算法對資料的平行讀取進行最佳化。 隊列- 具有多線程支援的非阻塞和阻塞隊列。非阻塞隊列旨在提高速度並在不阻塞線程的情況下進行操作。當某些條件不滿足時,例如隊列為空或溢出,或沒有空閒的“消費者”,您需要“減慢”“生產者”或“消費者”線程的速度時,可以使用阻塞隊列。 同步器是用於同步執行緒的輔助實用程式。它們是「並行」計算中的強大武器。 Executors - 包含用於建立執行緒池、調度非同步任務和獲取結果的優秀框架。 - 代表與基本同步機制 synchronized相比的替代且更靈活的線程同步機制。原子- 支援對基元和引用進行原子操作的類別。 來源:waitnotifynotifyAll

7. 你知道 Kankarensi 的哪些課程?

這個問題的答案在這篇文章中得到了完美的闡述。我不認為在這裡重印所有內容有什麼意義,因此我將只描述那些我有幸簡要地熟悉的類別。 ConcurrentHashMap<K, V> -與 和上的Hashtable區塊不同,資料以段的形式呈現,分為鍵的雜湊值。因此,資料是按段落存取的,而不是按單一物件存取的。另外,迭代器代表特定時間段的數據,不會拋出異常。 AtomicBoolean、AtomicInteger、AtomicLong、AtomicIntegerArray、AtomicLongArray - 如果在類別中您需要同步存取簡單類型變數怎麼辦?您可以將構造與, 一起使用,並且在使用原子操作,時使用。但是您可以透過使用新類別來做得更好。由於使用了 CAS,這些類的操作比通過. 另外,還有依照給定數量進行原子加法以及遞增/遞減的方法。 synhronizedHashMapConcurrentModificationExceptionintsynchronizedset/getvolatileAtomic*synchronized/volatile

8. ConcurrentHashMap 類別如何運作?

在其引入時,ConcurrentHashMapJava 開發人員需要以下雜湊映射實作:
  • 線程安全
  • 訪問整個表時沒有鎖
  • 執行讀取操作時最好沒有表鎖
主要實現思路ConcurrentHashMap如下:
  1. 地圖元素

    與元素不同HashMapEntryinConcurrentHashMap被聲明為volatile。這是一個重要的特性,也是由於JMM的變化所致。

    static final class HashEntry<K, V> {
        final K key;
        final int hash;
        volatile V value;
        final HashEntry<K, V> next;
    
        HashEntry(K key, int hash, HashEntry<K, V> next, V value) {
            this .key = key;
            this .hash = hash;
            this .next = next;
            this .value = value;
         }
    
        @SuppressWarnings("unchecked")
        static final <K, V> HashEntry<K, V>[] newArray(int i) {
            return new HashEntry[i];
        }
    }
  2. 哈希函數

    ConcurrentHashMap也使用了改進的雜湊函數。

    HashMap讓我提醒一下JDK 1.2中的情況:

    static int hash(int h) {
        h ^= (h >>> 20) ^ (h >>> 12);
        return h ^ (h >>> 7) ^ (h >>> 4);
    }

    ConcurrentHashMap JDK 1.5 版本:

    private static int hash(int h) {
        h += (h << 15) ^ 0xffffcd7d;
        h ^= (h >>> 10);
        h += (h << 3);
        h ^= (h >>> 6);
        h += (h << 2) + (h << 14);
        return h ^ (h >>> 16);
    }

    為什麼需要使雜湊函數變得更複雜?哈希映射中的表的長度由 2 的冪決定。對於二進位表示在低位和高位上沒有區別的雜湊碼,我們將會發生衝突。增加雜湊函數的複雜度正好解決了這個問題,減少了映射中發生衝突的可能性。

  3. 此映射被分成N個不同的段(預設為16個,最大值可以是16位元且是2的冪)。每個段都是一個線程安全的映射元素表。增加段的數量將鼓勵修改操作跨越多個段,從而降低運行時阻塞的可能性。

  4. 並發級別

    此參數會影響記憶卡的使用情況和卡片中的段數。

    段的數量將被選擇為大於 concurrencyLevel 的最接近的 2 的冪。降低 concurrencyLevel 會使執行緒在寫入時更有可能阻塞映射段。高估該指標會導致記憶體使用效率低。如果只有一個執行緒會修改map,其餘執行緒都會讀取,建議使用值1。

  5. 全部的

    那麼,主要優點和實現特點ConcurrentHashMap

    • 地圖有一個類似的hashmap互動介面
    • 讀取操作不需要鎖定並且並行執行
    • 寫入操作通常也可以並行執行而不會阻塞
    • 創建時註明需要的concurrencyLevel,透過讀寫統計來確定
    • 地圖元素的值value聲明為volatile
    來源: ConcurrentHashMap 的工作原理

9. 什麼是Lock類別?

為了控制對共享資源的訪問,我們可以使用鎖作為同步運算符的替代方案。鎖定功能封裝在java.util.concurrent.locks. 首先,執行緒嘗試存取共享資源。如果它是空閒的,則在該線程上放置一個鎖。一旦工作完成,共享資源上的鎖就會被釋放。如果資源未釋放並且已在其上放置了鎖,則執行緒將等待直到該鎖被釋放。鎖類別實作一個Lock定義以下方法的介面:
  • void lock():等待直到取得鎖
  • boolean tryLock():嘗試取得鎖;如果取得鎖,則傳回true。如果未取得鎖,則傳回false。與該方法不同的是,lock()如果鎖不可用,它不會等待獲取鎖
  • void unlock():移除鎖
  • Condition newCondition():Condition傳回與目前鎖關聯的對象
一般情況下鎖定的組織非常簡單:若要取得鎖,請呼叫該方法lock(),在完成共用資源的操作後,呼叫該方法unlock(),從而釋放鎖定。該物件Condition允許您管理阻塞。通常,要使用鎖,需要使用ReentrantLock包中的一個類別。java.util.concurrent.locks.該類別實作了 介面Lock。讓我們以一個小程式為例來看看如何使用 Java Lock API: 那麼,假設我們有一個類,它Resource有幾個線程安全的方法和不需要線程安全的方法。
public class Resource {

    public void doSomething(){
        // пусть здесь происходит работа с базой данных
    }

    public void doLogging(){
        // потокобезопасность для логгирования нам не требуется
    }
}
現在讓我們來看一個實作介面Runnable並使用類別方法的類別Resource
public class SynchronizedLockExample implements Runnable{

    // экземпляр класса Resource для работы с методами
    private Resource resource;

    public SynchronizedLockExample(Resource r){
        this.resource = r;
    }

    @Override
    public void run() {
        synchronized (resource) {
            resource.doSomething();
        }
        resource.doLogging();
    }
}
現在讓我們使用 Lock API 而不是synchronized.
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

// класс для работы с Lock API. Переписан с приведенной выше программы,
// но уже без использования ключевого слова synchronized
public class ConcurrencyLockExample implements Runnable{

    private Resource resource;
    private Lock lock;

    public ConcurrencyLockExample(Resource r){
        this.resource = r;
        this.lock = new ReentrantLock();
    }

    @Override
    public void run() {
        try {
            // лочим на 10 секунд
            if(lock.tryLock(10, TimeUnit.SECONDS)){
            resource.doSomething();
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }finally{
            //убираем лок
            lock.unlock();
        }
        // Для логгирования не требуется потокобезопасность
        resource.doLogging();
    }

}
從程式中可以看到,我們使用該方法tryLock()來確保執行緒只等待一定的時間。如果它沒有獲得物件的鎖,它只會記錄並退出。另一個重要的一點。必須使用塊try-finally來確保即使方法doSomething()拋出異常也能釋放鎖。 資料來源:

11.什麼是互斥體?

互斥體是用於同步執行緒/程序的特殊物件。它可以有兩種狀態──忙碌和空閒。簡單來說,互斥體是一個布林變量,它有兩個值:busy (true) 和 free (false)。當執行緒想要物件的獨佔所有權時,它將其互斥體標記為忙碌,當它完成對物件的處理時,它將其互斥標記為空閒。Java 中的每個物件都附加了一個互斥體。只有 Java 機器可以直接存取互斥鎖。它對程式設計師是隱藏的。

12.什麼是顯示器?

監視器是一種特殊的機制(一段代碼) - 互斥鎖上的附加元件,可確保其正確操作。畢竟,僅僅標記物件忙碌是不夠的;我們還必須確保其他線程不會嘗試使用忙碌物件。在Java中,監視器是使用關鍵字來實現的synchronized。當我們編寫同步區塊時,Java編譯器將其替換為三段程式碼:
  1. 在區塊的開頭synchronized,加入了將互斥體標記為忙碌的程式碼。
  2. 在區塊的末尾,synchronized添加了一個程式碼,將互斥鎖標記為空閒。
  3. 在該區塊之前,synchronized加入程式碼來檢查互斥鎖是否繁忙,然後執行緒必須等待它被釋放。
第1部分
留言
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION