精华内容
下载资源
问答
  • 一、线程安全、 二、锁机制 ( 类锁 | 对象锁 )、 三、锁分类 ( 轻量级锁 | 重量级锁 )、





    一、线程安全



    多个线程同时访问 同一个共享变量 时 , 只要能保证 数据一致性 , 那么该变量是线程安全的 ; 这里的数据是指主内存中的共享变量以及各个线程中的变量副本 , 保证这些变量一致 , 就是线程安全 ;

    线程安全 就是保证 线程操作的 原子性 , 可见性 , 有序性 ;

    volatile 关键字可以保证 可见性 有序性 ;

    synchronized 关键字可以保证 原子性 ;





    二、锁机制 ( 类锁 | 对象锁 )



    synchronized 是 Java 提供的一种锁机制 ;

    在普通方法上加锁 , 相当于对 this 进行加锁 ; 下面两个类的 fun 方法的线程锁是等效的 ;

    public class Student {
        private synchronized void fun() {
        }
    }
    
    public class Student {
        private void fun() {
            synchronized(this){
            }
        }
    }
    

    加锁的代码块 , 在同一个时间 , 只能由 1 1 1 个线程访问 ;


    对象锁 : synchronized() 代码块中 , 括号中的参数是 作用范围 ; synchronized(this) 表示作用范围只针对当前对象 , 如果 创建了多个对象 , 这几个对象中的锁都是 不同的锁 , 相互之间没有任何关系 ;

    Student s1 = new Student();
    Student s2 = new Student();
    

    只有当多个线程 , 访问同一个对象时 , 锁才有意义 ;

    如 :
    线程 A 访问 s1 对象的 fun 方法 , 线程 B 访问 s2 对象的 fun 方法 , 两个方法之间 没有互斥效果 ;
    线程 A 访问 s1 对象的 fun 方法 , 线程 B 也想访问 s1 对象的 fun 方法 , 此时必须 等待线程 A 访问完毕 , 释放锁之后 , 才能由线程 B 访问 s1 ;


    类锁 : 如果加锁的对象是静态方法 , 那么相当于在 Student.class 类上进行加锁 ; Student.class 对象全局只有 1 1 1 个 , 调用所有对象的 fun 方法 , 都是互斥的 ;

    public class Student {
        private synchronized static void fun() {
        }
    }
    

    等价于

    public class Student {
        private static void fun() {
            synchronized(Student.class){
            }
        }
    }
    




    三、锁分类 ( 轻量级锁 | 重量级锁 )



    如果线程 A 获得锁之后 , 执行线程内容 , 其它线程等待解锁时有两种情况 :

    • 轻量级锁 : 又称为 自旋锁 , 线程 盲等待 或 自旋等待 , 即 while 循环 , 没有进入阻塞状态 , 没有进入等待队列中排队 ; ( 轻量级 )
    • 重量级锁 : 线程进入 等待队列 , 排队等待线程 A 执行完毕 ; 在该队列的线程 , 需要 等待 OS 进行线程调度 , 一旦涉及到操作系统 , 量级就变重 , 效率变低 ; ( 重量级 )

    轻量级锁弊端 : 轻量级锁 不一定 比重量级锁 更好 ; 轻量级锁 等待过程中 , 高速执行循环代码 , 如果循环的时间很短 , 时间效率上很高 ; 但是一旦执行时间很长 , 比如连续执行十几秒甚至几分钟 , 浪费了大量的 CPU 资源 ;


    使用场景 :

    • 轻量级锁 : 轻量级锁只适合 线程少 , 等待时间短的 应用场景 , 如果线程很多 , 等待时间过长 , 会造成 CPU 大量浪费 ;
    • 重量级锁 : 重量级锁等待过程中 , 线程处于阻塞状态 , 效率可能低一些 , 但是不会造成资源浪费 , 如果 线程很多 , 或 等待时间很长 , 适合使用重量级锁 ;
    展开全文
  • 自旋可以使线程在没有取得的时候,不被挂起,而转去执行一个空循环,(即所谓的自旋,就是自己执行空循环),若在若干个空循环后,线程如果可以获得,则继续执行。若线程依然不能获得,才会被挂起。 使用...
     
    1、自旋锁
    自旋锁可以使线程在没有取得锁的时候,不被挂起,而转去执行一个空循环,(即所谓的自旋,就是自己执行空循环),若在若干个空循环后,线程如果可以获得锁,则继续执行。若线程依然不能获得锁,才会被挂起。
    使用自旋锁后,线程被挂起的几率相对减少,线程执行的连贯性相对加强。因此,对于那些锁竞争不是很激烈,锁占用时间很短的并发线程,具有一定的积极意义,但对于锁竞争激烈,单线程锁占用很长时间的并发程序,自旋锁在自旋等待后,往往毅然无法获得对应的锁,不仅仅白白浪费了CPU时间,最终还是免不了被挂起的操作 ,反而浪费了系统的资源。
    在JDK1.6中,Java虚拟机提供-XX:+UseSpinning参数来开启自旋锁,使用-XX:PreBlockSpin参数来设置自旋锁等待的次数。
    在JDK1.7开始,自旋锁的参数被取消,虚拟机不再支持由用户配置自旋锁,自旋锁总是会执行,自旋锁次数也由虚拟机自动调整。

    可能引起的问题:
    1.过多占据CPU时间:如果锁的当前持有者长时间不释放该锁,那么等待者将长时间的占据cpu时间片,导致CPU资源的浪费,因此可以设定一个时间,当锁持有者超过这个时间不释放锁时,等待者会放弃CPU时间片阻塞;
    2.死锁问题:试想一下,有一个线程连续两次试图获得自旋锁(比如在递归程序中),第一次这个线程获得了该锁&#x
    展开全文
  • HotSpot虚拟机中,对象在内存中存储的布局可以分为三块区域:对象头(Object Header)、实例数据(Instance Data)和对齐填充(Padding)。 对象头(Object Header)  JVM的对象头包括二/三部分信息:1、Mark ...

    HotSpot虚拟机中,对象在内存中存储的布局可以分为三块区域:对象头(Object Header)、实例数据(Instance Data)和对齐填充(Padding)。

    对象头(Object Header)

     JVM的对象头包括二/三部分信息:1、Mark Word;2、 类型指针;3、数组长度(只有数组对象才有)

     1、Mark Word

    用于存储对象自身的运行时数据, 如哈希码(HashCode)、GC分代年龄、锁状态标志、线程持有的锁、偏向线程ID、偏向时间戳等等,这部分数据的长度在32位和64位的虚拟机(暂 不考虑开启压缩指针的场景)中分别为32个和64个Bits。

    Mark Word在不同的锁状态下存储的内容不同,在32位JVM中是这么存的:

    锁状态25bit4bit1bit2bit
    23bit2bit是否偏向锁锁标志位
    无锁对象的HashCode分代年龄001
    偏向锁线程IDEpoch偏向时间戳分代年龄101
    轻量级锁指向栈中锁记录的指针00
    重量级锁指向重量级锁的指针10
    GC标记11

    其中无锁和偏向锁的锁标志位都是01,只是在前面的1bit区分了这是无锁状态还是偏向锁状态。

    2、 类型指针 

    即是对象指向它的类的元数据的指针,虚拟机通过这个指针来确定这个对象是哪个类的实例。 并不是所有的虚拟机实现都必须在对象数据上保留类型指针,即查找对象的元数据信息并不一定要经过对象本身。

    3、数组长度 

    如果对象是一个Java数组,那在对象头中还必须有一块用于记录数组长度的数据,因为虚拟机可以通过普通Java对象的元数据信息确定Java对象的大小,但是从数组的元数据中无法确定数组的大小。 

    偏向锁

     引入偏向锁是为了在无多线程竞争的情况下尽量减少不必要多次CAS获取锁的执行过程,而偏向锁只需要在置换ThreadID的时候依赖一次CAS原子操作(由于一旦出现多线程竞争的情况就必须撤销偏向锁,所以偏向锁的撤销操作的性能损耗必须小于节省下来的CAS原子指令的性能消耗)。偏向锁则是在只有一个线程或者多个线程不同步执行同步块时进一步提高性能。

    轻量级锁

    轻量级锁是竞争锁对象的线程不多,而且线程持有锁的时间也不长的情景,如果线程阻塞需要线程之间完成线程间的通信,耗费性能(用户态和内核态状态切换),所以直接让线程进入自旋等待锁释放。

    1、偏向锁获取过程:

      (1)访问Mark Word中偏向锁的标识位(1bit)是否设置成1,锁标志位(2bit)是否为01——确认为可偏向状态。

      (2)如果为可偏向状态,则偏向锁线程ID是否指向当前线程,如果是,进入步骤(4),否则进入步骤(3)。

      (3)如果偏向锁线程ID并未指向当前线程,因为偏向锁不会主动释放,所以当前线程可以看到对象时偏向状态以及拥有该对象锁的线程,这时表明在这个对象上已经存在竞争了,检查原来持有该对象锁的线程是否依然存活,如果挂了,则可以将对象变为无锁状态,然后重新CAS操作偏向新的线程,然后执行(4);如果原来的线程依然存活,由偏向锁升级为轻量级锁(在下面进行分析)。

      (4)执行同步代码。

    2、偏向锁升级为轻量级锁过程

    偏向锁只有遇到其他线程尝试竞争偏向锁时,持有偏向锁的线程才会释放锁,线程不会主动去释放偏向锁。偏向锁的撤销,需要当到达全局安全点(safepoint)时获得偏向锁的线程被挂起,需要查看Java对象头中记录的偏向锁的线程是否存活,如果没有存活,那么修改对象头偏向锁标志位为0,其它线程可以竞争将其设置为偏向锁;如果存活,拷贝对象头中的Mark Word到该线程的栈帧中的锁记录里让lock record的指针指向锁对象头中的Mark Word,再让Mark Word指向指向lock record,唤醒线程继续执行原来线程的同步代码,则当前线程通过CAS操作竞争锁,竞争失败执行自旋操作继续竞争锁。

      ps: 全局安全点safepoint 参考 理解JVM的safepoint

    3、轻量级锁获取过程 

    线程的栈帧中有一个名为锁记录(Lock Record)的空间,用于存储锁对象目前的Mark Word的拷贝,官方称之为 Displaced Mark Word。 

    线程会拷贝对象头中的Mark Word到锁记录(Lock Record)中,然后使用CAS操作尝试将锁对象的Mark Word指针指向Lock Record,并将线程栈帧中的Lock Record里的owner指针指向Object的 Mark Word。如果更新成功,则表示获取了轻量级锁。

    4、轻量级锁膨胀重量级锁过程

    a线程获得锁,会在a线程的栈帧里创建lock record(锁记录),让lock record的指针指向锁对象的对象头中的mark word.再让mark word 指向lock record.这就是获取了锁。如果b线程在锁竞争时,发现锁已经被a线程占用,则b线程不进入内核态,让b线程自旋,执行空循环,等待a线程释放锁。如果发现a线程没有释放锁,这时候c线程也来竞争锁,那么这个时候轻量级锁就会膨胀为重量级锁。

     

    展开全文
  • 偏向锁,轻量级锁与重量级锁区别与膨胀

    万次阅读 多人点赞 2017-03-19 20:44:01
    一直被这三个锁的膨胀问题所困扰,不知道到底实在什么时候会有偏向锁升级到轻量级锁,什么时候由轻量级锁升级到重量级锁。找到好久,也没有找到简洁明了的答案。  综合多个方面的描述综合自己的理解,特地记录下来...

    一直被这三个锁的膨胀问题所困扰,不知道到底实在什么时候会有偏向锁升级到轻量级锁,什么时候由轻量级锁升级到重量级锁。找到好久,也没有找到简洁明了的答案。

           综合多个方面的描述综合自己的理解,特地记录下来。但是也有可能理解有误。

      

    先依然描述这三个锁是什么: 这里直接从《深入理解Java虚拟机》粘贴过来。

    偏向锁

           Hotspot 的作者经过以往的研究发现大多数情况下锁不仅不存在多线程竞争,而且总是由同一线程多次获得,为了让线程获得锁的代价更低而引入

    了偏向锁。当一个线程访问同步块并获取锁时,会在对象头和栈帧中的锁记录里存储锁偏向的线程 ID,以后该线程在进入和退出同步块时不需要花费

    CAS操作来加锁和解锁,而只需简单的测试一下对象头的Mark Word里是否存储着指向当前线程的偏向锁,如果测试成功,表示线程已经获得了锁,

    如果测试失败,则需要再测试下 Mark Word中偏向锁的标识是否设置成 1(表示当前是偏向锁),如果没有设置,则使用 CAS 竞争锁,如果设置了,

    则尝试使用 CAS 将对象头的偏向锁指向当前线程。

           偏向锁的撤销:偏向锁使用了一种等到竞争出现才释放锁的机制,所以当其他线程尝试竞争偏向锁时,持有偏向锁的线程才会释放锁。偏向锁的撤

    销,需要等待全局安全点(在这个时间点上没有字节码正在执行),它会首先暂停拥有偏向锁的线程,然后检查持有偏向锁的线程是否活着,如果线程

    不处于活动状态,则将对象头设置成无锁状态,如果线程仍然活着,拥有偏向锁的栈会被执行,遍历偏向对象的锁记录,栈中的锁记录和对象头的

    Mark Word要么重新偏向于其他线程,要么恢复到无锁或者标记对象不适合作为偏向锁,最后唤醒暂停的线程。


    轻量级锁

           轻量级锁加锁:线程在执行同步块之前, JVM会先在当前线程的栈桢中创建用于存储锁记录的空间,并将对象头中的Mark Word复制到锁记录中,

    官方称为Displaced Mark Word。然后线程尝试使用 CAS 将对象头中的Mark Word替换为指向锁记录的指针。如果成功,当前线程获得锁,如果失败,

    表示其他线程竞争锁,当前线程便尝试使用自旋来获取锁。如果有两条以上的线程争用同一个锁,那轻量级锁就不再有效,要膨胀为重量级锁,锁标志

    的状态值变为”10”,Mark Word中存储的就是指向重量级(互斥量)的指针。

           轻量级锁解锁:轻量级解锁时,会使用原子的 CAS 操作来将Displaced Mark Word替换回到对象头,如果成功,则表示没有竞争发生。如果失败,

    表示当前锁存在竞争,锁就会膨胀成重量级锁。


            上面那句标红的话,真的是困扰了我好久,到底是两个线程,还是三个线程才开始膨胀呢!

    下面是我个人自己的理解:

            偏向所锁,轻量级锁都是乐观锁,重量级锁是悲观锁。

            一个对象刚开始实例化的时候,没有任何线程来访问它的时候。它是可偏向的,意味着,它现在认为只可能有一个线程来访问它,所以当第一个

    线程来访问它的时候,它会偏向这个线程,此时,对象持有偏向锁。偏向第一个线程,这个线程在修改对象头成为偏向锁的时候使用CAS操作,并将

    对象头中的ThreadID改成自己的ID,之后再次访问这个对象时,只需要对比ID,不需要再使用CAS在进行操作。

    一旦有第二个线程访问这个对象,因为偏向锁不会主动释放,所以第二个线程可以看到对象时偏向状态,这时表明在这个对象上已经存在竞争了,检查原来持有该对象锁的线程是否依然存活,如果挂了,则可以将对象变为无锁状态,然后重新偏向新的线程,如果原来的线程依然存活,则马上执行那个线程的操作栈,检查该对象的使用情况,如果仍然需要持有偏向锁,则偏向锁升级为轻量级锁,(偏向锁就是这个时候升级为轻量级锁的)。如果不存在使用了,则可以将对象回复成无锁状态,然后重新偏向。

            轻量级锁认为竞争存在,但是竞争的程度很轻,一般两个线程对于同一个锁的操作都会错开,或者说稍微等待一下(自旋),另一个线程就会释放锁。 但是当自旋超过一定的次数,或者一个线程在持有锁,一个在自旋,又有第三个来访时,轻量级锁膨胀为重量级锁,重量级锁使除了拥有锁的线程以外的线程都阻塞,防止CPU空转。


    展开全文
  • 偏向所锁,轻量级锁都是乐观锁,重量级锁是悲观锁。 一个对象刚开始实例化的时候,没有任何线程来访问它的时候。它是可偏向的,意味着,它现在认为只可能有一个线程来访问它,所以当第一个 线程来访问它的时候,它会...
  • 偏向锁:当一个线程访问对象时,它会偏向这个...这时对象已经存在竞争了,此时检查原来持有该对象锁的线程是否依然存活,如果挂了,则可以将对象变为无锁状态,然后重新偏向新的线程,如果原来的线程依然存活,而且还.
  • 自旋可以使线程在没有取得的时候,不被挂起,而转去执行一个空循环,(即所谓的自旋,就是自己执行空循环),若在若干个空循环后,线程如果可以获得,则继续执行。若线程依然不能获得,才会被挂起。 使用...
  • 对象锁和类锁的区别

    千次阅读 2020-04-12 16:47:25
    对象锁和类锁的区别synchronized 关键字对象锁1、锁住 this 对象2、 锁住实体里的非静态变量3、直接锁非静态方法对象锁代码测试类锁1、锁住 xxx.class2、锁住类中的静态变量3、直接在静态方法上加 synchronized类锁...
  • 1. 偏向:偏置模式用于使偏向给定的线程。当这个模式设置在低三位时,要么偏向某个特定的线程,要么是“匿名的”偏向,表明它可能是有偏见的。当是偏向于一个给定的线程,锁定和解锁可以在不使用原子...
  • 文章目录1 synchronized的优化1.1 CAS操作1.1.1 CAS带来的ABA问题1.1.2 自旋会浪费大量的处理器资源1.1.3 公平性1.2 Java对象头1.2.1 偏向1.2.1 偏向的获取1.2.1 偏向的撤销1.2.3 偏向的获得和撤销流程 ...
  • 区别 偏向锁:当一个线程访问对象时,它会偏向这个...这时对象已经存在竞争了,此时检查原来持有该对象锁的线程是否依然存活,如果挂了,则可以将对象变为无锁状态,然后重新偏向新的线程,如果原来的线程依然存活,而
  • java中每个对象都可作为锁,锁有四种级别,按照量级从轻到重分为:无锁、偏向锁、轻量级锁、重量级锁。并且锁只能升级不能降级。 在讲这三个锁之前,我先给大家讲清楚自旋和对象头的概念。 自旋 现在假设有这么一...
  • 1、对象监视器锁(重量级锁)、轻量级锁、偏向锁的含义 2、它们之间的区别 3、每一种锁的使用场景什么。 我们跟着一下几个问题一步一步深入了解: 什么是对象监视器锁 为什么它叫重量级锁   我们知道在...
  • 前言 Java 对象头(Java Object Header)
  • 在多线程并发编程中Synchronized一直是元老级角色,很多人都会称呼它为重量级锁,但是随着Java SE1.6对Synchronized进行了各种优化之后,有些情况下它并不那么重了,Java SE1.6中为了减少获得锁和释放锁带来的性能...
  • 面试必备之乐观锁与悲观

    万次阅读 多人点赞 2018-07-16 22:34:26
    何谓悲观锁与乐观 乐观对应于生活中乐观的人总是想着事情往好的方向发展,悲观对应于生活中悲观的人总是想着事情往坏的方向发展。这两种人各有优缺点,不能不以场景而定说一种人好于另外一种人。 悲观...
  • Java对象锁的理解

    万次阅读 热门讨论 2018-07-16 14:57:27
    以前理解Java的锁机制认为:锁的类型分为‘类锁’,’方法锁‘,’对象锁‘。 1.类锁(synchronize(静态对象)):类的所有对象都要竞争锁。 2.方法锁(在方法前加synchronize): 同一对象同一方法需要竞争锁。 3....
  • 当一个线程访问同步块并获取时,会在对象头和栈帧中的记录里存储偏向的线程 ID。以后该线程在进入和退出同步块时不需要花费CAS操作来加锁和解锁,而只需简单的检验一下对象头的Mark Word里是否存储着指向当前...
  • 对象锁共有四种状态:无锁、偏向锁、轻量级锁、重量级锁,锁竞争程度依次加重。 对象锁可以升级但不能降级,意味着偏向锁升级成轻量级锁后不能降级成偏向锁。 自旋是一种获取锁的策略,存在于获取轻量级锁的过程中...
  • Java synchronized之类锁/对象锁

    千次阅读 2017-11-03 18:24:15
    对象锁是基于对堆内存内对象的头部加锁信息; 类锁是基于对类对应的 java.lang.Class对象加所信息; 特别的, synchronized(this) 是对this所对应的对象加锁。需要特别注意的事是, 根据JMM的规范, synchronized 块...
  • 首先说明一下:方法锁和对象锁说的是一个东西,即只有方法锁或对象锁 和类锁两种锁 在java编程中,经常需要用到同步,而用得最多的也许是synchronized关键字了,下面看看这个关键字的用法。 因为...
  • 重量级锁:一个同步的A线程对应着一个monitor对象(该对象和锁对象是异议对应的关系,用来记录等待获得锁对象的锁标记的线程和已经获得锁标记的线程),堆空间对象对象头上会记录一个,这个锁信息指向monitor对象...
  • 轻量级锁与偏向锁

    万次阅读 2015-04-18 20:30:42
    要了解轻量级锁与偏向锁的原理和运作过程,需要先了解Hotspot虚拟机的对象头部分的内存布局。 1. 对象对象自身的运行时数据 如:哈希吗(HashCode)、GC分代年龄(Generational GC Age)等,这部分数据的长度...
  • Java 方法锁、对象锁、类锁

    千次阅读 2016-11-29 14:38:30
    首先介绍一下对象锁(也叫方法锁)类锁有那些不同。下文中使用对象锁称呼代替方法锁。  对于对象锁,是针对一个对象的,它只在该对象的某个内存位置声明一个标志位标识该对象是否拥有锁,所以它只会锁住当前的...
  • 轻量级锁状态 重量级锁状态 四种状态会随着竞争的情况逐渐升级,而且是不可逆的过程,即不可降级。 要注意的是,这四种状态都不是Java语言中的锁,而是Jvm为了提高锁的获取释放效率而做的优化(使用...
  • 对于synchronized这个关键字,可能之前大家有听过,他是一个重量级锁,开销很大,建议大家少用点。但到了jdk1.6之后,该关键字被进行了很多的优化,,建议大家多使用。 在现在的版本中,锁的状态总共有四种: 无锁...
  • synchronized中重量级锁、偏向锁和轻量级锁区别

    千次阅读 多人点赞 2019-08-06 20:29:36
    Java1.5之前synchronized是一个重量级锁,Java 1.6对synchronized进行的各种优化后,synchronized并不会显得那么重了。我们先介绍重量级锁,然后介绍优化后的轻量级锁和偏向锁。 0.对象头以及Mark Word 1重量...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 200,014
精华内容 80,005
关键字:

对象锁与类锁区别