JUC——并发集合类

如果要进行多个数据的保存,无疑首选类集(List、Set、Queue、Map),在类集的学习的时候也知道一个概念:许多集合的子类都具有同步与异步的差别,但是如果真的要在多线程之中去使用这些类,是否真的可以用呢?

范例:观察一下类集的问题:

package so.strong.mall.concurrent;
import java.util.ArrayList;
import java.util.List;

public class ListDemo {
    public static void main(String[] args) {
        final List<String> all = new ArrayList<>();
        for (int i = 0; i < 20; i++) {
            final int temp = i;
            new Thread(new Runnable() {
                @Override
                public void run() {
                    for (int j = 0; j < 20; j++) {
                        all.add(Thread.currentThread().getName() + "-" + temp + "-" + j);
                        System.out.println(all);
                    }
                }
            }).start();
        }
    }
}

不过很遗憾的是这个时候以上的代码出现了“java.util.ConcurrentModificationException”,该异常主要指的是当保存的容量个数和实际操作数可能不匹配的时候就出现该异常。

并发集合类

为了更好的实现集合的高并发访问处理,juc中创建一组新的集合工具类:

List和Set集合

public class CopyOnWriteArrayList<E> implements List<E>, RandomAccess, Cloneable, java.io.Serializable

  CopyOnWriteArrayList相当于线程安全的ArrayList,它实现了List接口。CopyOnWriteArrayList是支持高并发的。

public class CopyOnWriteArraySet<E> extends AbstractSet<E> implements java.io.Serializable

  相当于线程安全的HashSet,它继承与AbstractSet类。

  CopyOnWriteArraySet内部包含一个CopyOnWriteArrayList对象,它是通过CopyOnWriteArrayList来实现的。

Map集合

public class ConcurrentHashMap<K, V> extends AbstractMap<K, V> implements ConcurrentMap<K, V>, Serializable 

  ConcurrentHashMap是线程安全的哈希表,相当于线程安全的HashMap,它继承与AbstractMap类,并且实现了ConcurrentMap接口。ConcurrentHashMap是通过“锁分段”来实现的,它支持并发;

public class ConcurrentSkipListMap<K,V> extends AbstractMap<K,V> implements ConcurrentNavigableMap<K,V>,Cloneable,java.io.Serializable

  ConcurrentSkipListMap是线程安全的有序哈希表(相当于线程安全的TreeMap),它继承于AbstractMap类,并且实现了ConcurrentNavigableMap接口。ConcurrentSkipListMap是通过“跳表”来实现的,它支持并发;

public class ConcurrentSkipListSet<E> extends AbstractSet<E> implements NavigableSet<E>, Cloneable, java.io.Serializable

  ConcurrentSkipListSet是线程安全的有序的集合(相当于线程安全的TreeSet);它继承了AbstractSet,并且实现了NavigableSet接口。ConcurrentSkipListSet是通过ConcurrentSkipListMap实现的,它也支持并发。

Queue队列

public class ArrayBlockingQueue<E> extends AbstractQueue<E> implements BlockingQueue<E>, java.io.Serializable

  ArrayBlockingQueue是数组实现的线程安全的有界的阻塞队列;

public class LinkedBlockingQueue<E> extends AbstractQueue<E>implements BlockingQueue<E>, java.io.Serializable

  LinkedBlockingQueue是单向链表实现的(指定大小)阻塞队列,该队里按FIFO先进先出排序元素;

public class LinkedBlockingDeque<E>extends AbstractQueue<E> implements BlockingDeque<E>,  java.io.Serializable

  LinkedBlockingDeque是双向链表实现的(指定大小)双向并发阻塞队列,该阻塞队列同时支持FIFO和FILO两种操作方式;

public class ConcurrentLinkedQueue<E> extends AbstractQueue<E> implements Queue<E>, java.io.Serializable

  ConcurrentLinkedQueue是单向链表实现的无界队列,该队列按FIFO排序元素;

public class ConcurrentLinkedDeque<E> extends AbstractCollection<E> implements Deque<E>, java.io.Serializable

  ConcurrentLinkedDeque是双向链表的无界队列,该阻塞队列同时支持FIFO和FILO两种操作方式。

单值并发集合

juc包里面提供的CopyOnWriteArrayList、CopyOnWriteArraySet很明显是针对于List和Set接口实现的子类。

范例:使用CopyOnWriteArrayList实现多线程访问

package so.strong.mall.concurrent;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;

public class ListDemo {
    public static void main(String[] args) {
        final List<String> all = new CopyOnWriteArrayList<>();
        for (int i = 0; i < 20; i++) {
            final int temp = i;
            new Thread(new Runnable() {
                @Override
                public void run() {
                    for (int j = 0; j < 20; j++) {
                        all.add(Thread.currentThread().getName() + "-" + temp + "-" + j);
                        System.out.println(all);
                    }
                }
            }).start();
        }
    }
}

