并发集合(java.util.concurrent)
一、List
CopyOnWriteArrayList(ReentrantLock实现线程安全)
(1)并发修改(写操作)时保证线程安全:
通过ReentrantLock实现多个线程并发修改时的线程安全同步(添加元素的同时,不允许删除)
添加新元素:list.add("")
按照指定下标替换元素:list.set(index, element)
按照指定下标删除元素:list.remove(0)
(2)并发读取:
没有加锁,允许多个线程同时并发读取;但是读取时,可能产生脏读(读取的同时,允许写入操作)。
(3)CopyOnWrite思想:修改时将原数组内容复制Copy到新数组内,在新数组内修改,然后替换
二、Set
CopyOnWriteArraySet(ReentrantLock实现线程安全)
内部通过一个CopyOnWriteArrayList实现。
三、Queue
BlockingQueue阻塞队列(ReentrantLock实现线程安全)
阻塞队列:由两个线程,分别进行读写(take和put)操作;读取时,不允许写入,如果队列为空,则读取线程阻塞;写入时,不允许读取,如果队列已满,则写入线程阻塞。
ArrayBlockingQueue:有界队列
LinkedBlockingQueue:无界队列
应用:生产者-消费者模型
// 生产者-消费者模型
public class Test01 {public static void main(String[] args) {// 自增ID (原子性)AtomicInteger number = new AtomicInteger(1);// 保存生产者数据的阻塞队列LinkedBlockingQueue<String> queue = new LinkedBlockingQueue<>(); // LinkedBlockingQueue<>(3) 阻塞队列最多保存3个生产者数据// 创建线程池ThreadPoolExecutor executor = new ThreadPoolExecutor(6, 6, 0, TimeUnit.SECONDS,new LinkedBlockingQueue<Runnable>());// 1个生产者线程executor.execute(() -> {// 生产10个数据for (int i = 1; i <= 10; i++) {String data = "数据" + number.getAndIncrement();System.out.println("【生产者】生成:" + data);try {// 保存至阻塞队列queue.put(data); // 入队// 模拟延迟Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}});// 5个消费者线程for (int i = 1; i <= 5; i++) {executor.execute(() -> {while (true){try {String data = queue.take();System.out.println("【消费" + Thread.currentThread().getName() + "】获取:" + data);} catch (InterruptedException e) {e.printStackTrace();}}});}}
}
四、Map
ConcurrentHashMap
(1)JDK1.7:通过分段锁实现线程安全。
(2)JDK1.8:通过 synchronized+CAS实现线程安全。
当产生哈希冲突时,通过synchronized将根节点(链表头节点或树根节点)作为锁,进行线程的同步安全;
在没有产生哈希冲突时,通过CAS进行无锁化操作,降低synchronized进行线程同步操作所引发的性能下降。