美文网首页
随笔读并发包源码

随笔读并发包源码

作者: baiyin1115 | 来源:发表于2018-12-20 11:57 被阅读0次

    最近在读并发包源码,喜欢的就记录下。

    源码解析系列===》写的挺不错,强烈推荐看源码时候对着他的讲解看,能省好多事。(貌似得翻墙。。。。)


    • Excutor
      ThreadPoolExcutor是线程池实现的核心,可以比对下面这篇文章一起看,作者总结的不错。
      深度解读 java 线程池设计思想及源码实现
      如果你读过aqs的实现+reentrantLock源码,这ThreadPoolExcutor就简单多了,感觉Doug Lea大神先有了个状态state+队列的idea,创造了aqs,完了创造了五颜六色的世界。
      ThreadPoolExcutor里面真正管理执行线程的是Worker这个内部类,他继承了aqs,相当于对当前线程做了增强,有了锁特性、
      可以hang在BlockingQueue的take方法上去等待任务、执行的时候检查线程池的状态,你通过excute方法区执行线程的时候,其实是交给worker去处理。
      面试的时候经常会问ThreadPoolExcutor线程池的corePoolSize、keepAliveTime、RejectedExecutionHandler、workQueue、maximumPoolSize几个参数的意思啥的,让你说说线程池运行的规则,网上会有一堆文章,你临时补补呢,也能说个89不离10,其实呢,静下心来,抱着学习的目的看看源码,也挺有意思的,记忆还深刻。

    线程池的线程实现了Cyclic Work Distribution=== 循环工作分配模式

    这部分好有意思:
    ConcurrentHashMap在处理rehash的时候,并不会重新计算每个key的hash值,而是利用了一种很巧妙的方法。我们在上一篇说过,ConcurrentHashMap内部的table数组的大小必须为2的幂次,原因是让key均匀分布,减少冲突,这只是其中一个原因。另一个原因就是:

    当table数组的大小为2的幂次时,通过key.hash & table.length-1这种方式计算出的索引i,当table扩容后(2倍),新的索引要么在原来的位置i,要么是i+n。

    我们来看个例子:


    image.png

    上图中:
    扩容前,table数组大小为16,key1和key2映射到同一个索引5;
    扩容后,table数组的大小变成 2*16=32 ,key1的索引不变,key2的索引变成 5+16=21。
    而且还有一个特点,扩容后key对应的索引如果发生了变化,那么其变化后的索引最高位一定是1(见扩容后key2的最高位)。

    这种处理方式非常利于扩容时多个线程同时进行的数据迁移操作,因为旧table的各个桶中的结点迁移不会互相影响,所以就可以用“分治”的方式,将整个table数组划分为很多部分,每一部分包含一定区间的桶,每个数据迁移线程处理各自区间中的结点,对多线程同时进行数据迁移非常有利,后面我们会详细介绍。

    相关文章

      网友评论

          本文标题:随笔读并发包源码

          本文链接:https://www.haomeiwen.com/subject/lcvwhqtx.html