1.2java Map相关知识笔记

HashMap(允许null、不同步)

HashMap及与HashTable的比较:HashMap(允许null、不同步,数组+链表+红黑树),HashTable(不允许key和value为null,线程安全,数组+链表)

HashTable替代:ConcurrentHashMap,不允许null

再散列,桶数*2

tableSizeFor(),返回一个大于输入参数且最接近2的整数此幂的数。

用&实现取余,用&oldcap实现扩容时元素移动与否判断(移动oldcap或不动)

LinkedHashMap(允许null,不同步,有序)

可用来实现LRU算法(Least Recently Used最近最少使用)页面置换常用算法。

插入顺序与访问顺序

access-ordered linked hash maps(LRU)和insertion-ordered hash maps(此时修改已有key的value不是结构性修改),默认是插入顺序

对于访问顺序,它是LRU(最近最少使用)算法的实现,要使用它要么重写LinkedListMap的几个方法(removeEldestEntry(Map.Entry<K,V> eldest重写它可以删除最久未被使用的元素)和afterNodeInsertion(boolean evict)新增时判断是否需要删除最久未被使用的元素),要么是扩展成LRUMap来使用,不然设置为访问顺序(access-ordered)的用处不大

散列表+双向链表

初始容量对遍历没有影响从内部维护的双链表的表头开始循环输出

在构建新节点时构建的是LinkedHashMap.Entry不再是Node(继承HashMap的Node节点)重写了newNode方法

多态是无处不在的(子类用父类的方法,子类重写了父类的部分方法即可达到不一样的效果)比如:LinkedHashMap并没有重写put方法,而put方法内部的newNode()方法重写了。LinkedHashMap调用父类的put方法,里面回调的是重写后的newNode(),从而达到目的!

TreeMap(红黑树,非同步,有序,key不为空)

containsKeys、get、put、remove时间复杂度为logn

TreeMap实现有序要么就是外界传递进来Comparator对象(compare方法),要么就使用默认key的Comparable()接口(compareTo方法)(实现自然排序);

TreeMap有序是通过Comparator来进行比较的,如果comparator为null,那么就使用自然顺序。(如果在构造方法中传递了Comparator对象,那么就会以Comparator对象的方法进行比较。否则,则使用Comparable的compareTo(T o)方法来比较。

  1. 如果使用的是compareTo(T o)方法来比较,key一定是不能为null,并且得实现了Comparable接口的。
  2. 即使是传入了Comparator对象(用compare比较),不用compareTo(T o)方法来比较,key也是不能为null的

modCount指结构性修改的次数。(遍历时可用于判断是否在遍历的同时更改了结构ConcurrentModificationException)

TreeMap遍历是使用EntryIterator这个内部类

  1. 由于底层是红黑树,那么时间复杂度可以保证为log(n)
  2. key不能为null,为null为抛出NullPointException的
  3. 想要自定义比较,在构造方法中传入Comparator对象,否则使用key的自然排序来进行比较
  4. TreeMap非同步的,想要同步可以使用Collections来进行封装

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-f4GEffAa-1645971546430)(E:\note\image\Comparator.png)]

ConcurrentHashMap(1.8散列表+红黑树,不允许key或value为null)

只允许一个线程对散列表进行初始化。

get方法非阻塞。

Node节点是重写的,设置了volatile关键字修饰,致使它每次获取的都是最新设置的值。

JDK1.7的底层是:segments+HashEntry数组。

  • Hashtable是在每个方法上都加上了Synchronized完成同步,效率低下。
  • ConcurrentHashMap通过在部分加锁利用CAS算法来实现同步。

CAS算法与volatile关键字(通过部分锁与CAS算法实现线程安全)

CAS(一种乐观锁)(比较与交换,Compare and swap),是一种有名的无锁算法。

有三个操作数(内存值V、旧的预期值A、要修改的新值B)

当且仅当预期值A和内存值V相等时,将内存值V修改为B,否则什么都不做。

当多个线程尝试使用CAS同时更新同一个变量时,只有其中一个线程能更新变量的值(A和内存值V相同时,将内存值V修改为B),而其它线程都失败,失败的线程并不会被挂起,而是被告知这次竞争中失败,并可以再次尝试(否则什么都不做)

volatile仅仅用来保证该变量对所有线程的可见性,但不保证原子性。

不要将volatile用在getAndOperate场合,仅仅set或者get的场景是适合volatile的。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-KmBfdLa2-1645971546431)(E:\note\image\volatile.png)]

load到store之间是不安全的

volatile,Java内存模型将在写操作后插入一个写屏障指令,在读操作前插入一个读屏障指令。这意味着如果你对一个volatile字段进行写操作,你必须知道:1、一旦你完成写入,任何访问这个字段的线程将会得到最新的值。写入字段时所有线程都可以获得2、在你写入前,会保证所有之前发生的事已经发生,并且任何更新过的数据值也是可见的,因为内存屏障会把之前的写入值都刷新到缓存。强制刷新一次缓存

不能用于构建原子的复合操作,因此当一个变量依赖旧值时就不能使用volatile变量。

特别地,long型赋值不是原子操作,用volatile修饰后long型赋值可变为原子操作。

http://www.cnblogs.com/Mainz/p/3556430.html

https://www.cnblogs.com/Mainz/p/3546347.html

http://www.dataguru.cn/java-865024-1-1.html

ps://www.cnblogs.com/Mainz/p/3546347.html

http://www.dataguru.cn/java-865024-1-1.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值