`

jvm第7节-锁(偏向锁,轻量锁,自旋锁)

 
阅读更多

在介绍锁之前我们先介绍一个线程不安全的例子,一个全局的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;
	}
	@Override
	public 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

 

偏向锁
jvm控制,可以设置jvm启动参数
大部分情况是没有竞争的,所以可以通过偏向来提高性能
所谓的偏向,就是偏心,即锁会偏向于当前已经占有锁的线程
将对象头Mark的标记设置为偏向,并将线程ID写入对象头Mark
只要没有竞争,获得偏向锁的线程,在将来进入同步块,不需要做同步
当其他线程请求相同的锁时,偏向模式结束
-XX:+UseBiasedLocking -jdk6需要手动打开
默认启用
在竞争激烈的场合,偏向锁会增加系统负担
偏向锁是系统自带的设置参数开启,java代码如下:
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%
轻量级锁 BasicObjectLock,这个锁是嵌入到线程栈中的,他有两部组成BasicLock和ptr to obj hold the lock,BasicLock里面存放着对象头,ptr to obj hold the lock为指向持有对象锁的指针
普通的锁处理性能不够理想,轻量级锁是一种快速的锁定方法。
如果对象没有被锁定
将对象头的Mark指针保存到锁对象中
将对象头设置为指向锁的指针(在线程栈空间中)

如果轻量级锁失败,表示存在竞争,升级为重量级锁(常规锁)

在没有锁竞争的前提下,减少传统锁使用OS互斥量产生的性能损耗

 

在竞争激烈时,轻量级锁会多做很多额外操作,导致性能下降

自旋锁
当竞争存在时,如果线程可以很快获得锁,那么可以不在OS层挂起线程,让线程做几个空操作(自旋)
JDK1.6中-XX:+UseSpinning开启
JDK1.7中,去掉此参数,改为内置实现
如果同步块很长,自旋失败,会降低系统性能
如果同步块很短,自旋成功,节省线程挂起切换时间,提升系统性能
 

上面的一些锁不是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)

在应用层面判断多线程的干扰,如果有干扰,则通知线程重试,一般这样做会让程序变的复杂,但性能更加好。

  • 大小: 21.5 KB
  • 大小: 32.5 KB
  • 大小: 19.5 KB
  • 大小: 6.7 KB
  • 大小: 19.5 KB
  • 大小: 4.6 KB
1
1
分享到:
评论

相关推荐

    Java并发篇乐观锁,悲观锁,自旋锁

    - **实现**:synchronized基于Monitor机制,通过JVM实现,锁状态有无锁、偏向锁、轻量级锁和重量级锁四种。 - **轻量级锁**:在没有多线程竞争时,减少传统重量级锁的开销,适应线程交替执行同步块的场景。如果...

    偏向锁-轻量级锁-重量级锁

    本文将详细解析Java中的偏向锁、轻量级锁和重量级锁,这些都是JVM为了提高并发性能而实现的锁优化策略。 首先,我们从最简单的偏向锁开始。**偏向锁**的设计理念是假设大多数情况下,锁都不会被多个线程竞争。当一...

    java 偏向锁、轻量级锁及重量级锁synchronized原理.docx

    总的来说,Java的`synchronized`通过对象头的Mark Word和Monitor对象实现了线程安全的同步机制,同时引入了偏向锁、轻量级锁和自旋锁等优化手段,以平衡性能和线程安全性。理解这些锁的工作原理对于编写高性能的并发...

    nginx-upstream-jvm-route-1.15

    【标题】"nginx-upstream-jvm-route-1.15" 涉及的核心知识点是Nginx的upstream模块与JVM路由的整合,特别针对Nginx 1.15版本。这个项目旨在解决在配置Nginx时遇到的特定错误提示“nginx: [emerg] invalid parameter ...

    synchronized锁自旋.docx

    本文将深入探讨`synchronized`锁的内部机制,包括自旋锁、自适应自旋锁以及轻量锁和偏向锁。 首先,`synchronized`锁通常被称为对象锁或重量锁,它基于Java虚拟机(JVM)中的Monitor对象实现。Monitor由对象头中的2...

    JVM调优总结 Xms -Xmx -Xmn -Xss

    ### JVM调优总结:Xms、Xmx、Xmn、Xss 在Java虚拟机(JVM)的运行过程中,合理的参数配置对于提高程序性能至关重要。本文将对JVM调优中的几个关键参数进行深入解析,包括-Xms、-Xmx、-Xmn和-Xss等,帮助开发者更好...

    JVM调优总结 -Xms -Xmx -Xmn -Xss

    JVM调优总结 -Xms -Xmx -Xmn -Xss JVM 调优是 Java virtual machine 的性能优化,通过调整 JVM 的参数来提高 Java 应用程序的性能。其中,-Xms、-Xmx、-Xmn、-Xss 是四个重要的参数,分别控制 JVM 的初始堆大小、...

    metrics-jvm-3.1.5-API文档-中文版.zip

    赠送jar包:metrics-jvm-3.1.5.jar; 赠送原API文档:metrics-jvm-3.1.5-javadoc.jar; 赠送源代码:metrics-jvm-3.1.5-sources.jar; 赠送Maven依赖信息文件:metrics-jvm-3.1.5.pom; 包含翻译后的API文档:...

    第3节: 揭秘JVM运行时数据区-02

    第3节: 揭秘JVM运行时数据区-02第3节: 揭秘JVM运行时数据区-02第3节: 揭秘JVM运行时数据区-02第3节: 揭秘JVM运行时数据区-02第3节: 揭秘JVM运行时数据区-02第3节: 揭秘JVM运行时数据区-02第3节: 揭秘JVM运行...

    java jvm 参数 -Xms -Xmx -Xmn -Xss -

    Java虚拟机(JVM)是Java程序运行的基础,它负责解释和执行字节码。在JVM中,内存管理是至关重要的,而`-Xms`, `-Xmx`, `-Xmn`, `-Xss`等参数则直接影响着Java应用程序的性能和稳定性。这些参数是用来调整JVM堆内存...

    基于jvm-sandbox-repeater重新开发的一款流量回放平台产品

    Moonbox(月光宝盒)是JVM-Sandbox生态下的,基于jvm-sandbox-repeater重新开发的一款流量回放平台产品。在jvm-sandbox-repeater基础上提供了更加丰富功能,同时便于线上部署和使用,更多对比参考。 使用场景 你...

    Android Studio 报错failed to create jvm error code -4的解决方法

    代码如下:failed to create jvm error code -4 这一般应是内存不够用所致,解决方法参考如下。 打开 Android Studio 安装目录下的bin目录,查找并打开文件 studio.exe.vmoptions,修改代码: 代码如下:-Xmx512m 为...

    偏向锁理论太抽象,实战了解下偏向锁如何发生以及如何升级【实战篇】.doc

    而当t3尝试第20个元素时,由于撤销次数达到阈值,后续的锁将直接是轻量级锁,直到撤销总数达到40,JVM不再使用偏向锁,直接上轻量级锁。 在实际应用中,理解和掌握偏向锁、轻量级锁和重量级锁的升级过程对于优化多...

    jvm知识点整理-脑图

    jvm知识点整理-脑图

    metrics-jvm-3.1.5-API文档-中英对照版.zip

    赠送jar包:metrics-jvm-3.1.5.jar; 赠送原API文档:metrics-jvm-3.1.5-javadoc.jar; 赠送源代码:metrics-jvm-3.1.5-sources.jar; 赠送Maven依赖信息文件:metrics-jvm-3.1.5.pom; 包含翻译后的API文档:...

    jvm调优测试仓库-jvm-monitor.zip

    1. JVisualVM:JDK自带的轻量级工具,提供丰富的JVM监控功能,包括线程、堆内存、类加载、Garbage Collector、JMX等信息。 2. JConsole:同样是JDK自带的工具,提供GUI界面,可监控JVM的性能和诊断问题。 3. ...

    jvm全面知识详解-全网最全(JVM面试题)

    jvm全面知识详解-全网最全(JVM面试题)

    JVM的调优总结----------

    ### JVM调优总结 #### 1. JVM配置 在Java应用程序的运行过程中,JVM(Java虚拟机)扮演着至关重要的角色。为了确保应用程序能够高效稳定地运行,正确配置JVM参数至关重要。以下是一些常见的JVM配置参数及其含义: ...

    jvm性能调优-jvm内存模型和优化-performance-jvm-memorymodel-optimize.zip

    《JVM性能调优:深入理解JVM内存模型与优化》 在Java开发中,JVM(Java Virtual Machine)性能调优是提升应用程序效率的关键环节。JVM内存模型的理解和优化,对于解决性能瓶颈、避免内存泄漏以及提高系统稳定性至关...

Global site tag (gtag.js) - Google Analytics