Java中的并发集合

130 阅读5分钟

5.1 引言

并发集合在并发编程中的作用 在并发编程中,多线程同时访问和修改共享数据结构时,会导致数据一致性问题。传统的集合类如ArrayList、HashMap等不是线程安全的,在多线程环境下使用这些集合可能会导致数据损坏或其他意外行为。为了解决这个问题,Java提供了一些线程安全的并发集合类,这些集合类在设计时就考虑了多线程并发访问的需求,能够在高并发环境下提供高效、安全的数据访问和操作。

本文的内容结构 本文将介绍Java中常用的并发集合类及其实现原理,主要内容包括:

常用并发集合类 并发集合的实现原理

5.2 常用并发集合类

ConcurrentHashMap

简介 ConcurrentHashMap是一个线程安全的哈希表,实现了ConcurrentMap接口。它支持并发读取和更新,能够在高并发环境下提供高效的性能。

特性 高效的并发访问:使用分段锁(Segmented Locking)来减少锁竞争,提高并发性能。 非阻塞读取:大多数读取操作不需要加锁,提供了快速的读取性能。 可伸缩性:能够处理大量并发访问而不会显著降低性能。 示例代码

import java.util.concurrent.ConcurrentHashMap;
 
public class ConcurrentHashMapDemo {
    public static void main(String[] args) {
        ConcurrentHashMap<String, Integer> map = new ConcurrentHashMap<>();
 
        // 添加元素
        map.put("one", 1);
        map.put("two", 2);
        map.put("three", 3);
 
        // 并发访问
        map.forEach((key, value) -> System.out.println(key + ": " + value));
 
        // 更新元素
        map.put("two", 22);
        System.out.println("Updated value for 'two': " + map.get("two"));
 
        // 删除元素
        map.remove("three");
        System.out.println("Removed 'three': " + map.containsKey("three"));
    }
}

CopyOnWriteArrayList

简介 CopyOnWriteArrayList是一个线程安全的List实现,采用写时复制(Copy-On-Write)机制。它适用于读操作频繁、写操作较少的场景。

特性 写时复制:每次写操作都会创建一个新的数组,确保读操作不受影响。 无需同步:读操作不需要加锁,写操作通过复制数组实现线程安全。 适用于读多写少的场景:在读操作频繁、写操作较少的情况下,能够提供高效的性能。 示例代码

import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
 
public class CopyOnWriteArrayListDemo {
    public static void main(String[] args) {
        List<String> list = new CopyOnWriteArrayList<>();
 
        // 添加元素
        list.add("one");
        list.add("two");
        list.add("three");
 
        // 并发访问
        list.forEach(System.out::println);
 
        // 更新元素
        list.set(1, "two updated");
        System.out.println("Updated value at index 1: " + list.get(1));
 
        // 删除元素
        list.remove("three");
        System.out.println("Removed 'three': " + list.contains("three"));
    }
}

ConcurrentLinkedQueue

简介 ConcurrentLinkedQueue是一个基于链表的无界线程安全队列,实现了Queue接口。它采用无锁的CAS(Compare-And-Swap)算法,适用于高并发环境下的队列操作。

特性 非阻塞算法:采用CAS算法实现无锁的并发访问,提供高效的队列操作。 无界队列:没有容量限制,可以动态扩展。 适用于高并发场景:能够在高并发环境下提供高效的队列操作。 示例代码

import java.util.Queue;
import java.util.concurrent.ConcurrentLinkedQueue;
 
public class ConcurrentLinkedQueueDemo {
    public static void main(String[] args) {
        Queue<String> queue = new ConcurrentLinkedQueue<>();
 
        // 添加元素
        queue.add("one");
        queue.add("two");
        queue.add("three");
 
        // 并发访问
        queue.forEach(System.out::println);
 
        // 移除元素
        String removedElement = queue.poll();
        System.out.println("Removed element: " + removedElement);
 
        // 查看队头元素
        String headElement = queue.peek();
        System.out.println("Head element: " + headElement);
    }
}

5.3 并发集合的实现原理

各类并发集合的内部实现机制 ConcurrentHashMap的实现原理 ConcurrentHashMap使用了一种称为分段锁(Segmented Locking)的机制。整个哈希表被分成多个段(Segment),每个段包含一个哈希表。当一个线程访问某个段时,只有该段会被锁定,其他段仍然可以并发访问。这样可以显著减少锁竞争,提高并发性能。

CopyOnWriteArrayList的实现原理 CopyOnWriteArrayList采用写时复制机制。每次写操作(如添加、更新或删除元素)时,都会创建一个新的数组,将原数组中的元素复制到新数组中,然后在新数组上执行写操作。这样可以确保读操作不受写操作的影响,从而实现无锁并发访问。

ConcurrentLinkedQueue的实现原理 ConcurrentLinkedQueue采用无锁的CAS算法实现并发访问。队列中的每个节点包含一个指向下一个节点的引用和一个元素值。通过CAS操作,可以原子性地更新节点引用,实现无锁的入队和出队操作。

示例代码和性能比较 性能比较示例代码

import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.List;
import java.util.Queue;
import java.util.Map;
 
public class ConcurrentCollectionsPerformance {
    public static void main(String[] args) {
        // ConcurrentHashMap性能测试
        Map<Integer, Integer> map = new ConcurrentHashMap<>();
        long startTime = System.nanoTime();
        for (int i = 0; i < 1000000; i++) {
            map.put(i, i);
        }
        long endTime = System.nanoTime();
        System.out.println("ConcurrentHashMap time: " + (endTime - startTime) + " ns");
 
        // CopyOnWriteArrayList性能测试
        List<Integer> list = new CopyOnWriteArrayList<>();
        startTime = System.nanoTime();
        for (int i = 0; i < 100000; i++) {
            list.add(i);
        }
        endTime = System.nanoTime();
        System.out.println("CopyOnWriteArrayList time: " + (endTime - startTime) + " ns");
 
        // ConcurrentLinkedQueue性能测试
        Queue<Integer> queue = new ConcurrentLinkedQueue<>();
        startTime = System.nanoTime();
        for (int i = 0; i < 1000000; i++) {
            queue.add(i);
        }
        endTime = System.nanoTime();
        System.out.println("ConcurrentLinkedQueue time: " + (endTime - startTime) + " ns");
    }
}

性能比较

ConcurrentHashMap在高并发环境下提供了高效的并发读写性能,适用于需要频繁访问和修改的场景。 CopyOnWriteArrayList适用于读操作频繁、写操作较少的场景,读操作性能高,但写操作较慢。 ConcurrentLinkedQueue提供了高效的无锁队列操作,适用于高并发环境下的队列操作。 结论 本文详细介绍了Java中的常用并发集合类,包括ConcurrentHashMap、CopyOnWriteArrayList和ConcurrentLinkedQueue,并讨论了它们的实现原理和性能特性。通过使用这些并发集合类,开发者可以在多线程环境下高效、安全地管理共享数据,提高并发编程的性能和可靠性。