簡體   English   中英

哪些 Java 集合是同步的(線程安全的),哪些不是?

[英]Which Java Collections are synchronized(thread safe), which are not?

哪些 Java 集合是同步的,哪些不是?

示例:HashSet 不同步

共有三組集合。

  • Java 1.0 集合主要是遺留類。 這包括哈希表、向量、堆棧。 這些是同步的,但我不建議您使用它們。 屬性可能是一個例外,但我不會在多線程上下文中使用它。
  • 1998 年添加的 Java 1.2 集合在很大程度上取代了這些集合不是同步的,但可以使用Collections.synchronizedXxx()方法進行同步
  • 2004 年添加的 Java 5.0 並發集合支持無鎖、線程安全的集合。

簡而言之,我建議您使用的所有集合都不是同步的。

線程安全集合 -

  1. 並發哈希映射

線程安全,無需同步整個地圖 使用鎖完成寫入時讀取速度非常快 在對象級別沒有鎖定 使用多個鎖。

  1. 同步哈希映射

對象級同步 讀寫都獲取鎖 鎖定集合有性能缺陷 可能導致爭用

  1. 向量

  2. 哈希表

  3. 復制寫入數組列表

  4. 復制寫入數組集

其余的都不是線程安全的

您可以獲得 Java Collection的同步版本

Collections.synchronizedCollection(Collection<T> c)

[ javadoc ]

簡單回答:沒有一個Collection實現是同步的,因為synchronized不是類屬性,它只適用於方法和塊。

我想,您想知道哪些實現是線程安全的,哪些來自 java 集合框架的類可以安全地用於多線程環境中。

該信息始終包含在 javadoc 中( 例如:Arraylist - 這不是線程安全的)

Collection 接口中的ArrayList、LinkedList、HashSet、LinkedHashset 和TreeSet 以及HashMap、LinkedHashMap 和Treemap 都是非同步的

集合接口中的向量是同步的

前面的例子是完全錯誤的。

首先,您沒有從不同的線程訪問您剛剛同步的列表,您無法證明同步正在正確執行,您無法證明添加過程是原子的。 其次,列表本身上的同步子句是一種不好的做法,您不知道優化器是否會使用列表中的項目進行同步,從而導致意外行為。 此外,您正在同步的是對列表中元素的讀取/寫入訪問,而不是列表本身。 取出 Collections.synchronized 並查看輸出。 多試幾次。 請舉以下例子:

class ProcessSomething {
    private List<Integer> integerList = Collections.synchronizedList(new ArrayList<>());
    private void calculate() {
        for (int i = 0; i < 10000; i++) {
            try {
                Thread.sleep(1);
            } catch (InterruptedException ex) {
                Logger.getLogger(App.class.getName()).log(Level.SEVERE, null, ex);
            }
            integerList.add(new Random().nextInt(100));
        }
    }
    private void calculate2() {
        for (int i = 0; i < 10000; i++) {
            try {
                Thread.sleep(1);
            } catch (InterruptedException ex) {
                Logger.getLogger(App.class.getName()).log(Level.SEVERE, null, ex);
            }
            integerList.add(new Random().nextInt(100));
        }
    }
    public void process() {
        Long start = System.currentTimeMillis();
        Thread t1 = new Thread(new Runnable() {
            public void run() {
                calculate();
            }
        });
        t1.start();
        Thread t2 = new Thread(new Runnable() {
            public void run() {
                calculate2();
            }
        });
        t2.start();
        try {
            t1.join();
            t2.join();
        } catch (InterruptedException ex) {
            Logger.getLogger(ProcessSomething.class.getName()).log(Level.SEVERE, null, ex);
        }
        Long end = System.currentTimeMillis();
        System.out.println("Duration: " + (end - start));
        System.out.println("List size: " + integerList.size());
    }
}
public class App {
    public static void main(String[] args) {
        new ProcessSomething().process();
    }
}

java.util 包中的所有集合類(Vector 和Hashtable 除外)都不是線程安全的。 僅有的兩個遺留集合是線程安全的:Vector 和 Hashtable。 為什么? 原因如下:同步可能非常昂貴! 你知道,Vector 和 Hashtable 是 Java 歷史早期存在的兩個集合,它們從一開始就是為線程安全而設計的(如果你有機會查看它們的源代碼,你會發現它們的方法都是同步的!)。 然而,它們很快暴露了多線程程序的性能不佳。 您可能知道,同步需要鎖,這總是需要時間來監控,這會降低性能。 這就是新集合(List、Set、Map 等)根本不提供並發控制以在單線程應用程序中提供最大性能的原因。

同步使性能降低。 當然,Java集合不是同步的。 但是 Java 提供了一個 Synchronization Wrappers 來同步 Java Collection 見鏈接

for example:


    import java.util.ArrayList;
    import java.util.Collections;
    import java.util.Iterator;
    import java.util.List;

    public class SynchronizedListExample {

        public static void main(String[] args) {

            List<String> syncList = Collections.synchronizedList(new ArrayList<String>());

            syncList.add("one");//no need to synchronize here
            syncList.add("two");
            syncList.add("three");
            String st = syncList.get(0); //it is ok here => no need to synchronize

            // when iterating over a synchronized list, we need to synchronize access to the synchronized list
           //because if you don't synchronize here, synchList maybe be changed during iterating over it
            synchronized (syncList) {
                Iterator<String> iterator = syncList.iterator();
                while (iterator.hasNext()) {
                    System.out.println("item: " + iterator.next());
                }
            }

        }

    }

導入 java.util.Collections; //導入這個

List<String> syncList = Collections.synchronizedList(new ArrayList<String>());

這就是您如何在 Java 中同步列表。

線程安全集合

  • 傳統 - Vector (父級為List )和Hashtable (父級為Map
  • 同步集合使用synchronized監視器。 Collections.synchronized , Collections.synchronizedList() , Collections.synchronizedSortedMap() , Collections.synchronizedSet() ...
  • 並發集合(Java 5)
    • Copy-On-Write(COW) - 比同步集合具有更好的性能,但具有更大的內存占用。 修改數組時會創建新的數組副本(添加、設置、刪除)。 它是多讀操作和后修改的一個很好的變體。 CopyOnWriteArrayList , CopyOnWriteArraySet
    • Compare-And-Swap(CAS) [關於] - ConcurrentLinkedQueue , ConcurrentSkipListMap
    • 基於Lock - ConcurrentHashMap , BlockingQueue后代

我猜集合 API 的每個實現都寫在文檔中。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM