AQS
AQS(AbstractQueuedSynchronizer)是RetrentLock与Java并发包工具的实现根底,其底层采纳乐观锁,大量应用了CAS操作,并且在抵触时,采纳自旋形式重试,以实现轻量级锁和高效的获取锁
CAS的全称为Compare-And-Swap,是一条CPU的原子指令,其作用是让CPU比拟后原子地更新某个地位的值,通过考察发现,其实现形式是基于硬件平台的汇编指令,就是说CAS是靠硬件实现的,JVM只是封装了汇编调用
其实现次要由状态、队列、CAS三局部组成:
状态:在AQS中,状态由state属性来示意,该属性的值示意了锁的状态,state为0示意锁没有被占用,state大于0示意已被占用
队列:在AQS中,队列的实现是一个双向链表,它示意所有期待锁的线程的汇合,当线程获取锁失败时通过CAS操作将本人退出队列的开端
CAS操作:操作系统层面提供的API,CAS是一条CPU原语,其蕴含三个操作数——内存地位、预期原值和新值,如果内存地位的值与预期原值相匹配,那么处理器会主动将该地位值更新为新值
执行流程
- 线程尝试获取锁,将state的状态通过CAS操作由0改写成1
- 未获取到锁,则将本人封装成node,通过CAS操作退出队列尾部
- 如果前置节点是头节点,则会再次尝试获取锁
- 将前驱节点状态设置为signal后,通过LockSupport.park,挂起以后线程
- 拿到锁的线程执行完逻辑后,通过LockSupport.unPark唤起后置节点线程,后置节点线程则会再次尝试去获取锁
AQS超时机制
通过LockSupport的parkNanos实现
并发容器
ConcurentHashMap实现
jdk1.7
- 应用一个Segment数组和多个HashEntry组成,每个数组桶位上面挂一个HashEntry
- 当执行put操作时,会进行第一次key的hash来定位Segment的地位,如果该Segment还没有初始化,即通过CAS操作进行赋值,而后进行第二次hash操作,找到相应的HashEntry的地位,再通过ReentrantLock进行加锁后,将数据增加HashEntry中的对应地位
jdk1.8
- 与HashMap构造统一,底层是数组+链表或数组加红黑树结构实现
- 作流程是,对key进行hash运算定位到数组下标,如果下标地位链表为空则先初始化,再cas插入,如果有数据,则用同步锁Synchronized对数组桶位进行加锁后插入
这个改变阐明了jdk团队认为通过优化后的Synchronized比ReentrantLock效率高
ThreadLocal
ThreadLocal是一个线程隔离变量
ThreadLocal.set办法相当于给以后线程的TheadLocalMap属性赋值,key就是TheadLocal本人,value是要set的值
应用场景:
- 多线程应用一些线程不平安的工具类时,ThreadLocal复用工具对象
- 用来传递上下文,能够防止对象的跨层传递。(定义一个工具类,类中定义一个TheadLocal动态属性,通过工具类调用TheadLocal的set和get办法)
- 具体场景:之前oracle迁徙mysql数据库时,切换开关应用ThreadLocal保留至以后线程,防止开关值的上下文传递
内存泄露场景:
因为TheadLocalMap与线程生命周期统一,在应用线程池等线程生命周期长的场景应用TheadLocal时,如不手动执行remove操作,value便不会被回收,造成内存泄露