当前位置: 首页 > wzjs >正文

专业智能建站网站友情链接交换平台

专业智能建站网站,友情链接交换平台,高端网站制,淘宝数据查询文章目录 线程安全集合类解决方案多线程环境使用顺序表多线程环境使用队列多线程环境使用哈希表ConcurrentHashMap1. 缩小锁的粒度2. 充分使用 CAS3. 针对扩容操作 线程安全集合类 ArrayList、Queue、HsahMap… 都是线程不安全的 Vector、Stack、Hashtable 都是线程安全的&am…

文章目录

  • 线程安全集合类
  • 解决方案
    • 多线程环境使用顺序表
    • 多线程环境使用队列
    • 多线程环境使用哈希表
      • ConcurrentHashMap
        • 1. 缩小锁的粒度
        • 2. 充分使用 CAS
        • 3. 针对扩容操作

线程安全集合类

ArrayListQueueHsahMap… 都是线程不安全的

VectorStackHashtable 都是线程安全的(内置了 synchronized),实际上这几个东西并不推荐使用

  • 因为这几个都是无脑加 synchronized,无论如何都要加锁,哪怕单线程也要加锁,不科学。很有可能出现阻塞,可能会使程序效率大打折扣
  • 编译器的“锁消除”并不能 100%解决问题,只能把十拿九稳的地方进行优化,有些代码是锁消除机制摸不透的

解决方案

多线程环境使用顺序表

  1. 自己加锁

image.png

  • ArrayList 套了个壳。ArrayList 各种操作本身不带锁,通过上述套壳之后,得到了新的对象,新的对象里面的关键方法都是带有锁的

  1. 使用 CopyOnWriteArrayList

这里面主要用到了“写实拷贝

  • 线程安全问题,在多个线程修改同一个数据的时候会触发

image.png|482

  • 把顺序表复制一份,修改新的顺序表内容,然后修改引用的指向,这样就不会有线程安全问题
    • “修改引用指向”这个操作是原子的,不需要加锁

这种操作有很大的局限性

  1. 修改不能太频繁(复制开销很大)
  2. 顺序表也不应该太大

一般在服务器加载配置文件的时候,就要把配置文件的内容解析出来,放到内存的数据结构中(顺序表/哈希表…)

  • 服务器的修改频率很低
  • 配置文件一般体积都不大(几 kb)

多线程环境使用队列

  1. 自己加锁
  2. BlockingQueue(线程安全的)

多线程环境使用哈希表

HashMap 肯定不行,它是线程不安全的。更靠谱的是 Hashtable,其在一些关键方法上添加了 synchornized,但这个不好用

  • 他俩区别就是有无 synchornized

后来标准库又引入了一个更好的解决方案:ConcurrentHashMap

ConcurrentHashMap

改进:

1. 缩小锁的粒度

image.png|485

  • Hashtable 是直接在方法上使用 synchornized,相当于是对 this 加锁,整个哈希表就只有这一把锁,此时,尝试修改两个不同链表上的元素,都会触发锁冲突(Hashtable 底层实现是数组+链表)

  • 锁的粒度很大,是一个全局锁,同一时刻只能有一个线程访问整个哈希表。

  • 仔细观察就可以发现,如果修改两个不同链表上的元素,不涉及到线程安全问题(修改不同变量)

    • 如果修改的是同一个链表上的元素,就可能涉及到线程安全问题
    • 比如这俩变量在链表上的位置是相邻的,操作引用的时候,就可能涉及到操作同一个引用
  • 此时,针对同一个链表操作,再加锁;针对不同链表操作,就不必加锁了(不要产生锁冲突)


ConcurrentHashMap 就是把锁变小了,给每一个链表都发了一个锁image.png

  • 弄出了这么多锁,会付出更多空间的代价吗?
    • 不会;Java 中,任何一个对象都可以直接作为锁对象。本身哈希表中就得有数组,数组的元素都是已经存在的(每个链表的头结点),此时,只要使用数组元素(链表头结点)作为加锁的对象即可

image.png|405

  • 每个链表就是构成桶的一个木板。所谓“锁桶”,就是针对每个木板(每个链表)分别加锁的