范例:使用CopyOnWriteArraySet实现多线程访问

package so.strong.mall.concurrent;
import java.util.Set;
import java.util.concurrent.CopyOnWriteArraySet;

public class ListDemo {
    public static void main(String[] args) {
        final Set<String> all = new CopyOnWriteArraySet<>();
        for (int i = 0; i < 20; i++) {
            final int temp = i;
            new Thread(new Runnable() {
                @Override
                public void run() {
                    for (int j = 0; j < 20; j++) {
                        all.add(Thread.currentThread().getName() + "-" + temp + "-" + j);
                        System.out.println(all);
                    }
                }
            }).start();
        }
    }
}

如果某一个类需要存储用户的公共资源,并且多个线程允许同时写入数据的话,就可以考虑使用此类集合实现处理。

ConcurrentHashMap

观察继承结构:

public class ConcurrentHashMap<K, V> extends AbstractMap<K, V>
        implements ConcurrentMap<K, V>, Serializable

发现它是ConcurrentMap接口的子类,而ConcurrentMap接口定义如下:

public interface ConcurrentMap<K, V> extends Map<K, V>

范例:默认情况下使用ConcurrentHashMap的基本使用:

package so.strong.mall.concurrent;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

public class ConcurrentHashMapDemo {
    public static void main(String[] args) {
        final Map<String, String> all = new ConcurrentHashMap<>();
        for (int i = 0; i < 2; i++) {
            final int temp = i;
            new Thread(new Runnable() {
                @Override
                public void run() {
                    for (int j = 0; j < 3; j++) {
                        all.put(Thread.currentThread().getName(), "x = " + temp + ",j = " + j);
                        System.out.println(all);
                    }
                }
            }).start();
        }
    }
}

  使用ConcurrentHashMap并不仅仅是去解决“java.util.ConcurrentModificationException”异常,Map集合的主要特征是做数据的查询操作,所以在ConcurrentHashMap设计的时候考虑到了数据更新的安全性和数据查询的并发性。

ConcurrentHashMap的整体特征:写的时候同步写入,使用独占锁,读的时候为了保证性能使用了共享锁。

跳表(Skip)集合

跳表集合本质上的功能是一种快速查询功能,也就是说它会在一个有序的链表里面选择一些数据作为检索的种子数,那么利用这些种子数方便进行数据的查找,非常类似于二分法。

在juc开发包里面提供有跳表的多线程支持程序类:ConcurrentSkipListMap、ConcurrentSkipListSet。

范例:观察跳表实现ConcurrentSkipListMap

package so.strong.mall.concurrent;
import com.sun.scenario.effect.impl.sw.sse.SSEBlend_SRC_OUTPeer;
import sun.java2d.pipe.SpanIterator;
import java.util.Map;
import java.util.concurrent.ConcurrentSkipListMap;

public class SkipDemo {
    public static void main(String[] args) {
        final Map<String, String> all = new ConcurrentSkipListMap<>();
        for (int i = 0; i < 20; i++) {
            final int temp = i;
            new Thread(new Runnable() {
                @Override
                public void run() {
                    for (int j = 0; j < 30; j++) {
                        all.put(Thread.currentThread().getName(), "x=" + temp + ",j=" + j);
                    }
                }
            }).start();
        }
        System.out.println(all.get("Thread-0"));
    }

}

范例:使用ConcurrentSkipListSet

package so.strong.concurrents;
import java.util.Set;
import java.util.concurrent.ConcurrentSkipListSet;

public class SkipDemo {
    public static void main(String[] args) {
        final Set<String> all = new ConcurrentSkipListSet<>();
        for (int i = 0; i < 2; i++) {
            final int temp = i;
            new Thread(new Runnable() {
                @Override
                public void run() {
                    for (int j = 0; j < 10; j++) {
                        all.add(Thread.currentThread().getName()+"-"+temp+"-"+j);
                    }
                }
            }).start();
        }
        System.out.println(all.contains("Thread-0-0-1"));
    }
}

如果要想保证快速地定位查询,那么使用跳表是最快速的,因为其检索的算法要比顺序检索强许多。

原文地址:https://www.cnblogs.com/itermis/p/9066144.html

时间: 2024-10-27 17:12:15

JUC——并发集合类的相关文章

使用JUC并发工具包的Lock和Condition,实现生产者和消费者问题中的有界缓存

JDK5.0之前,用java实现生产者和消费者的唯一方式就是使用synchronized内置锁和wait/notify条件通知机制.JDK5.0之后提供了显示锁Lock和条件队列Condition,与内置锁和内置条件队列相对应,但是显示的锁和条件队列,功能更强大,更灵活.此外JDK5.0之后还提供了大量很有用的并发工具类,如BlockingQueue等,基于这些数据结构,能够方便.快速.高效的构建自己应用需要的效果.这里我们简单使用下显示锁和条件队列,来模拟有界缓存的实现,功能类似于JDK内置的

