阿摩線上測驗 登入

申論題資訊

試卷:104年 - 104 關務特種考試_四等_資訊處理:程式語言概要#24070
科目:程式語言
年份:104年
排序:0

申論題內容

五、假設你要寫一段程式碼,來管理數個並行執行緒(thread)之間共享的一雜湊表 (hash table),而雜湊表的操作必須符合原子性(atomicity)。你可以使用一個互 斥鎖(mutual exclusion lock)來保護整個表,你也可以用一個鎖分別保護每個雜湊 表的桶(bucket)。請分別說明這兩種做法的優點和缺點。(20 分)

詳解 (共 1 筆)

詳解 提供者:hchungw

在管理數個並行執行緒共享的雜湊表(hash table)時,確保操作的原子性非常重要。我們可以使用互斥鎖來達到這個目的。以下是兩種常見的鎖策略:保護整個表的單一鎖和為每個桶(bucket)分別設置鎖。這兩種方法各有優點和缺點。
使用單一鎖保護整個表
優點:
簡單實現:只需要一個互斥鎖,程式碼簡單易懂,易於維護。
強一致性:在操作雜湊表的任何時候,只有一個執行緒能夠訪問和修改表,確保了操作的一致性。
缺點:
低並行性:由於同一時間只有一個執行緒可以訪問整個表,這會導致高併發情況下的效能瓶頸。
高等待時間:在高併發環境下,執行緒需要等待較長時間才能獲得鎖,可能會影響整體效能。
使用每個桶的單獨鎖
優點:
高並行性:不同的桶可以同時被多個執行緒訪問和修改,從而提高了並行性和效能。
減少等待時間:鎖的競爭減少,執行緒在進行操作時等待的時間更短。
缺點:
實現較為複雜:需要為每個桶管理單獨的鎖,程式碼變得更為複雜,增加了開發和維護的難度。
死鎖風險:如果不小心設計,可能會引入死鎖問題(例如多個執行緒同時獲取多個鎖時,可能會互相等待對方釋放鎖)。
不一致性風險:需要小心處理跨桶操作,以避免不一致的狀況。
實現示例
以下是兩種方法的簡單示例。
單一鎖保護整個表
java
複製程式碼
import java.util.concurrent.locks.ReentrantLock;
import java.util.HashMap;
import java.util.Map;
public class SingleLockHashTable {
    private final ReentrantLock lock = new ReentrantLock();
    private final Map<Integer, String> hashTable = new HashMap<>();
    public void put(int key, String value) {
        lock.lock();
        try {
            hashTable.put(key, value);
        } finally {
            lock.unlock();
        }
    }
    public String get(int key) {
        lock.lock();
        try {
            return hashTable.get(key);
        } finally {
            lock.unlock();
        }
    }
}
每個桶的單獨鎖
java
複製程式碼
import java.util.concurrent.locks.ReentrantLock;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
public class BucketLockHashTable {
    private static class Bucket {
        private final ReentrantLock lock = new ReentrantLock();
        private final List<Entry> entries = new LinkedList<>();
    }
    private static class Entry {
        final int key;
        String value;
        Entry(int key, String value) {
            this.key = key;
            this.value = value;
        }
    }
    private final Bucket[] buckets;
    private static final int NUM_BUCKETS = 16;
    public BucketLockHashTable() {
        buckets = new Bucket[NUM_BUCKETS];
        for (int i = 0; i < NUM_BUCKETS; i++) {
            buckets[i] = new Bucket();
        }
    }
    private int hash(int key) {
        return key % NUM_BUCKETS;
    }
    public void put(int key, String value) {
        int bucketIndex = hash(key);
        Bucket bucket = buckets[bucketIndex];
        bucket.lock.lock();
        try {
            for (Entry entry : bucket.entries) {
                if (entry.key == key) {
                    entry.value = value;
                    return;
                }
            }
            bucket.entries.add(new Entry(key, value));
        } finally {
            bucket.lock.unlock();
        }
    }
    public String get(int key) {
        int bucketIndex = hash(key);
        Bucket bucket = buckets[bucketIndex];
        bucket.lock.lock();
        try {
            for (Entry entry : bucket.entries) {
                if (entry.key == key) {
                    return entry.value;
                }
            }
            return null;
        } finally {
            bucket.lock.unlock();
        }
    }
}
總結
單一鎖保護整個表:適合簡單情況,實現簡單但並行性差。
每個桶的單獨鎖:適合高並發環境,並行性好但實現複雜且需要注意死鎖風險。
根據應用的具體需求和環境,選擇合適的鎖策略來管理並行訪問的雜湊表,可以在性能和安全性之間取得平衡。