Java中常见的集合比较:
(一)List
List接口
List是有序的Collection,使用此接口能够精确的控制每个元素插入的位置。用户能够使用索引(元素在List中的位置,类似于数组下标)来访问List中的元素,这类似于Java的数组。
List允许有相同的元素。
除了具有Collection接口必备的iterator()方法外,List还提供一个listIterator()方法,返回一个ListIterator接口,和标准的Iterator接口相比,ListIterator多了一些add()之类的方法,允许添加,删除,设定元素,还能向前或向后遍历。
实现List接口的常用类有LinkedList,ArrayList,Vector和Stack。
LinkedList类
LinkedList实现了List接口,允许null元素。此外LinkedList提供额外的get,remove,insert方法在LinkedList的首部或尾部。这些操作使LinkedList可被用作堆栈(stack),队列(queue)或双向队列(deque)。
注意LinkedList没有同步方法。如果多个线程同时访问一个List,则必须自己实现访问同步。一种解决方法是在创建List时构造一个同步的List:
List list = Collections.synchronizedList(new LinkedList(...));
ArrayList类
ArrayList实现了可变大小的数组。它允许所有元素,包括null。ArrayList没有同步。
size,isEmpty,get,set方法运行时间为常数。但是add方法开销为分摊的常数,添加n个元素需要O(n)的时间。其他的方法运行时间为线性。
每个ArrayList实例都有一个容量(Capacity),即用于存储元素的数组的大小。这个容量可随着不断添加新元素而自动增加,但是增长算法并没有定义。当需要插入大量元素时,在插入前可以调用ensureCapacity方法来增加ArrayList的容量以提高插入效率。
和LinkedList一样,ArrayList也是非同步的(unsynchronized)。
Vector类
Vector非常类似ArrayList,但是Vector是同步的。由Vector创建的Iterator,虽然和ArrayList创建的Iterator是同一接口,但是,因为Vector是同步的,当一个Iterator被创建而且正在被使用,另一个线程改变了Vector的状态(例如,添加或删除了一些元素),这时调用Iterator的方法时将抛出ConcurrentModificationException,因此必须捕获该异常。
Stack 类
Stack继承自Vector,实现一个后进先出的堆栈。Stack提供5个额外的方法使得Vector得以被当作堆栈使用。基本的push和pop方法,还有peek方法得到栈顶的元素,empty方法测试堆栈是否为空,search方法检测一个元素在堆栈中的位置。Stack刚创建后是空栈
(二)map
Map接口
Map主要用于存储健值对,根据键得到值,因此不允许键重复(重复了覆盖了),但允许值重复。
HashTable
与HashMap
、ConcurrentHashMap
主要的区别在于HashMap不是同步的、线程不安全的和不适合应用于多线程并发环境下,而ConcurrentHashMap
是线程安全的集合容器,特别是在多线程和并发环境中,引入ConcurrentHashMap
是为了在同步集合HashTable之间有更好的选择,通常作为Map
的主要实现。除了线程安全外,他们之间还有一些细微的不同。
HashMap
和ConcurrentHashMap
的细节和对比它们之间的参数比如线程安全、同步、性能和基本的使用。
- 就像上面所说他们之间的第一个重要的区别就是
ConcurrentHashMap
是线程安全的和在并发环境下不需要加额外的同步。虽然它不像Hashtable
那样需要同样的同步等级(全表锁),但也有很多实际的用途。 - 你可以使用
Collections.synchronizedMap(HashMap)
来包装HashMap作为同步容器,这时它的作用几乎与Hashtable
一样,当每次对Map
做修改操作的时候都会锁住这个Map
对象,而ConcurrentHashMap
会基于并发的等级来划分整个Map来达到线程安全,它只会锁操作的那一段数据而不是整个Map
都上锁。 ConcurrentHashMap
有很好的扩展性,在多线程环境下性能方面比做了同步的HashMap
要好,但是在单线程环境下,HashMap
会比ConcurrentHashMap
好一点。
总结一下以上两者的区别,它们在线程安全、扩展性、同步之间的区别。如果是用于缓存的话,ConcurrentHashMap
是一个更好的选择,在Java应用中会经常用到。ConcurrentHashMap
在读操作线程数多于写操作线程数的情况下更胜一筹。
ConcurrentHashMap vs Hashtable vs Synchronized Map
虽然三个集合类在多线程并发应用中都是线程安全的,但是他们有一个重大的差别,就是他们各自实现线程安全的方式。Hashtable
是jdk1的一个遗弃的类,它把所有方法都加上synchronized
关键字来实现线程安全。所有的方法都同步这样造成多个线程访问效率特别低。Synchronized Map
与HashTable
差别不大,也是在并发中作类似的操作,两者的唯一区别就是Synchronized Map
没被遗弃,它可以通过使用Collections.synchronizedMap()
来包装Map
作为同步容器使用。
另一方面,ConcurrentHashMap
的设计有点特别,表现在多个线程操作上。它不用做外的同步的情况下默认同时允许16个线程读和写这个Map容器。因为其内部的实现剥夺了锁,使它有很好的扩展性。不像HashTable
和Synchronized Map
,ConcurrentHashMap
不需要锁整个Map,相反它划分了多个段(segments),要操作哪一段才上锁那段数据。
坦白说,集合类是一个最重要的Java API,我觉得恰当的使用它们是一种艺术。依我个人经验,我会使用ArrayList
这些容器来提高自己的Java程序的性能,而不会去用一些遗弃的容器比如Vector
等等,在Java 5之前,Java集合容器有一个很致命的缺陷就是缺乏可扩展性。
同步集合类比如Hashtable
和Vector
在多线程Java应用里面逐渐成为障碍物;在jdk5后出现一些很好的并发集合,对大容量、低延迟的电子交易系统有很大影响,是快速存取数据的支柱。
原文地址:
ConcurrentHashMap和HashMap的区别
ConcurrentHashMap vs Hashtable vs Synchronized Map
ConcurrentHashMap能完全替代HashTable吗?
回答:hash table虽然性能上不如ConcurrentHashMap,但并不能完全被取代,两者的迭代器的一致性不同的,hash table的迭代器是强一致性的,而concurrenthashmap是弱一致的。 ConcurrentHashMap的get,clear,iterator 都是弱一致性的。 Doug Lea 也将这个判断留给用户自己决定是否使用ConcurrentHashMap。
选择哪一个,是在性能与数据一致性之间权衡。
ConcurrentHashMap适用于追求性能的场景,大多数线程都只做insert/delete操作,对读取数据的一致性要求较低。
LinkedHashMap 是HashMap的一个子类,保存了记录的插入顺序,在用Iterator遍历LinkedHashMap时,先得到的记录肯定是先插入的.也可以在构造时用带参数,按照应用次数排序。在遍历的时候会比HashMap慢,不过有种情况例外,当HashMap容量很大,实际数据较少时,遍历起来可能会比 LinkedHashMap慢,因为LinkedHashMap的遍历速度只和实际数据有关,和容量无关,而HashMap的遍历速度和他的容量有关。
(三)set
Set接口
Set不允许包含相同的元素,如果试图把两个相同元素加入同一个集合中,add方法返回false。
Set判断两个对象相同不是使用==运算符,而是根据equals方法。也就是说,只要两个对象用equals方法比较返回true,Set就不 会接受这两个对象。
HashSet
HashSet有以下特点
不能保证元素的排列顺序,顺序有可能发生变化
不是同步的
集合元素可以是null,但只能放入一个null
当向HashSet结合中存入一个元素时,HashSet会调用该对象的hashCode()方法来得到该对象的hashCode值,然后根据 hashCode值来决定该对象在HashSet中存储位置。
简单的说,HashSet集合判断两个元素相等的标准是两个对象通过equals方法比较相等,并且两个对象的hashCode()方法返回值相 等
注意,如果要把一个对象放入HashSet中,重写该对象对应类的equals方法,也应该重写其hashCode()方法。其规则是如果两个对 象通过equals方法比较返回true时,其hashCode也应该相同。另外,对象中用作equals比较标准的属性,都应该用来计算 hashCode的值。
LinkedHashSet
LinkedHashSet集合同样是根据元素的hashCode值来决定元素的存储位置,但是它同时使用链表维护元素的次序。这样使得元素看起 来像是以插入顺序保存的,也就是说,当遍历该集合时候,LinkedHashSet将会以元素的添加顺序访问集合的元素。
LinkedHashSet在迭代访问Set中的全部元素时,性能比HashSet好,但是插入时性能稍微逊色于HashSet。
TreeSet类
TreeSet是SortedSet接口的唯一实现类,TreeSet可以确保集合元素处于排序状态。TreeSet支持两种排序方式,自然排序 和定制排序,其中自然排序为默认的排序方式。向TreeSet中加入的应该是同一个类的对象。
TreeSet判断两个对象不相等的方式是两个对象通过equals方法返回false,或者通过CompareTo方法比较没有返回0
自然排序
自然排序使用要排序元素的CompareTo(Object obj)方法来比较元素之间大小关系,然后将元素按照升序排列。
Java提供了一个Comparable接口,该接口里定义了一个compareTo(Object obj)方法,该方法返回一个整数值,实现了该接口的对象就可以比较大小。
obj1.compareTo(obj2)方法如果返回0,则说明被比较的两个对象相等,如果返回一个正数,则表明obj1大于obj2,如果是 负数,则表明obj1小于obj2。
如果我们将两个对象的equals方法总是返回true,则这两个对象的compareTo方法返回应该返回0
定制排序
自然排序是根据集合元素的大小,以升序排列,如果要定制排序,应该使用Comparator接口,实现 int compare(T o1,T o2)方法