锁的类型
(1)显式锁:ReentrantLock ,实现juc 里Lock ,实现的是基于ReentrantLock类中的lock()和unlock(0方法
(2)隐式锁:Synchronized 加锁的机制,jvm的内置锁,它不需要手动进行加锁,jvm会自动加锁
jvm内置锁通过synchronized使用 ,通过内部的(监视器锁)来实现,基于进入进入与退出Monitor对象的实现方法与代码同步,监视起的底层依赖于操作系统的mutex lock(互斥锁)实现,是一个重要的重量级的锁,性能比较低
monitorenter |
代码段 |
monitorexit |
jvm底层monitor 的实现代码
synchronized的加锁的方式主要有
1.同步类方法 ,锁是当前类对象
public static synchronized syn()
2.同步实例方法 ,所示当前实例对象,在spring容器中必须是single
public synchronized syn()
3.同步代码块,锁是括号里面的对象
对象的内存结构
使用synchronized 进行对象锁的时候,必须有一个对象,来记录当前 所得状态
(1)对象头:如 hash 码 ,对象属性的所属年代,对象锁,所得状态标志,偏向锁(线程)ID ,偏向时间,数组的长度
(2)对象实际数据:创建对象时候,对象中成员变量,方法等
(3)对齐填充:对象的大小必须位8字节的整数倍
在对对象进行进行锁的时候会出现逃逸分析
逃逸:正常来说,对象创建实例后会存放到堆中,然而部分会创建在当前线程的栈中
Java1.7之后会自动配置开启逃逸分析
关闭逃逸分析,同时调大堆空间,避免堆内GC的发生,如果有GC信息将会被打印出来 VM运行参数:-Xmx4G -Xms4G -XX:-DoEscapeAnalysis -XX:+PrintGCDetails -XX:+HeapDumpOnOutOfMemoryError 开启逃逸分析 VM运行参数:-Xmx4G -Xms4G -XX:+DoEscapeAnalysis -XX:+PrintGCDetails -XX:+HeapDumpOnOutOfMemoryError 执行main方法后 jps 查看进程 jmap -histo 进程ID
出现逃逸行为的方式
1.同步省略。如果一个对象被发现只能从一个线程倍访问到,那么对于这个对象的操作,可以不用考虑同步
比如 synchronized(new Object){} 当前这个object 对象是动态创建的每一个对象进行使用的时候都是不同的,所以jvm对其进行了优化,不会存放到堆中而是当前的线程栈中
2.将堆分配转化位栈分配。如果一个对象在子程序中被分配,要使指向该对象的指针永远不会发生逃逸,对象可能是栈分配的候选,而不是堆分配
3.分离对象或者标量替换。有的对象可能不需要作为一个连续的内存结构存在也可以被访问到,那么对象的部分(或全部)可以不存储在内存,而是CPU寄存器中。
在获取锁的过程中,锁会进行膨胀,无锁》偏向锁》轻量级锁》重量级锁,锁的升级是由低到高不能逆转
偏向锁:java1.6之后为了减少获取锁和释放锁(从用户态到内核态)的开销,出现了偏向锁和轻量级锁, 如果一个线程获取了锁,那么锁就进入了偏向模式,此时Mark Word 的结构也会转 向偏向锁结构,当这个线程再次请求锁的时候,无序再做任何同步操作,既获取锁的过程,这样就会省去大量有关锁的操作,提高性能
轻量级锁:如果偏向锁失败,虚拟机不会立即升级位重量级锁,它还会尝试使用一种称为轻量级锁的优化手段(1.6之后加入),此时Mark Word 的结构也会变为轻量级锁的结构。轻量级锁适应的场景是线程交 替执行同步块的场合,如果存在同一时间访问同一锁的场合,如果没有获取锁不会立即升为重量级的锁,而是进行锁的自旋,为了避免线程真实地在操作系统层面挂起,因为从用户态到内核态的开销比较大,就是空转,因为每个线程占用CPU的时间片都会很短,在进行自选之后如果不能获取锁就会升级为重量级锁
锁的粗化:
是jvm对锁的一种优化方式
这是另外一种锁的优化方式,java 虚拟机在JIT编译的时候(可以简单理解为当某段代码即将第一次被执行时进行编译,又称及时编译),通过对运行上下文扫描,去除不可能存在共享资源竞争的锁,通过这种方式可以节省毫无意义的请求锁的时间。
如 StringBuffer sb=new StringBuffer();
sb.append("a")
sb.append("b")
因为StrinbBuffer是线程安全的每次进行append 里面有synchronized同步方法,但是进行连续添加的时候,虚拟机不会给每一个添加锁而是 对其进行优化
synchronized(this){
sb.append("a")
sb.append("b")
}
锁的消除.
当 synchronized(new Object){}
jvm对其进行优化的时候不会对其进行加锁,因为当前的对象只会被当前线程所使用,其中的方法不会加锁