JAVA的各种集合的线程安全性

一、概念

线程安全:

就是当多线程访问时,采用了加锁机制。即当一个线程访问该类的某个数据时,会对这个数据进行保护,其他线程不能对其访问,直到该线程读取完之后,其他线程才可以使用。防止出现数据不一致或数据被污染的情况。

线程不安全:

就是不提供数据访问时的数据保护,多个线程能够同时操作某个数据,从而出现数据不一致或数据被污染的情况。

对于线程不安全的问题,一般会使用synchronized关键字加同步锁控制。

线程安全工作原理:

jvm中有一个main memory对象,每个线程也有自己的working memory,一个线程对一个变量variable进行操作时,都需要在自己的working memory创建一个copy,操作完之后在写入main memory。而使用synchronized的关键是建立一个monitor,这个monitor可以时要修改的变量,也可以时其他自己认为合适的对象(方法),然后通过这个monitor加锁来实现线程安全,每个线程在获得这个锁之后,要执行完加载load到working memory到use && 指派assign到储存store 再到main memory的过程。才会释放它得到的锁,这样就实现了所谓的线程安全。

二、线程安全的集合对象

  • Vector
  • HashTable
  • StringBuffer

三、非线程安全的对象

  • ArrayList
  • LinkedList
  • HashMap
  • HashSet
  • TreeMap
  • TreeSet
  • StringBuilder

四、相关集合对象的比较

Vector、ArrayList、LinkedList

1、Vector:

Vector与ArrayList一样,也是通过数组实现的。不同的是它支持线程同步,即某一时刻只有一个线程能够操作Vector,避免多线程同时写而造成不一致,但实现线程同步需要很高的花费,因此,访问它比访问ArrayList慢。

2、ArrayList

a.当操作是在一系列数据的后面添加数据而不是在前面或中间,并需要随机的访问元素时,使用ArrayList性能比较好。

b.ArrayList是最常用的List实现类,内部时通过数组实现,它需要对元素进行快速随机访问,数组的缺点时每个元素之间不能有间隔,当数组大小不能满足时需要增加储存能力,就要将已经有的数组数据复制到新的储存空间,当ArrayList的中间位置插入或删除元素时,要将数组进行复制、移动,代价比较高。因此它适合快速随机查找和遍历元素,不适合增加和删除元素。

3、LinkedList

a.当对一系列数据的前面或中间执行添加或删除操作时,并且按照顺序访问其中的元素时,要使用LinkedList。

b.LikedList是用链表结构储存数据,很适合数据的动态插入和删除,随机访问和遍历的速度比较慢。另外,它还提供了List接口没有的方法,专门用于操作表头和表尾的元素的,可以当作堆栈、队列和双向队列使用。

Vector和ArrayList在使用上非常相似,都可以用来表示一组数量可变的对象应用集合,并且可以随机的访问其中的元素。

 

HashTable、HashMap和HashSet

HashTable和HashMap采用的储存机制是一致的,不同的是:

1、HashMap:

a.采用数组方式储存Key—value构成的Entry对象,无容量限制。

b.基于key hash查找Entry对象存放到数组的位置,对于hash冲突采用链表方式解决

c.在插入元素时可能会扩大数组的容量,在扩大容量时必须从新计算hash,并复制对象到新数组。

d.是非线程安全的

e.遍历使用的是Iterator迭代器

2、HashTable

a.是线程安全的

b.无论时key还是value都不允许为空,在HashTable调用put时,如果key为null,直接抛出NullPointerException异常

c.遍历使用的是Enumeration例举

3、HashSet

a.基于HashMap实现,无容量限制

b.是非线程安全的

c.不保证数据的有序

TreeSet、TreeMap:

TreeSet和TreeMap都是完全基于Map来实现的,并且都不支持get(index)来获得指定位置的元素,需要遍历来获取。另外TreeSet还提供了一些排序方面的支持,例如,传入Comparator来实现,descendingSet以及descendingIterator等。

1、TreeSet:

a.基于TreeMap实现,支持排序

b.是非线程安全的

2、TreeMap:

a.典型的基于红黑树的Map实现,因此它要求一定要有key比较的方法,要么传入Comparator比较器实现,要么key对象实现Comparator接口

b.是非线程安全的

StringBuffer和StringBuilder

StringBuffer和StringBuilder都继承自AbstractStringBuilder类,在AbstractStringBuilder中也是使用字符数组保存字符串的

1、在执行速度方面比较:StringBuilder > StringBuffer

2、他们都是字符串变量,是可改变的对象,每当我们用他们对字符串做操作时,实际上是在一个对象上操作的,不像String一样创建一些对象进行操作,所以速度快

3、StringBuilder:非线程安全

4、StringBuffer:线程安全

对应String、StringBuilder和StringBuffer三者使用总结:

1、如果要操作少量的数据使用String

2、单线程操作大量字符串缓存区使用StringBulider

3、多线程操作大量字符串缓存区使用StringBuffer

猜你喜欢

转载自blog.csdn.net/qq501569325/article/details/89472086