jvm第7节-锁(偏向锁,轻量锁,自旋锁)
为什么80%的码农都做不了架构师?>>>
在介绍锁之前我们先介绍一个线程不安全的例子,一个全局的list,开2个线程往里面插入数据,代码如下:
package com.jvm.day6.lock.demo;import java.util.ArrayList;
import java.util.List;/*** 测试都线程共享一个变量带来的现象* @Author:xuehan* @Date:2016年3月20日下午3:35:29*/
class NumberAdd implements Runnable{public static List<Integer> numberList =new ArrayList<Integer>();public static int startNum;public NumberAdd(int startNum){this.startNum = startNum;}@Overridepublic void run() {int count = 0;while(count < 1000000){numberList.add(count ++ );startNum = startNum + 2;}}
}
public class Test{public static void main(String[] args) throws Exception {Thread t1 = new Thread(new NumberAdd(1));Thread t2 = new Thread(new NumberAdd(0));t1.start();t2.start();while(t1.isAlive() || t2.isAlive()){Thread.sleep(2);}System.out.println("集合大小" + NumberAdd.numberList.size() );System.out.println( "最后一个值的大" + NumberAdd.numberList.get(NumberAdd.numberList.size() - 1));for(int i = NumberAdd.numberList.size() - 10 ; i < NumberAdd.numberList.size() -1; i ++){System.out.println(NumberAdd.numberList.get(i));}}
}
按照开始想的,集合里面应该有200万个数据了,结果却出现了数组越界的错误,为什么呢,这是因为ArrayList不是线程安全的,用来存放数据的elementData是共享的, 线程A往list里添加数据的时候刚验证大小通过,还没有插入,然后轮到线程B执行,线程B刚好插入了list该扩容的最后一个元素,然后list满了,线程A执行,A线程往集合里面插入元素,引起了数据越界。
jvm锁
每个对象都一个mark头,他的作用是:
Mark Word,对象头的标记,32位
描述对象的hash、锁信息,垃圾回收标记,年龄
指向锁记录的指针
指向monitor的指针
GC标记
偏向锁线程ID
package com.jvm.day6.lock;import java.util.List;
import java.util.Vector;/***使用 偏向锁-XX:+UseBiasedLocking -XX:BiasedLockingStartupDelay=0* 不使用偏向锁-XX:-UseBiasedLocking* 根据测试下面代码使用偏向锁可提高150毫秒执行时间 150/2300,提高效率6% * @Author:xuehan* @Date:2016年3月19日下午12:06:15*/
public class DeflectionLock {public static List<Integer> numberList =new Vector<Integer>();public static void main(String[] args) throws InterruptedException {System.out.println((int)'l');long begin=System.currentTimeMillis();int count=0;int startnum=0;while(count<10000000){numberList.add(startnum);startnum+=2;count++;}long end=System.currentTimeMillis();System.out.println(end-begin);}
}
根据我的写实偏向锁可以提高性能6%
如果轻量级锁失败,表示存在竞争,升级为重量级锁(常规锁)
在没有锁竞争的前提下,减少传统锁使用OS互斥量产生的性能损耗
在竞争激烈时,轻量级锁会多做很多额外操作,导致性能下降
上面的一些锁不是Java语言层面的锁优化方法
他们是内置于JVM中的获取锁的优化方法和获取锁的步骤
偏向锁可用会先尝试偏向锁
轻量级锁可用会先尝试轻量级锁
以上都失败,尝试自旋锁
再失败,尝试普通锁,使用OS互斥量在操作系统层挂起
我们可以从以下方面对锁进行优化
减少锁的时间
没必须放在同步块的代码尽量不要放在代码块里
减少锁的粒度
将大对象,拆成小对象,大大增加并行度,降低锁竞争
偏向锁,轻量级锁成功率提高
实现的例子如ConcurrentHashMap
使用若干个Segment :Segment<K,V>[] segments
Segment中维护HashEntry<K,V>
put操作时
先定位到Segment,锁定一个Segment,执行put
在减小锁粒度后, ConcurrentHashMap允许若干个线程同时进入
锁分离
根据功能进行锁分离
ReadWriteLock
读多写少的情况,可以提高性能
读写分离思想可以延伸,只要操作互不影响,锁就可以分离
LinkedBlockingQueue
队列
链表
锁粗化
通常情况下,为了保证多线程间的有效并发,会要求每个线程持有锁的时间尽量短,即在使用完公共资源后,应该立即释放锁。只有这样,等待在这个锁上的其他线程才能尽早的获得资源执行任务。但是,凡事都有一个度,如果对同一个锁不停的进行请求、同步和释放,其本身也会消耗系统宝贵的资源,反而不利于性能的优化
for(int i=0;i<1000;i++){synchronized(lock){}}
// 应该写成
synchronized(lock){for(int i =0; i < 1000; i ++){}
}
这时候我们要增加锁的持有时间不要让请求和释放锁频繁的发生
锁消除
在java方法体里如果不是共享的变量不需要同步操作的,这时候jvm会自动的优化把锁去掉,如StingBuffer和Vector,使用锁消除
-server -XX:+DoEscapeAnalysis -XX:+EliminateLocks
关闭锁消除
-server -XX:+DoEscapeAnalysis -XX:-EliminateLocks
无锁
锁是悲观的操作
无锁是乐观的操作
无锁的一种实现方式
CAS(Compare And Swap),CAS是原子的
非阻塞的同步
CAS(V,E,N)
在应用层面判断多线程的干扰,如果有干扰,则通知线程重试,一般这样做会让程序变的复杂,但性能更加好。
转载于:https://my.oschina.net/zaxb/blog/1544121
jvm第7节-锁(偏向锁,轻量锁,自旋锁)相关推荐
- 并发系列三:证明分代年龄、无锁、偏向锁、轻量锁、重(chong)偏向、重(chong)轻量、重量锁
前言 上篇文章咱们了解了synchronized关键字的常见用法.对象头以及证明了一个对象在无锁状态下的对象头markwork部分的前56位存储的是hashcode.接下来,咱们继续来根据对象头分别证 ...
- 自旋锁和互斥锁实例_多线程编程之自旋锁
一.什么是自旋锁 一直以为自旋锁也是用于多线程互斥的一种锁,原来不是! 自旋锁是专为防止多处理器并发(实现保护共享资源)而引入的一种锁机制.自旋锁与互斥锁比较类似,它们都是为了解决对某项资源的互斥使用 ...
- Linux 锁机制(3)之自旋锁
Linux 锁机制(3)之自旋锁 1. 自旋锁 1.1 两种锁 1.2 自旋锁 1.3 自旋名字来源:自旋锁一直循环等待,直到获取锁为止. 1.4 自旋锁优点: 2 自旋锁特点/使用: 2.1 临界区 ...
- 一文看懂临界区、互斥锁、同步锁、临界区、信号量、自旋锁等名词!
点击上方"业余草",选择"置顶公众号" 第一时间获取技术干货和业界资讯! 关于线程安全的专有名词有一大堆.你们突然之间问我这个名词是什么意思,那个名词是什么意思 ...
- 自旋锁与互斥锁的对比、手工实现自旋锁
自旋锁与互斥锁的对比.手工实现自旋锁 版权声明:本文为博主原创文章,转载请注明出处,谢谢. https://blog.csdn.net/FreeeLinux/article/details/53695 ...
- 2021面试 Lock,synch,dcl双检查锁sy+volite,悲观锁,偏向,轻量锁,重量锁,升级12
0.数据库悲观锁:for update: MySQL实现悲观锁_九色鹿-CSDN博客_mysql悲观锁怎么实现 1. ReentrantLock锁公平与非公平实现.重入原理: ReentrantLo ...
- 锁优化:逃逸分析、自旋锁、锁消除、锁粗化、轻量级锁和偏向锁
1. 逃逸分析 Escape Analysis 1.1 逃逸分为两种: 方法逃逸:当一个对象在方法中被定义后,可能作为调用参数被外部方法说引用. 线程逃逸:通过复制给类变量或者作为实例变量在其他线程中 ...
- 轻量级锁的加锁和解锁逻辑-自旋锁
轻量级锁在加锁过程中,用到了自旋锁 所谓自旋,就是指当有另外一个线程来竞争锁时,这个线程会在原地循环等待,而不是把该线程给阻塞,直到那个获得锁的线程释放锁之后,这个线程就可以马上获得锁的. 注意,锁在 ...
- 【面试 分布式锁详细解析】续命 自旋锁 看门狗 重入锁,加锁 续命 解锁 核心源码,lua脚本解析,具体代码和lua脚本如何实现
Redisson实现分布式锁原理 自己实现锁续命 在 controller 里开一个 线程 (可以为 守护线程) 每10秒,判断一个 这个 UUID是否存在,如果 存在,重置为 30秒. 如果不存在, ...
- Juc07_乐观锁和悲观锁、公平锁和非公平锁、递归锁(可重入锁)、死锁及排查、自旋锁
文章目录 ①. 乐观锁和悲观锁 ②. 公平锁和非公平锁 ③. 可重入锁(又名递归锁) ④. 死锁及排查 ⑥. 自旋锁 ①. 乐观锁和悲观锁 ①. 悲观锁(synchronized关键字和Lock的实现 ...
最新文章
- Python break语句,continue语句,pass 语句
- HDU-3068-最长回文 (Manacher算法)
- 如何解决问题:程序无法正常启动(0xc0000022)
- 【Microsoft Word】Aurora插入公式点击Refresh,提示Problems running LaTex解决方法
- 零基础学Java有哪些必看书?推荐这5本
- 深度学习之生成对抗网络(2)GAN原理
- JDBC 数据库连接操作——实习第三天
- 语句练习题 折纸、阶乘、阶乘求和、范围内条件查找(水仙花数)。
- 调用指定目录下的批处理bat_批处理(.bat)的奇技淫巧
- 以软件开发周期来说明不同的测试的使用情况
- Sturts2【四】 StrutsPrepareAndExecuteFilter源码分析二
- VMware Workstation pro无法在Windows上运行的解决方法
- lme4 | 在R中运行混合效应模型(多层模型)
- 阿里云视频点播 和HLS加密解密
- CentOS7关于hostname
- 普通二维码跳转微信小程序
- 关闭Postman v5.0自动更新
- java ibm notes_使用Java API从Lotus Notes NSF文件中提取电子邮件
- 特斯拉“深陷”召回/监管调查,“高田气囊门”是前车之鉴
- 测绘资质专业类别及乙级作业限制范围是什么?