Java 理论与实践: 并发集合类

Java 理论与实践: 并发集合类 DougLea的 util.concurrent 包除了包含许多其他有用的并发构造块之外,还包含了一些主要集合类型 List 和 Map 的高性能的.线程安全的实现.在本月的 Java理论与实践中,BrianGoetz向您展示了用 ConcurrentHashMap 替换 Hashtable 或 synchronizedMap ,将有多少并发程序获益.您可以在本文的 中与作者以及其他读者共享您的想法(您也可以点击文章顶部或者底部的 讨论进入论坛). 在Java

秋招之路9:juc并发

j.u.c是java.util.concurrent的简称 通过查api,了解到是由以下这三个组成的. juc包图 锁的两种实现方式 java并发编程,关于锁的实现方式有两种: 1.基于synchronized关键字实现同步,jvm内置锁,也叫隐式锁,由jvm自动加锁和解锁 2.juc下的lock接口实现的更加灵活的锁的实现方式,也叫显示锁,需要手动加锁和解锁 重要分类 locks部分:显示锁(互斥锁和读写锁)相关: atomic部分:原子变量类相关,是构建非阻塞队列算法的基础,使用CAS实现:

JUC并发编程--AQS

转自: https://www.jianshu.com/p/d8eeb31bee5c 前言 在java.util.concurrent.locks包中有很多Lock的实现类,常用的有ReentrantLock.ReadWriteLock(实现类ReentrantReadWriteLock),内部实现都依赖AbstractQueuedSynchronizer类,接下去让我们看看Doug Lea大神是如何使用一个普通类就完成了代码块的并发访问控制.为了方便,本文中使用AQS代替AbstractQue

《码出高效 Java开发手册》第七章 并发与多线程

码云: https://gitee.com/forxiaoming/JavaBaseCode/blob/master/EasyCoding/src/concurrency/multithreading/index.md 并发(Concurrency) 与并行(Parallelism) 以KTV唱歌为例, Parallelism 是指有多少人可以使用话筒同时唱歌, Concurrency是指同一个话筒被多少个人轮流使用; 一个科室两个专家同时出诊, 就是两个并行任务; 其中一个医生时而问诊, 时而

JUC一

警醒自己不断学习和成长 正式学习的准备工作 JUC并发编程 1.什么是JUC JUC就是java.util .concurrent工具包的简称.这是一个处理线程的工具包,JDK 1.5开始出现的. 2.进程和线程回顾 什么是进程和线程? 进程:是一个具有一定独立功能的程序在一个数据集上的一次动态执行的过程,是操作系统进行资源分配和调度的一个独立单位,是应用,例如:QQ.exe 线程:是拥有资源和独立运行的最小单位,也是程序执行的最小单位. 一个进程可以包含多个线程,一个进程至少有一个线程!Jav

40个Java集合类面试题和答案(转载)

Java集合框架为Java编程语言的基础,也是Java面试中很重要的一个知识点.这里,我列出了一些关于Java集合的重要问题和答案. 1.Java集合框架是什么?说出一些集合框架的优点? 每种编程语言中都有集合,最初的Java版本包含几种集合类:Vector.Stack.HashTable和Array.随着集合的广泛使用,Java1.2提出了囊括所有集合接口.实现和算法的集合框架.在保证线程安全的情况下使用泛型和并发集合类,Java已经经历了很久.它还包括在Java并发包中,阻塞接口以及它们的实

Java并发框架——AQS之阻塞与唤醒

根据前面的线程阻塞与唤醒小节知道,目前在Java语言层面能实现阻塞唤醒的方式一共有三种:suspend与resume组合.wait与notify组合.park与unpark组合.其中suspend与resume因为存在无法解决的竟态问题而被Java废弃,同样,wait与notify也存在竟态条件,wait必须在notify之前执行,假如一个线程先执行notify再执行wait将可能导致一个线程永远阻塞,如此一来,必须要提出另外一种解决方案,就是park与unpark组合,它位于juc包下,应该也

并发容器之CopyOnWriteArrayList分析

今天介绍的主角是CopyOnWriteArrayList类,是jdk1.5才加入的一个并发集合类,它是ArrayList的Thread-safe的变体,属于COW的一种,COW系列的还有CopyOnWriteArraySet集合.COW是一种用于程序设计中的优化策略.其基本思路是,从一开始大家都在共享同一个内容,当某个人想要修改这个内容的时候,才会真正把内容Copy出去形成一个新的内容然后再改,这是一种延时懒惰策略. 先给出结论: CopyOnWriteArrayList适用于读操作比写操作多很