精华内容
下载资源
问答
  • 前言:java的线程是映射到操作系统的原生线程上的,如果要阻塞和唤醒线程,需要操作系统帮忙,要从用户态转为核心态,需要花费很多处理器时间。

    前言:java的线程是映射到操作系统的原生线程上的,如果要阻塞和唤醒线程,需要操作系统帮忙,要从用户态转为核心态,需要花费很多处理器时间。

    java对象 在内存布局中分三部分:对象头,实例数据,对齐填充。

    对象头里面有一个锁标志位,无锁状态为:01,偏向锁的锁标志位值为:01,轻量级锁值为:00,重量级锁为:10 ,

    无锁和偏向锁的值都是01 ,如何区分?还有一个是否偏向锁的标志位。无锁为0,偏向锁为1.

    偏向锁和轻量级锁都是锁的优化,主要是为了可以减少线程获取锁和释放锁的次数,偏向锁的对象头会存储当前获取锁的线程的id,根据这个id,当该线程再次执行加锁的方法不需再次获取锁。轻量级锁的对象头会指向栈帧中锁记录的指针,当线程再次执行此同步代码块时,判断当前对象的 Mark Word 是否指向当前线程的栈帧,如果是则表示当前线程已经持有当前对象的锁,则直接执行同步代码块;重量级锁通过对象内部的监视器(ObjectMonitor)实现,其本质是依赖于底层操作系统的 Mutex Lock 实现,操作系统实现线程之间的切换需要从用户态到内核态的切换,成本非常高。

    展开全文
  • 在本文中小编给的大家整理了关于Java锁的升级策略 偏向锁 轻量级锁 重量级锁的相关知识点内容,需要的朋友们参考下。
  • Java线程并发中常见的锁--自旋锁 偏向锁 轻量级锁 轻量级锁

    随着互联网的蓬勃发展,越来越多的互联网企业面临着用户量膨胀而带来的并发安全问题。本文着重介绍了在java并发中常见的几种锁机制。 

    1.偏向锁

     

    偏向锁是JDK1.6提出来的一种锁优化的机制。其核心的思想是,如果程序没有竞争,则取消之前已经取得锁的线程同步操作。也就是说,若某一锁被线程获取后,便进入偏向模式,当线程再次请求这个锁时,就无需再进行相关的同步操作了,从而节约了操作时间,如果在此之间有其他的线程进行了锁请求,则锁退出偏向模式。在JVM中使用-XX:+UseBiasedLocking

    复制代码
    复制代码
    package jvmProject;
    
    import java.util.List;
    import java.util.Vector;
    
    public class Biased {
    
        public static List<Integer> numberList = new Vector<Integer>();
        public static void main(String[] args) {
            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);
        }
    }
    复制代码
    复制代码

     

    初始化一个Vector,往里面添加10000000个Integer对象,然后输出时间差。以此来测试偏向锁的性能。至于为什么要使用Vector而不使用ArrayList呢?

    因为ArrayList是线程不安全的,Vector是线程安全的。这样说可能还不够具体,可以翻看一下源码吧。

    Vector中的几乎所有操作是带有sychronized的,而ArrayList是没有的,所以Vector是线程安全的。

    接下来我们来测试一下,开启偏向锁和不开启偏向锁对程序性能的影响有多大。

     

     

    配置JVM启动(开启偏向锁)参数为:

     

     

     

    配置JVM启动(关闭偏向锁)参数为:

     

     

    Perfect!开启偏向锁的程序运行时间明显较短,开启偏向锁比不开启偏向锁,在单个线程中操作一个对象的同步方法,是有一定的优势的。其实也可以这样理解,当只有一个线程操作带有同步方法的Vector对象的时候,此时对Vector的操作就转变成了对ArrayList的操作。

     

    偏向锁在锁竞争激烈的场合没有太强的优化效果,因为大量的竞争会导致持有锁的线程不停地切换,锁也很难保持在偏向模式,此时,使用偏向锁不仅得不到性能的优化,反而有可能降低系统的性能,因此,在激烈竞争的场合,可以尝试使用

    -XX:-UseBiastedLocking参数禁用偏向锁。

     

    2.轻量级锁

     

    如果偏向锁失败,Java虚拟机就会让线程申请轻量级锁,轻量级锁在虚拟机内部,使用一个成为BasicObjectLock的对象实现的,这个对象内部由一个BasicLock对象和一个持有该锁的Java对象指针组成。BasicObjectLock对象放置在Java栈帧中。在BasicLock对象内部还维护着displaced_header字段,用于备份对象头部的Mark Word.

    当一个线程持有一个对象的锁的时候,对象头部Mark Word信息如下

    [ptr                       |00] locked  

    末尾的两位比特为00,整个Mark Word为指向BasicLock对象的指针。由于BasicObjectLock对象在线程栈中,因此该指针必然指向持有该锁的线程栈空间。当需要判断一个线程是否持有该对象时,只需要简单地判断对象头的指针是否在当前线程的栈地址范围即可。同时,BasicLock对象的displaced_header,备份了原对象的Mark word内容,BasicObjectLock对象的obj字段则指向持有锁的对象头部。

     

    3.重量级锁

     

    当轻量级锁失败,虚拟机就会使用重量级锁。在使用重量级锁的时,对象的Mark Word如下:

    [ptr                     |10]  monitor

     

    重量级锁在操作过程中,线程可能会被操作系统层面挂起,如果是这样,线程间的切换和调用成本就会大大提高。

     

    4.自旋锁

          自旋锁可以使线程在没有取得锁的时候,不被挂起,而转去执行一个空循环,(即所谓的自旋,就是自己执行空循环),若在若干个空循环后,线程如果可以获得锁,则继续执行。若线程依然不能获得锁,才会被挂起。

    使用自旋锁后,线程被挂起的几率相对减少,线程执行的连贯性相对加强。因此,对于那些锁竞争不是很激烈,锁占用时间很短的并发线程,具有一定的积极意义,但对于锁竞争激烈,单线程锁占用很长时间的并发程序,自旋锁在自旋等待后,往往毅然无法获得对应的锁,不仅仅白白浪费了CPU时间,最终还是免不了被挂起的操作 ,反而浪费了系统的资源。

    在JDK1.6中,Java虚拟机提供-XX:+UseSpinning参数来开启自旋锁,使用-XX:PreBlockSpin参数来设置自旋锁等待的次数。

    在JDK1.7开始,自旋锁的参数被取消,虚拟机不再支持由用户配置自旋锁,自旋锁总是会执行,自旋锁次数也由虚拟机自动调整。

     

    展开全文
  • 今天简单了解了一下java轻量级锁和重量级锁以及偏向锁。看了看这篇文章觉得写的不错 原文链接 java 偏向锁轻量级锁及重量级锁synchronized原理 Java对象头与Monitor java对象头是实现synchronized的锁对象的基础,...

    今天简单了解了一下java轻量级锁和重量级锁以及偏向锁。看了看这篇文章觉得写的不错
    原文链接

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

    Java对象头与Monitor

    java对象头是实现synchronized的锁对象的基础,synchronized使用的锁对象是存储在Java对象头里的。

    对象头包含两部分:Mark Word 和 Class Metadata Address

    在这里插入图片描述

    其中Mark Word在默认情况下存储着对象的HashCode、分代年龄、锁标记位等以下是32位JVM的Mark Word默认存储结构

    在这里插入图片描述

    由于对象头的信息是与对象自身定义的数据没有关系的额外存储成本,因此考虑到JVM的空间效率,Mark Word 被设计成为一个非固定的数据结构,以便存储更多有效的数据,它会根据对象本身的状态复用自己的存储空间,如32位JVM下,除了上述列出的Mark Word默认存储结构外,还有如下可能变化的结构:

    在这里插入图片描述

    重量级锁synchronized的实现
    重量级锁也就是通常说synchronized的对象锁,锁标识位为10,其中指针指向的是monitor对象(也称为管程或监视器锁)的起始地址。每个对象都存在着一个 monitor 与之关联,对象与其 monitor 之间的关系有存在多种实现方式,如monitor可以与对象一起创建销毁或当线程试图获取对象锁时自动生成,但当一个 monitor 被某个线程持有后,它便处于锁定状态。

    在这里插入图片描述

    上图简单描述多线程获取锁的过程,当多个线程同时访问一段同步代码时,首先会进入 Entry Set当线程获取到对象的monitor 后进入 The Owner 区域并把monitor中的owner变量设置为当前线程,同时monitor中的计数器count加1,若线程调用 wait() 方法,将释放当前持有的monitor,owner变量恢复为null,count自减1,同时该线程进入 WaitSet集合中等待被唤醒。若当前线程执行完毕也将释放monitor(锁)并复位变量的值,以便其他线程进入获取monitor(锁)。

    由此看来,monitor对象存在于每个Java对象的对象头中(存储的指针的指向),synchronized锁便是通过这种方式获取锁的,也是为什么Java中任意对象可以作为锁的原因,同时也是notify/notifyAll/wait等方法存在于顶级对象Object中的原因。

    自旋锁与自适应自旋
    Java的线程是映射到操作系统的原生线程之上的,如果要阻塞或唤醒一个线程,都需要操作系统来帮忙完成,这就需要从用户态转换到核心态中,因此状态转换需要耗费很多的处理器时间,对于代码简单的同步块(如被synchronized修饰的getter()和setter()方法),状态转换消耗的时间有可能比用户代码执行的时间还要长。

    虚拟机的开发团队注意到在许多应用上,共享数据的锁定状态只会持续很短的一段时间,为了这段时间去挂起和恢复线程并不值得。如果物理机器有一个以上的处理器,能让两个或以上的线程同时并行执行,我们就可以让后面请求锁的那个线程“稍等一下“,但不放弃处理器的执行时间,看看持有锁的线程是否很快就会释放锁。为了让线程等待,我们只需让线程执行一个忙循环(自旋),这项技术就是所谓的自旋锁。

    自旋锁在JDK1.4.2中引入,使用-XX:+UseSpinning来开启。JDK1.6中已经变为默认开。自旋等待不能代替阻塞。自旋等待本身虽然避免了线程切换的开销,但它是要占用处理器时间的,因此,如果锁被占用的时间很短,自旋等待的效果就会非常好,反之,如果锁被占用的时间很长,那么自旋的线程只会浪费处理器资源。因此,自旋等待的时间必须要有一定的限度,如果自旋超过了限定次数(默认是10次,可以使用-XX:PreBlockSpin来更改)没有成功获得锁,就应当使用传统的方式去挂起线程了。

    JDK1.6中引入自适应的自旋锁,自适应意味着自旋的时间不在固定。而是有虚拟机对程序锁的监控与预测来设置自旋的次数。

    自旋是在轻量级锁中使用的

    轻量级锁
    轻量级锁提升程序同步性能的依据是:对于绝大部分的锁,在整个同步周期内都是不存在竞争的(区别于偏向锁)。这是一个经验数据。如果没有竞争,轻量级锁使用CAS操作避免了使用互斥量的开销,但如果存在锁竞争,除了互斥量的开销外,还额外发生了CAS操作,因此在有竞争的情况下,轻量级锁比传统的重量级锁更慢。

    轻量级锁的加锁过程:
    在代码进入同步块的时候,如果同步对象锁状态为无锁状态(锁标志位为“01”状态,是否为偏向锁为“0”),虚拟机首先将在当前线程的栈帧中建立一个名为锁记录(Lock Record)的空间,用于存储锁对象目前的Mark Word的拷贝,官方称之为 Displaced Mark Word。这时候线程堆栈与对象头的状态如图:

    在这里插入图片描述

    拷贝对象头中的Mark Word复制到锁记录(Lock Record)中;

    拷贝成功后,虚拟机将使用CAS操作尝试将锁对象的Mark Word更新为指向Lock Record的指针,并将线程栈帧中的Lock Record里的owner指针指向Object的 Mark Word。
    如果这个更新动作成功了,那么这个线程就拥有了该对象的锁,并且对象Mark Word的锁标志位设置为“00”,即表示此对象处于轻量级锁定状态,这时候线程堆栈与对象头的状态如图所示。
    在这里插入图片描述

    如果这个更新操作失败了,虚拟机首先会检查对象的Mark Word是否指向当前线程的栈帧,如果是就说明当前线程已经拥有了这个对象的锁,那就可以直接进入同步块继续执行。否则说明多个线程竞争锁,轻量级锁就要膨胀为重量级锁,锁标志的状态值变为“10”,Mark Word中存储的就是指向重量级锁(互斥量)的指针,后面等待锁的线程也要进入阻塞状态。

    在这里插入图片描述

    偏向锁
    偏向锁是JDK6中引入的一项锁优化,它的目的是消除数据在无竞争情况下的同步原语,进一步提高程序的运行性能。

    偏向锁会偏向于第一个获得它的线程,如果在接下来的执行过程中,该锁没有被其他的线程获取,则持有偏向锁的线程将永远不需要同步。大多数情况下,锁不仅不存在多线程竞争,而且总是由同一线程多次获得,为了让线程获得锁的代价更低而引入了偏向锁。

    当锁对象第一次被线程获取的时候,线程使用CAS操作把这个线程的ID记录在对象Mark Word之中,同时置偏向标志位1。以后该线程在进入和退出同步块时不需要进行CAS操作来加锁和解锁,只需要简单地测试一下对象头的Mark Word里是否存储着指向当前线程的ID。如果测试成功,表示线程已经获得了锁。

    当有另外一个线程去尝试获取这个锁时,偏向模式就宣告结束。根据锁对象目前是否处于被锁定的状态,撤销偏向后恢复到未锁定或轻量级锁定状态。
    在这里插入图片描述

    偏向所锁,轻量级锁及重量级锁
    偏向所锁,轻量级锁都是乐观锁,重量级锁是悲观锁。
    一个对象刚开始实例化的时候,没有任何线程来访问它的时候。它是可偏向的,意味着,它现在认为只可能有一个线程来访问它,所以当第一个
    线程来访问它的时候,它会偏向这个线程,此时,对象持有偏向锁。偏向第一个线程,这个线程在修改对象头成为偏向锁的时候使用CAS操作,并将
    对象头中的ThreadID改成自己的ID,之后再次访问这个对象时,只需要对比ID,不需要再使用CAS在进行操作。
    一旦有第二个线程访问这个对象,因为偏向锁不会主动释放,所以第二个线程可以看到对象时偏向状态,这时表明在这个对象上已经存在竞争了,检查原来持有该对象锁的线程是否依然存活,如果挂了,则可以将对象变为无锁状态,然后重新偏向新的线程,如果原来的线程依然存活,则马上执行那个线程的操作栈,检查该对象的使用情况,如果仍然需要持有偏向锁,则偏向锁升级为轻量级锁,(偏向锁就是这个时候升级为轻量级锁的)。如果不存在使用了,则可以将对象回复成无锁状态,然后重新偏向。
    轻量级锁认为竞争存在,但是竞争的程度很轻,一般两个线程对于同一个锁的操作都会错开,或者说稍微等待一下(自旋),另一个线程就会释放锁。 但是当自旋超过一定的次数,或者一个线程在持有锁,一个在自旋,又有第三个来访时,轻量级锁膨胀为重量级锁,重量级锁使除了拥有锁的线程以外的线程都阻塞,防止CPU空转。

    展开全文
  • 转载——java 中的锁 – 偏向锁轻量级锁、自旋锁、重量级锁
    展开全文
  • java多线程 偏向锁 轻量级锁 重量级锁 java的对象有三个存储区域,对象头,实例数据,对齐填充。 其中对象头中由两部分区域: 1:对象的类型指针,jvm通过这个指针可以找到该对象是哪个类的实例。但是访问对象的...
  • Java偏向锁轻量级锁

    2018-06-30 15:32:29
    Java SE 1.6对锁进行了大量优化工作,引入轻量级锁偏向锁,这里只对这两种优化作说明。Java SE 1.6中的锁状态分为无锁、偏向锁、轻量锁、重量锁4种,级别依次递增,性能越来越差,且升级后不允许降级,这么做能在...
  • [Java并发] synchronize 锁升级 偏向锁 轻量级锁 自旋锁笔记synchronized 实现原理与应用Java 对象头 - synchronized 锁锁的升级:自旋锁、自适应自旋锁、轻量级锁与偏向锁自旋锁自适应自旋锁轻量级锁偏向锁锁对比锁...
  • 1 前言 在Java SE1.6之前,synchronized一直都是重量级锁,如果某个...在Java SE1.6之后,为了减少获得锁和释放锁带来的性能消耗而引入的偏向锁轻量级锁,以及锁的存储结构和升级过程。这些锁就存在锁对象的对象...
  •   资源消耗 目的 ... 单线程进行同步块时,消除轻量级锁的CAS操作。 大多数场景为单线程访问同步块,一旦有竞争,偏向锁失效。 判断markword是否...
  • Java中的偏向锁轻量级锁, 重量级锁解析

    万次阅读 多人点赞 2018-08-13 18:39:49
    参考文章 聊聊并发(二)Java SE1.6中的Synchronized Lock Lock Lock: Enter! 5 Things You Didn’t Know About Synchronization in Java and Scala ...Java 中的Java 中主要2种加锁机制: synchr...
  • 先Mark,后补充 参照: https://www.infoq.cn/article/java-se-16-synchronized http://www.cnblogs.com/paddix/p/5405678.html http://www.cnblogs.com/lzh-blogs/p/7477157.html
  • synchronized的执行过程: 1. 检测Mark Word里面是不是当前线程的ID,如果... 如果失败,则说明发生竞争,撤销偏向锁,进而升级为轻量级锁。 4. 当前线程使用CAS将对象头的Mark Word替换为锁记录指针,如果成功,当...
  • 锁的状态总共有四种:无锁状态、偏向锁轻量级锁和重量级锁。随着锁的竞争,锁可以从偏向锁升级到轻量级锁,再升级的重量级锁(但是锁的升级是单向的,也就是说只能从低到高升级,不会出现锁的降级)。锁的状态是...
  • 文章目录什么是偏向级锁、轻量锁、重量级锁偏向锁轻量级锁重量级锁 什么是偏向级锁、轻量锁、重量级锁         首先,我们需要明确一点:这三种锁只针对synchronized &...
  • Java并发编程之偏向锁轻量级锁、重量级锁
  • https://www.cnblogs.com/deltadeblog/p/9559035.html
  • Java并发编程之自旋锁、偏向锁轻量级锁、重量级锁
  • Synchronized一直是多线程并发编程中的重要角色,但是在Java1.6中,为了减少获得锁带来的性能消耗,引入了偏向锁轻量级锁。 目录 锁的状态: 偏向锁 轻量级锁 重量级锁 偏向锁轻量级锁、重量级锁应用场景 ...
  • 由于Java面向对象的思想,在JVM中需要大量存储对象,存储时为了实现一些额外的功能,需要在对象中添加一些标记字段用于增强对象功能,这些标记字段组成了对象头。 |----------------------------------------------...
  • 其实在JDK1.5以前的早期版本,还没有那么细粒度完善的锁机制,基本上就一个synchronized打遍天下,但是从JDK1.6之后Oracle对Java锁进行了很大的改动,也就出现了偏向锁/轻量级锁机制和锁的升级/降级机制 偏向锁...
  • 始终只有一个线程在执行同步块,在它没有执行完释放锁之前,没有其它线程去执行同步块,在锁无竞争的情况下使用,一旦有了竞争就升级为轻量级锁,升级为轻量级锁的时候需要撤销偏向锁,撤销偏向锁的时候会导致stop ...
  • 轻量级锁 轻量级锁的加锁过程 释放线程锁的过程 重量级锁 相关文章 线程阻塞的代价 java的线程是映射到操作系统原生线程之上的,如果要阻塞或唤醒一个线程就需要操作系统介入,需要在户态与核心态之间切换,...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 1,948
精华内容 779
关键字:

java偏向锁轻量级锁

java 订阅