写点与Java中的集合和锁相关的内容,大多都和面试相关,如有错误望在评论区指正
这些东西是室友小F深夜教的,总结的不是特别好,见谅。
hashmap的复杂度是O(1)
一、
先说一下list。List 的两个实现类是arraylist和linklist
- Linklist实现方法是链表,特点是很方便的进行扩容,新建一个节点,接到链表的尾部,缺点是只擅长顺序查找,遍历,不能随机访问。
- Arraylist底层实现是数组,特点是随机查找,不擅长扩容,arraylist的底层数组有个最大值,是没法变的,超过阈值,就会扩容,建立一个两倍这么大的数组,把原来数组里的数腾到新的数组上,花的时间更长。
有一个两全其美的办法,map
二、
Hashmap ,数据结构是数组加链表,数组是怎么实现的,想象有0~15这16个坑,擅长被随机查找,每个坑里存放一个链表,先存一个3,在a3容器中,这时候想装19,规定一个方法,叫hashcode,可重写,想办法把超过最大值的数取余,19 % 16 = 3,所以也放在a3中,所以a3有3和19。这样通过hashcode来确定把数字放在哪个坑里面,就可以快速进行随机查找。为了提高查询速度,hashmap也会扩容,就是扩展坑的数量,尽量保证一个坑里的数量不超过5个,Java1.5之后,新功能:如果坑中的链表长度超过8,链表会变成新的数据结构,红黑树,加速查找,二分查找。当大于8的时候从链表变成红黑树,小于7会变回链表。7~8就相当于一个缓冲区。
- Hashtable是线程安全的,但问题很大,因为他的所有方法都加了synchronized修饰,有人在访问hashtable的时候其他线程都不能访问,效率太低
- Hashmap线程不安全,快,两个线程可以同时访问一个map,
三、
推出了一个concurrent hashmap,分水岭是1.8之前和之后,
原来的hashtable是对方法加锁,比如有人访问hashmap,那其他人就无法访问,比如要访问3这个坑,只对3这个坑加锁,
四、
锁分两种:悲观锁和乐观锁,
- 悲观锁的特点是:当有一个进程进到被锁住的内容内,其他的进程想进来的话会被阻塞住。
- 乐观锁的特点是(cas)compare and
swap:一个线程进入了,其他线程也可以进,当第一个线程进了,找到一个数字3,想把3变成4,但其他线程也想读取3,而且读到了,如果第一个线程读到了3,而且把3变成了4,又放回去了,这时候其他线程还拿着3想把3变成5呢,等变成了5,一放回去,发现原来的3没了,这个时候compare比较,如果原来的还是3,则把3变成5,但如果发现原来的数字变了,变成4了,后续就要根据实际情况实际考虑了。
两种锁的使用场景:
- 悲观锁:所有人都在抢资源,但只能一个人占有,一个人占有的时候其他人会被阻塞。适合纠纷很厉害
- 乐观锁:所有人都在抢资源,而且所有人也都能抢到,一个人改了数字,其他人重算,再抢,再改,再重算。。。适合有纠纷不是很严重的
悲观锁的代表就是Java里面的sychronized,
Java里面没有关键字实现乐观锁,只有特定的类或者方法,比如sychronized里面使用了乐观锁,还有Java里面有一个类叫原子类,atomic。
补充:
- Hashset使用hashmap实现的。
- Hashmap是唯一允许键值为空的。