Jvm内部锁机制总结

来源:互联网 发布:嗯淘宝网店教学视频 编辑:程序博客网 时间:2024/06/18 09:47
一、线程安全和对象头Mark
每个对象都有一个对象头标记Mark(32位)
Mark描述对象hash、锁信息、垃圾回收标记、年龄

二、锁的分类
偏向锁:(只在单线程有效)
--------- 偏心锁,锁会偏向让当前已经持有锁的线程持有
--------- Mark中:标记为偏向,写入线程ID
--------- 只要没有竞争,获得偏向锁的线程将来进入同步块不需要同步(提高性能)
--------- 其它线程请求相同锁时(产生竞争),偏向模式结束
--------- 启用偏向锁: -XX:+UseBiasedLocking(默认启用)


轻量级锁
-------- BasicObjectLock(嵌入在栈中的对象):Mark对象头+锁指针
-------- 性能高,快速锁定
-------- 没有竞争时,使用轻量级锁。有竞争时(性能下降),升级为重量级锁。

自旋锁
-------- 竞争存在时,如果某个线程获取了锁,就让线程做几个空操作(自旋)
-------- JDK 1.7以上内置实现
-------- 同步块很长,自旋容易失败(需要操作系统挂起线程、还空操作消耗了系统资源),降低系统性能
-------- 同步块短,自旋成功率高(不需要操作系统挂起线程),提高系统性能

JVM获取锁的步骤:尝试获取偏向锁---》尝试获取轻量级锁-----》尝试获取自旋锁-----》获取普通锁

三、锁的操作优化
减少锁持有时间
-------- 只同步需要同步的代码块

减小锁粒度
-------- 大对象拆成小对象,降低锁竞争
-------- 提供偏向锁、轻量级锁成功率
-------- HashMap的同步实现:
Collections.synchronizedMap(Map m)获得一个同步的hasnMap,其中get和put方法都被synchronized,每次只能被一个线程访问,效率低。
-------- ConcurrentHashMap通过减小锁粒度优化:
将HashMap底层的数组分段,分层若干个Segment,每次put、get操作只锁定一个Segment数组段,因此允许多线程同时访问ConcurrentHashMap,提供系统效率。

锁分离
-------- 对锁功能进行分类
-------- 读写锁的实现:ReadWriteLock,读锁和读锁不互斥,读锁和写锁,写锁和写锁互斥。
-------- 阻塞链表队列的实现:LinkedBlockingQueue,put和take操作互不影响,不需要锁住整个链表,只需要take和put持有不同的锁即可。
 

锁粗化
-------- 减少synchronized的出现次数,多个锁合并在一个锁执行。
 

锁消除(JVM编译器执行)
-------- 编译时,发现某个对象不能被多线程访问,JVM编译器会将锁消除。

无锁操作(乐观锁)
-------- 乐观认为不存在多线程竞争,首先尝试无竞争状态实现代码,如果执行时发现有竞争,退而求其次通知线程重试
-------- 实现方式:CAS(Compare And Swap)比较交换操作(CPU指令):
CAS(V, Expect, New):传入三个参数,V为需要操作的线程,Expect为线程正常运行期望得到的结果,New为线程赋予的新值。当且仅当V线程的值正常执行结果为Expect时,才把新值New赋值给V
-------- java.util.concurrent.atomic.AtomicInteger中的CAS操作(无锁实现):
1
public final int getAndSet(int newValue){//设置新值,返回旧值
2
    for(;;;){
3
        int current = get();//查看当前线程的期望值
4
        if (compareAndSet(current, newValue))//查看期望值current在compareAndSet方法中是否正确,如果正确则设置新值
5
            return current;
6
    }
7
}


参考资料:http://blog.csdn.net/zhaoqiang121121/article/details/45673011