iT邦幫忙

0

[Java] Thread-Safety是什麼 – Part 2

閱讀時間: 10分鐘

接上一篇文章,又來為大家在10分鐘內講解一些有關Thread-safety的介紹。
再講3個做到Thread-safety的方式。
大家可以因應情況選擇一個最合適的表達方法。

4. Synchronized Collections
大家可以輕易地創建一個thread-safe的集合(collection)透過synchronization wrappers。

Collection<Integer> syncCollection = Collections.synchronizedCollection(new ArrayList<>());
Thread thread1 = new Thread(() -> syncCollection.addAll(Arrays.asList(1, 2, 3, 4, 5, 6)));
Thread thread2 = new Thread(() -> syncCollection.addAll(Arrays.asList(7, 8, 9, 10, 11, 12)));
thread1.start();
thread2.start();

synchronized collections 利用內在鎖(intrinsic locking)在每一個method中.
換言之,method在同一時間只可以被一個thread存取,
假如其他threads試圖存取,就會被阻擋blocked,直到那個method被上一個thread 解鎖(unlocked)。

5. Concurrent Collections
它是synchronized collections的替代品,同樣可以做到thread-safe 的集合。
在Java中, 提供了一個java.util.concurrent package,裡內有幾個concurrent collections 例如: ConcurrentHashMap。

Map<String,String> concurrentMap = new ConcurrentHashMap<>();
concurrentMap.put("1", "one");
concurrentMap.put("2", "two");
concurrentMap.put("3", "three");

不過concurrent collections跟synchronized collections是有不同的地方,concurrent collections 會將數據分成不同部分以做到thread-safety的功能。
在ConcurrentHashMap,每一個thread可以鎖住一個map的segment(一個map由不同segments組成)。所以一個map可以同時被多個threads存取。

6. Atomic Objects
可以利用atomic classes來做到thread-safety的功能,Java可以提供AtomicInteger, AtomicLong, AtomicBoolean, 和AtomicReference等元素來完成任務。
首先,Atomic classes可以容許大家完成各種atomic的操作以做到thread-safe,同時沒有用到任何synchronization。
會用以下例子詳細講解:

public class Counter {
     
    private int counter = 0;
     
    public void incrementCounter() {
        counter += 1;
    }
     
    public int getCounter() {
        return counter;
    }
}

假設目前的是一個race condition,兩個threads同時存取incrementCounter() method。最後的結果是counter field的值會是2,而當中的incrementCounter()不是atomic。

下面會是一個thread-safe的例子透過利用物件AtomicInteger修改了Counter class:

public class AtomicCounter {
     
    private final AtomicInteger counter = new AtomicInteger();
     
    public void incrementCounter() {
        counter.incrementAndGet();
    }
     
    public int getCounter() {
        return counter.get();
    }
}

這個例子是thread-safe是因為它在增加數值時利用了atomic的元素- incrementAndGet,先加1再存取加1之後的值。


尚未有邦友留言

立即登入留言