五、 锁应用
2016-07-14 00:39
246 查看
5.1、线程安全
多线程访问ArrayList。代码:
publicstatic List<Integer> numberList =new ArrayList<Integer>();
publicstatic class AddToList implements Runnable{
int startnum=0;
public AddToList(int startnumber){
startnum=startnumber;
}
@Override
public void run() {
int count=0;
while(count<1000000){
numberList.add(startnum);
startnum+=2;
count++;
}
}
}
publicstatic void main(String[] args) throws InterruptedException {
Thread t1=new Thread(new AddToList(0));
Thread t2=new Thread(new AddToList(1));
t1.start();
t2.start();
while(t1.isAlive() || t2.isAlive()){
Thread.sleep(1);
}
System.out.println(numberList.size());
}
5.2、偏向锁
n 大部分情况是没有竞争的,所以可以通过偏向来提高性能n 所谓的偏向,就是偏心,即锁会偏向于当前已经占有锁的线程
n 将对象头Mark的标记设置为偏向,并将线程ID写入对象头Mark
n 只要没有竞争,获得偏向锁的线程,在将来进入同步块,不需要做同步
n 当其他线程请求相同的锁时,偏向模式结束
n -XX:+UseBiasedLocking
– 默认启用
n 在竞争激烈的场合,偏向锁会增加系统负担
代码:
publicstatic List<Integer> numberList =new Vector<Integer>();
publicstatic void main(String[] args) throws InterruptedException {
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);
}
-XX:+UseBiasedLocking-XX:BiasedLockingStartupDelay=0
-XX:-UseBiasedLocking
5.3、轻量级锁
– 嵌入在线程栈中的对象普通的锁处理性能不够理想,轻量级锁是一种快速的锁定方法。
如果对象没有被锁定:
1) 将对象头的Mark指针保存到锁对象中
2) 将对象头设置为指向锁的指针(在线程栈空间中)
如果轻量级锁失败,表示存在竞争,升级为重量级锁(常规锁)
在没有锁竞争的前提下,减少传统锁使用OS互斥量产生的性能损耗
在竞争激烈时,轻量级锁会多做很多额外操作,导致性能下降
5.4、自旋锁
n 当竞争存在时,如果线程可以很快获得锁,那么可以不在OS层挂起线程,让线程做几个空操作(自旋)n JDK1.6中-XX:+UseSpinning开启
n JDK1.7中,去掉此参数,改为内置实现
n 如果同步块很长,自旋失败,会降低系统性能
n 如果同步块很短,自旋成功,节省线程挂起切换时间,提升系统性能
内置于JVM中的获取锁的优化方法和获取锁的步骤
– 偏向锁可用会先尝试偏向锁
– 轻量级锁可用会先尝试轻量级锁
– 以上都失败,尝试自旋锁
– 再失败,尝试普通锁,使用OS互斥量在操作系统层挂起
5.5、synchronized
1)减少锁持有时间publicsynchronized void syncMethod(){
othercode1();
mutextMethod();
othercode2();
}
将synchronized置于代码块中
public voidsyncMethod2(){
othercode1();
synchronized(this){
mutextMethod();
}
othercode2();
}
2)减小锁的粒度
将大对象,拆成小对象,大大增加并行度,降低锁竞争
偏向锁,轻量级锁成功率提高
HashMap的同步实现
public Vget(Object key) {
synchronized (mutex) {returnm.get(key);}
}
public V put(Kkey, V value) {
synchronized (mutex) {returnm.put(key, value);}
}
5.6、锁分离
n 根据功能进行锁分离n ReadWriteLock
n 读多写少的情况,可以提高性能
| 读锁 | 写锁 |
读锁 | 可访问 | 不可访问 |
写锁 | 不可访问 | 不可访问 |
n LinkedBlockingQueue
5.7、锁粗化
通常情况下,为了保证多线程间的有效并发,会要求每个线程持有锁的时间尽量短,即在使用完公共资源后,应该立即释放锁。只有这样,等待在这个锁上的其他线程才能尽早的获得资源执行任务。但是,凡事都有一个度,如果对同一个锁不停的进行请求、同步和释放,其本身也会消耗系统宝贵的资源,反而不利于性能的优化for(inti=0;i<CIRCLE;i++){
synchronized(lock){
}
}
synchronized(lock){
for(inti=0;i<CIRCLE;i++){
}
}
5.8、消除锁
在即时编译器时,如果发现不可能被共享的对象,则可以消除这些对象的锁操作public static void main(String args[])throws InterruptedException {
longstart = System.currentTimeMillis();
for(int i = 0; i < CIRCLE; i++) {
craeteStringBuffer("JVM","Diagnosis");
}
longbufferCost = System.currentTimeMillis() - start;
System.out.println("craeteStringBuffer:" + bufferCost + " ms");
}
public static StringcraeteStringBuffer(String s1, String s2) {
StringBuffersb = new StringBuffer();
sb.append(s1);
sb.append(s2);
returnsb.toString();
}
设置CIRCLE= 2000000
-server -XX:+DoEscapeAnalysis-XX:+EliminateLocks
createStringBuffer: 187 ms
-server -XX:+DoEscapeAnalysis-XX:-EliminateLocks
createStringBuffer: 254 ms
相关文章推荐
- ViewGroup事件分发
- 四、 监控分析
- 7.5 将一个数组中的值按逆序重新存放(改)
- 三、 GC算法
- Centos7安装杀毒软件ClamAV
- unity中实现 幸运转轮
- 郭郭自学笔记(2):堆排序2.0
- 剑指offer系列-T24_2二叉搜索树的后序遍历序列
- 安装程序时出现2502 2503错误解决方法
- REDHAT6.5实现Nginx+Tomcat+Memcache负载均衡
- 两台主机网线直连
- 二、 JVM参数调试
- 水平垂直居中问题解法
- AndroidStudio使用SVN
- 一、 jvm运行机制
- hdu 1232 畅通工程并查集版
- Flume快速入门(五):File Channel之重播(replay)
- Memcached内存管理slabclass
- 【慢速学数据结构】集合(并查集)篇
- VS2013的 Browser Link 引起的问题