Java 1.7 及其之前,ConcurrentHashMap 是通过“分段锁”来实现的

  • 给若干个链表分配一把锁
  • 这种设定,不太合适,实现更复杂,效率也不够高,还要引入额外的空间开销(重新定义锁)
    Java 8 开始,这里的设定就变成每个链表一把锁了
2. 充分使用 CAS

充分使用 CAS 原子操作,减少了一些加锁

  • 比如,针对哈希表元素个数的维护

synchornized 里面不是刚开始是偏向锁或者轻量级锁,速度很快吗?

  • synchornized 有可能成为重量级锁,并且是否升级了不可控
3. 针对扩容操作

扩容是一个重量操作

0.75 是负载因子默认的扩容阈值,不是负载因子本体

  • 负载因子是你算出来的数
  • 拿着实际的元素个数/数组长度(桶的个数)算出来的数值,这个值可能是 0.1,可能是 0.5 可能是 1,可能是 10
  • 然后我们拿着这个值和扩容阈值进行比较,看看是否需要扩容

负载因子:描述了每个桶上面平均有多少个元素

  • 此时桶上的链表的元素不应该太长,才能保证遍历的时间复杂度为 O ( 1 ) O(1) O(1)

如果太长:

  1. 变成树(长度不平均的情况)
  2. 扩容
    • 创建一个更大的数组,把旧的 Hash 表的元素都给搬运到(删除/插入)到新的数组上
    • 如果 hash 表本身元素非常多,这里的扩容操作就会消耗很长时间
    • hash 表平时都很快,突然间某个操作就变慢了,过一会又快了(表现不稳定,坏事)
    • 我们无法控制何时触发扩容,一旦触发扩容,就会导致这次操作非常耗时(用户直观感受:卡顿)

HashMap 的扩容操作是一把梭哈,在某一次插入元素操作中,整体完成扩容(就会卡顿,耗时)

ConcurrentHashMap 的策略是“化整为零,蚂蚁搬家

  • 每次只搬运一部分元素
  • 假设有 1kw 个元素,此时扩容的时候,每次插入/查找/删除,都会搬运一部分元素(每次搬运 5k 个元素),一共花 2k 次搬完(花的时间更长,但是值得)
  • 确保每操作消耗的时间都不会很长,避免出现很卡的情况

在扩容过程中,同时存在两份哈希表,一份是新的,一份是旧的

  • 插入操作:直接往新的上插入
  • 删除操作:新的旧的都直接删除
  • 查找操作:新的旧的都要查询一下
http://www.dtcms.com/wzjs/596032.html

相关文章:

  • 厦门海投工程建设有限公司网站资料网站模板
  • 乾安网站建设公司电话长寿做网站的电话
  • 网站建设网络推广书生牙科医院网站建设
  • 鄂州网站设计效果建立全国统一的突发事件信息系统
  • 亚马逊网站运营怎么做网站开发与设计岗位职责
  • 桐乡做网站网站开发成本报表
  • 企业网站seo优ppt做书模板下载网站
  • 德阳住房和城乡建设局网站做电商能赚钱吗
  • 网站设计的性能需求完整的网络营销推广方案包括
  • 网站的域名怎么看网站建设中 倒计时
  • 中国建设劳动学会网站东莞做网站哪家公司好
  • 网站备案找谁程序开发接单
  • 盛泽建设局网站做淘宝客网站域名是别人的
  • 做旅游网站包括哪些栏目网站建设开发价格高吗
  • 电子商务网站建设结论活动策划方案
  • wordpress跳转到不同分站nas可以做视频网站吗
  • 嘉定做网站的wordpress可the7
  • 东莞市专注网站建设怎么样东莞网页制作价格
  • 深圳app网站建设陈俊兵wordpress点餐主题
  • php wap网站实现滑动式数据分页全国村级网站建设
  • 内容分享网站设计网站收录情况
  • 外贸网站建设官网便民工具 网站开发
  • it培训机构哪个好些刷关键词排名seo软件
  • 如何搭建公司内部网站网站建设要备案吗
  • 做现货去哪些网站营销好呢网站功能需求用什么做
  • 网站生成工具二级域名网站有哪些
  • 17做网站官网门户类网站备案
  • 电商网站如何做东莞seo站内优化
  • 深圳证券网站开发网站建设管理规范
  • 星沙做网站宿迁市建设局网站首页