Java多線程 Concurrent集合與atomic封裝類

1、Concurrent集合

Java標準庫java.util.concurrent包提供了基於線程安全的集合。針對標準的Java集合類List、Map、Set、Deque,java.util.concurrent包也提供了對應的併發集合類。

interfacenon-thread-safethread-safe
List ArrayList CopyOnWriteArrayList
Map HashMap ConcurrentHashMap
Set HashSet / TreeSet CopyOnWriteArraySet
Queue ArrayDeque / LinkedList ArrayBlockingQueue / LinkedBlockingQueue
Deque ArrayDeque / LinkedList LinkedBlockingDeque

 

使用併發集合類與使用非線程安全的集合類完全相同。

import java.util.concurrent.ArrayBlockingQueue;

Queue q = new ArrayBlockingQueue(0);

2、BlockingQueue

BlockingQueue即阻塞隊列,被阻塞的情況主要有兩種:隊列滿了的時候進行入隊列操作、隊列空了的時候進行出隊列操作。因此,當一個線程試圖對一個已經滿了的隊列進行入隊列操作時,它將會被阻塞,除非有另一個線程做了出隊列操作;同樣,當一個線程試圖對一個空隊列進行出隊列操作時,它將會被阻塞,除非有另一個線程進行了入隊列操作。又阻塞隊列的特性可知,阻塞隊列是線程安全的。

阻塞隊列主要用在生產者/消費者的場景,下面這幅圖展示了一個線程生產、一個線程消費的場景:

 負責生產的線程不斷的製造新對象並插入到阻塞隊列中,直到達到這個隊列的上限值。隊列達到上限值之後生產線程將會被阻塞,直到消費的線程對這個隊列進行消費。同理,負責消費的線程不斷的從隊列中消費對象,直到這個隊列爲空,當隊列爲空時,消費線程將會被阻塞,除非隊列中有新的對象被插入。

BlockingQueue的實現類有:

  • ArrayBlockingQueue
  • DelayQueue
  • LinkedBlockingQueue
  • PriorityBlockingQueue
  • SynchronousQueue

3、atomic

Java atomic封裝類,提供了在多線程環境下,無鎖進行原子性操作。Atomic包裏內部實現不是簡單的使用synchronized,而是一個更爲高效的方式CAS (compare and swap) + volatile和native方法,從而避免了synchronized的高開銷,提升執行效率。

CAS:compare and swap,比較和替換技術,將預期值與當前變量的值比較(compare),如果相等則使用新值替換(swap)當前變量,否則不作操作;現代CPU已廣泛支持CAS指令,如果不支持,那麼JVM將使用自旋鎖,與互斥鎖一樣,兩者都需先獲取鎖才能訪問共享資源,但互斥鎖會導致線程進入睡眠,而自旋鎖會一直循環等待直到獲取鎖。

import java.util.concurrent.atomic.AtomicInteger;

public class Atomic {
    private static int count = 0;
    private static AtomicInteger aiCount = new AtomicInteger(0);

    public static void main(String[] args) {
        for (int i = 0; i < 20; i++) {
            Thread t = new Thread() {
                @Override
                public void run() {
                    for (int j = 0; j < 1000; j++) {
                        count++;
                        aiCount.incrementAndGet();
                    }
                }
            };
            t.start();

        }
        System.out.println(count);
        System.out.println(aiCount);
    }

}
// 19948
// 20000

由於自增或自減操作在多線程環境下是不安全的。上述對count變量和 aiCount變量使用20個線程,分別對其1000次自增操作。會發現count變量結果每次並不一致,基於原子封裝的 aiCount 變量多線程下均能得到正確結果。

 

 

參考鏈接:

1、https://www.liaoxuefeng.com/wiki/1252599548343744/1306581083881506

2、https://blog.csdn.net/suifeng3051/article/details/48807423

3、https://my.oschina.net/u/4381576/blog/3416692

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章