AIOps 一场颠覆传统运维的盛筵
852
2022-09-19
Java 性能调优指南之 Java 集合概览(java培训)
本文将概览所有标准的 Java 集合类型。我们将按照它们可区分的属性与主要用例进行分类。除此之外,我们还将穷举在不同集合类型之间进行数据转换的方法。
数组(Arrays)
数组是 Java 语言内置的唯一集合类型,尤其擅长处理预先知道数量上限的元素集。java.util.Arrays 包含了许多用于处理数组的方法,列举如下:
Arrays.asList ——将 array(数组) 转变为 List(列表),后者可以传值给其他标准的集合构造函数。Arrays.binarySearch ——对有序数组或其分段进行快速查找。Arrays.copyOf ——如果想在扩展数组的同时保存其内容,可调用该方法。Arrays.copyOfRange ——如果需要拷贝整个数组或其分段,可调用该方法。Arrays.deepEquals, Arrays.deepHashCode ——支持嵌套子数组的 Arrays.equals 或 Arrays.hashCode 版本。Arrays.equals ——如果需要比较两个数组是否相等,可调用此方法(不可调用数组自身的 equals 方法,array.equals 方法未被重写,因此只会比较对数组的引用,而非其内容。)此方法可以与 Java 5 中的 boxing(装箱)与 varargs(可变参数)特性并用,以编写类 equals 方法的简单实现——在比较对象类型之后,将所有类字段都传给 Arrays.equals 即可。Arrays.fill ——将整个数组或其分段赋值为给定的值。Arrays.hashCode ——计算数组内容的 hashcode 值(数组自身的 hashcode 方法无法实现此功能。)此方法可以与 Java 5 中的 boxing(装箱)与 varargs(可变参数)特性并用,以编写类 hashcode 方法的简单实现——将所有类字段都传给 Arrays.hashcode 即可。Arrays.sort ——根据自然排序(natural ordering)规则,对整个数组或其分段进行排序。若要利用已知的 Comparator 对 Object[] 进行排序,也有一对 Arrays.sort 方法。Arrays.toString ——打印数组的具体内容。
最后,还有一点,任何 Collection(集合) 都可以使用 T[] Collection.toArray( T[] a ) 方法拷贝到数组中。此方法调用的常见模式如下:
return coll.toArray( new T[ coll.size() ] );
此方法调用会分配足够大的数组以存储整个集合,因此 toArray 不必要分配很大的数组用于返回。
单线程集合(Single-threaded collections)
Lists(列表)
Queues(队列)/deques(双队列)
Maps(映射)
Sets(集合)
java.util.Collections
就像针对数组的 java.util.Arrays 包一样,java.util.Collections 包提供了许多处理集合的好方法。
本文将要介绍的第一组方法会返回集合的各种视图:
Collections.checkedCollection / checkedList / checkedMap / checkedSet / checkedSortedMap / checkedSortedSet —— 会返回集合的视图,在运行时检查所添加元素的类型。如果试图添加类型不兼容的元素,会抛出 ClassCastException 异常。该功能能有效防止运行时造型(runtime casts)。Collections.emptyList / emptyMap / emptySet ——当你需要返回不可变的空集合,而又不想分配任何对象时,此类方法便能派上用场。Collections.singleton / singletonList / singletonMap —— 返回带有单个条目的不可变 set/list/map。Collections.synchronizedCollection / synchronizedList / synchronizedMap / synchronizedSet / synchronizedSortedMap / synchronizedSortedSet —— 返回包含所有同步方法的集合视图(低成本又低效率的多线程方法,仍然不支持put-or-update之类的复合动作)。Collections.unmodifiableCollection / unmodifiableList / unmodifiableMap / unmodifiableSet / unmodifiableSortedMap / unmodifiableSortedSet ——返回集合的不可变视图。当需要实现包含任意集合的不可变对象时尤其有用。
本文介绍的第二组方法都因为相同的原因被排除在集合之外:
Collections.addAll ——如果要往一个集合添加一定数量的元素或一个数组的内容,调用此方法。Collections.binarySearch —— 与 Arrays.binarySearch 对于 arrays(数组)的作用相同。Collections.disjoint —— 检查2个集合之间不存在共同的元素。Collections.fill —— 用给定值替换某个列表中的所有元素。Collections.frequency —— 给定集合中有多少元素与给定对象相等。Collections.indexOfSubList / lastIndexOfSubList —— 这些方法与 String.indexOf(String) / lastIndexOf(String) 相似,它们会找出给定列表中给定子列表首次或末次出现的情况。Collections.max / min —— 基于自然排序或 Comparator 找出集合中的最大或最小元素。Collections.replaceAll —— 在给定列表中用某个元素替代另一个元素。Collections.reverse —— 颠倒给定列表中的元素次序。如果你打算在列表排序之后立即调用此方法,不如在进行元素排序时使用 Collections.reverseOrder 比较器。Collections.rotate —— 根据给定距离旋转列表中的元素。Collections.shuffle ——打乱列表的排序。注意,你可以为此方法提供自己的随机生成器,可以是 java.util.Random,java.util.ThreadLocalRandom 或 java.security.SecureRandom。Collections.sort —— 根据自然排序或给定的 Comparator 对列表进行排序。Collections.swap —— 根据给定的位置交换列表中的2个元素(许多开发者都亲自编写此方法)。
并发集合
本部分将介绍 java.util.concurrent 包中提供的线程安全(thread-safe)集合类型。这些集合的主要特性在于能确保其方法的原子执行(atomic execution)。不过,不要忘记,涉及多个方法调用的 “add-or-update” 或 “check-then-update” 等复合动作(compound actions)仍然应该同步。因为,在复合动作第一步中查询到的信息在执行第二个步骤之前可能已经失效。
大多数并发集合类型从 Java 1.5 开始引入。ConcurrentSkipListMap / ConcurrentSkipListSet 以及 LinkedBlockingDeque 是在 Java 1.6 开始启用的。在 Java 1.7 中的最近更新为 ConcurrentLinkedDeque 与 LinkedTransferQueue 的加入。
Lists(列表)
CopyOnWriteArrayList ——列表实现,针对每次更新都创建一个底层数组的新拷贝。这一操作的成本很高,因此,当遍历的次数远大于更新时使用此类比较合适。此集合类型的常见用例为 listeners/observers 集合。
Queues(队列)/deques(双队列)
ArrayBlockingQueue —— 包含一个数组类的有界阻塞队列。无法调整大小,因此,当向满的队列添加一个元素时,该方法调用会遭到阻塞,直到另一个线程从该队列中提取出了一个元素。ConcurrentLinkedDeque / ConcurrentLinkedQueue ——基于链表(linked list)的无界队列/双队列。往该队列中添加元素不会遭到阻塞,但是要求此类集合的使用者(consumer)必须与其产出者(producer)保持至少相同的工作效率,否则就会出现内存耗尽的情况。此类还相当依赖 CAS (compare-and-set) 操作。DelayQueue ——由 Delayed(延迟) 元素组成的无界阻塞队列。其元素只有在延迟过期之后才能从队列中剔除。队首是剩余延迟值最小(包括负值,代表延迟已经过期)的元素。当想要实现一个由延迟任务组成的队列时(无需手动实现,使用 ScheduledThreadPoolExecutor 即可),此队列便能派上用场。LinkedBlockingDeque / LinkedBlockingQueue ——基于链表(linked list)的可选有界(可以在创建时指定最大容量,也可以不指定)队列/双队列。以 ReentrantLock-s 为空/满条件。LinkedTransferQueue ——基于链表(linked list)的无界队列。除了普通的队列操作,此类还拥有一组传递方法(transfer methods),允许产出者直接向等待中的使用者发送消息,从而解决了在队列中存储元素的需求。这是一个基于 CAS 操作的无锁(lock-free)集合类型。PriorityBlockingQueue —— PriorityQueue 的无界阻塞队列版。SynchronousQueue ——不带任何内部容量的阻塞队列。因此,任何插入请求必须等待对应的删除请求,反之亦然。如果你不需要 Queue 接口,同样的功能可以通过 Exchanger 实现。
Maps(映射)
ConcurrentHashMap ——对 get 操作全并发、对 put 操作可配置并发的散列表(hash table)。该并发等级可通过构造函数参数(默认为16) concurrencyLevel 进行调整,该参数定义了映射内的划分情况。在 put 操作中只有更新后的划分会被锁定。请牢记,此映射类型并不是 HashMap 算法的线程安全替代品 ——任何对此映射(或其他并发集合类)的 “get-then-put” 序列方法调用都必须是外部同步的。ConcurrentSkipListMap ——基于跳跃表(skip list)的 ConcurrentNavigableMap 实现。本质上,此集合类可以作为 TreeMap 的线程安全替代物使用。
Sets(集合)
ConcurrentSkipListSet ——采用 ConcurrentSkipListMap 类进行存储的并发集合。CopyOnWriteArraySet ——采用 CopyOnWriteArrayList 类进行存储的并发集合。
另请参阅
推荐阅读
如果你想对 Java 集合类有更深入的了解,笔者建议你从下面的书中找一本阅读。
总结
以下是所有 JDK 集合类的简单总结:
Single threaded (单线程) | Concurrent (并发) | |
Lists(列表) |
|
|
Queues / deques (队列/双队列) |
|
|
Maps(映射) |
|
|
Sets(集合) |
|
|
发表评论
暂时没有评论,来抢沙发吧~