一、基础概念
1、重进入
当一个线程请求已被其他线程占有的锁时,请求线程会被阻塞。
但当一个线程请求被自己占有的锁时,请求会成功。即可重进入
2、volatile和锁
锁可以保证可见性和原子性;
volatile只能保证可见性;
四大屏障;
3、CAS
3.1 CAS并发原语体现在Java中就是sun.misc.Unsafe类的各个方法。调用Unsafe中的CAS方法,JVM会帮我们实现出CAS汇编指令。这是一种完全依赖于硬件的功能,通过它实现了原子操作。
由于CAS是一种系统原语,原语的执行必须是连续的,且不允许中断,也就是说CAS是一条CPU的原子指令,不会造成数据不一致的问题。
3.2 原子引用 AtomicReference
3.3 手写自旋锁
3.4 CAS缺点
1、循环时间长开销大
2、ABA问题----AtomicStampedReference
4、Monitor
hotspot中,monitor采用ObjectMonitor实现。
每一个对象都天生带着ObjectMonitor,每一个被锁住的对象都会和Monitor关联起来
5、原子类
1、分类:基本原子类、数组原子类、
引用原子类:AtomicReference,AtomicStampedReference,AtomicMarkableReference
原子更新对象属性:AtomicIntegerFieldUpdater,AtomicLongFieldUpdater,AtomicReferenceFieldUpdater
必须使用int类型,否则报错
AtomicReferenceFieldUpdater
2、LongAdder和LongAccumulator
LongAdder比AtomicLong在大吞吐量时性能显著,减少乐观锁次数;
LongAdder只适用于累加,只能从0开始;
LongAdder 继承 Striped64 继承 Number
LongAdder总体思想:分散热点,将value值分散到一个Cell数组中,不同线程会命中到数组的不同槽中,各个线程只对自己槽中的值进行CAS操作。如果要获取真正的Long值,只需将各个槽中的值累加返回。
初始化cell数组:
扩容
6、ThreadLocal
6.1 初步解释
ThreadLocal提供线程局部变量,这些变量与正常的变量不同,因为每一个线程在访问ThreadLocal实例的时候,都有自己的、独立初始化的变量副本。ThreadLocal实例通常是类中的私有静态字段,使用他的目的是希望将状态与线程关联起来
6.2 使用注意
使用完成后调用remove(),删除此线程局部变量的当前线程值。
6.3 源码分析
1、Thread,ThreadLocal,ThreadLocalMap的关系
2、get方法
首先获取当前线程的成员变量threadLocals,即一个ThreadLocalMap,若map为null,则进行初始化;
初始化的过程,即创建一个ThreadLocalMap,赋值给当前线程的threadLocals。
6.4 内存泄漏问题
1、内存泄漏:不再会被使用的对象或变量占用的内存不能被回收
2、强引用(Reference):对于强引用对象,就算出现了OOM,也不会对该对象进行回收
强引用是我们最常见的普通对象引用。
3、软引用(SoftReference):对于只有软引用的对象,当系统内存充足时不会回收,系统内存不足时会回收。
4、弱引用(WeakReference):对于只有弱引用的对象,只要垃圾回收器一运行,不管jvm的内存是否足够,都会被回收。
5、虚引用(PhantomReference):
虚引用形同虚设,如果一个对象仅持有虚引用,那么它和没有任何引用一样,在任何时候都可能被回收,不能单独使用也不能通过它访问对象,虚引用必须和引用队列(ReferenceQueue)结合使用。被回收后会放到引用队列中,可以执行后续的操作,如事后清理操作。
虚引用的主要作用是跟踪对象被垃圾回收的状态,仅仅只是提供了一种确保对象被finalize后,做某些事情的通知机制。get方法总是返回null
6、为什么用弱引用
如上图所示,因ThreadLocalMap中存放的当前ThreadLocal的引用,而ThreadLocalMap是Thread的成员变量,当栈帧中的强引用取消时,弱引用可被回收,可大大减小内存泄漏的防线。
7、总结
7、对象内存布局
1、对象内存布局初识
对象在堆内存中的存储布局可以划分为三个部分:对象头、实例数据、对齐填充(整体保证大小为8个字节的倍数)
对象头:对象标记(Mark Word),类元信息(又叫类型指针)
2、对象头-MarkWord
包含哈希码(如obj.hashcode()),GC标记,GC次数,同步锁标记,偏向锁持有者等,默认存储HashCode,分代年龄和锁标志位等信息。
64位系统中,MarkWord占8字节
3、对象头-类元信息(类型指针)
每次new对象时的模板,指向方法区的类元信息
64位系统中,类元信息占8个字节
4、实例数据