精华内容
下载资源
问答
  • 而随着开锁技术的提高,A级锁能轻易地被打开,建议大家换装B级锁,或超B级锁!!! 安提醒:家用门锁3—5年就需要更换。如果没有条件换锁的,睡前记得把门反锁好,并插上钥匙扭半圈,做到这样就比较保险啦。 ...

    目前,有超过50%的用户仍在使用A级锁。而随着开锁技术的提高,A级锁能轻易地被打开,建议大家换装B级锁,或超B级锁!!!

    安提醒:家用门锁3—5年就需要更换。如果没有条件换锁的,睡前记得把门反锁好,并插上钥匙扭半圈,做到这样就比较保险啦。

    你家里还在用这种钥匙吗?

    【涨知识】你家用的是A级锁还是B级锁,什么锁最安全? (2)

    这些钥匙的锁比较安全:

    【涨知识】你家用的是A级锁还是B级锁,什么锁最安全? (3)

    门锁分类

    【涨知识】你家用的是A级锁还是B级锁,什么锁最安全? (1)

    A级安全程度最低,目前超B级最安全

    此前,一张名为“9种钥匙安全分类图”曾在微博上热传,图中列举了普通居民家中常用的9款机械锁的钥匙,并对照分类教大家怎样辨别锁具的安全级别,一时间,网友纷纷对号入座,不少人惊叹家中的门锁“弱爆”。

    据了解,我国目前对于锁具并没有强制性的分类标准,行业内最普遍的分类方法,是2011年我国几家锁具厂家共同制定的一个分类标准。

    按照该标准,民用机械防盗门锁分为普通防护级别和高防护级别,根据锁芯安全程度由低到高,共划分为A级、B级、超B级(也称C级)三个级别。而网上一度盛传的这种分类图,也是市面上比较常见的一种分类方法。

    判断级别

    看钥匙的纹路可推断锁具的安全级别

    从网上反馈的情况看,很多的居民并不清楚自家所用的门锁到底属于哪种安全等级,也不知道该如何判断。

    对此,内行人士表示,机械防盗门锁的安全级别可以通过钥匙来辨认,看懂钥匙上的弹子槽和铣槽,就能判断锁芯的安全等级了。

    钥匙上的纹路一般有两种,一种是点状的,一种是曲折的条状的,前者称为弹子槽,后者就是铣槽。通过辨别这些纹路,就能够推断锁具的安全级别。

    A级防盗锁:钥匙上只有弹子槽,其所对应的钥匙,最常见的是一字钥匙和十字钥匙。这两种钥匙虽然纹路上看起来好像是条带状的,但实际上对应的锁芯却是弹子结构的,这种结构的锁芯的区别仅限于弹子的变化,且弹子槽少而浅,很容易开启。

    B级防盗锁:钥匙上既有弹子槽又有铣槽,一般为平板钥匙,双面双排,钥匙主要包括单排防拔钥匙、单排月牙(量子)钥匙、双面叶片钥匙钥匙。

    超B级(C级防盗锁):钥匙双面都有弹子槽和铣槽,侧面也有一排弹子槽,钥匙形状为单面叶片内铣槽或外铣槽。

    应用范围

    B级锁已够家用;别忘定期升级锁芯

    不过,相对于而言,A级锁现在使用的范围还是比较小的,目前普通居民家中普遍使用的都是B级锁,有一些新安装的防盗门已经使用超B级(C级)锁了。

    和A级锁相比,B级锁的安全性要高出很多。正常情况下,B级锁能防范大部分的盗贼了。超B级锁则是家庭机械防盗锁中等级中最高的,一般来说,这种锁的防盗开启时间近400分钟,当然,价格也比其他的两款锁具要高出许多。

    对于普通居民而言,A级锁已经不能保障门户的安全,建议更换更高级的锁具。那么什么样的门锁才能有基本的安全保证呢?专业人士表示,就普通家用而言,B级锁就已够用了。这种锁的开启需要借助专业的工具,即便是熟练的开锁师傅,也需要花费5分钟以上的时间,而一般情况下,“小偷两三分钟打不开就会放弃了。”

    当然,安装个B级锁也并非就能一劳永逸了,因为开锁技术一直在升级,要让自家的锁具“跟得上时代的步伐”,就得定期给锁芯升级。专业人士提醒道,最好五年升级一次锁芯,让门锁的防盗水平能够跟得上开锁技术的变化。

    提醒

    不明广告别信 找110最安全

    市民需要开锁,千万别相信来历不明的墙体广告,这存在安全隐患:看人忽悠,见市民不懂就乱开价;开锁人员没有备案,身份信息不明,事后要找难度高;个别别有用心的锁匠,今日当锁匠来开锁,他日可能变小偷来盗窃。因此,市民最好找110联动协作开锁服务队。该队经警方严格审核和备案开锁人员信息,规范制定开锁服务流程,为队员配置统一服装、工作牌,可以给市民提供安全的开锁服务。

    市民群众向110求助开锁服务的渠道有哪些?

    1.直接拨打110,说清需开锁人信息、地址、锁的类型。

    2.110联动开锁“微”服务:关注厦门110微信,进入开锁服务选项,输入需开锁人信息、地址、求租开锁的类型等,微信平台将自动匹配地址并将就近的锁匠信息推送给开锁求助群众,由群众直接联系锁匠上门服务。另外,群众通过“微”服务平台还可以关注锁匠的地理位置、出行距离等。

    支招

    挑锁芯有技巧 超B级最好

    目前,家用门锁一般分为三个级别:A级,以技术开启超过1分钟为合格标准;B级,以技术开启超过5分钟为合格标准;超B级,以无法技术开启或技术开启超过270分钟为标准。

    第一招:买锁看钥匙的“牙齿”。牙越多,齿越深,排列越复杂,开启难度就越大,防盗性能就越好。

    第二招:挑锁论斤称两,一比重量二看锁芯。重量越重,锁芯质量越好,锁芯内的珠子越多,防盗功能越好。

    第三招:选锁芯看颜色,比色泽看做工。质量好的锁芯采用电镀处理,表面光滑,色泽光亮。其中颜色深黄的是铜芯,比较坚固,防盗性能较好;锁芯色泽暗淡,颜色灰白有气泡是锌合金,防盗性能较一般。

    第四招:钥匙旋转插入锁芯被卡的防盗性能差。钥匙半插入后,用5至7分力顺时或逆时旋转并继续将钥匙压进锁口,钥匙被卡说明锁芯的防盗性能差,顺利在半旋转状态插进锁芯的说明防盗性能好。

    爱分享微信二维码

    转载请注明:爱分享 » 【涨知识】你家用的是A级锁还是B级锁,什么锁最安全?
    原文地址:http://www.ihref.com/read-17396.html

    展开全文
  • 锁的状态总共有四种:无锁状态、偏向锁、轻量级锁和重量级锁。随着锁的竞争,锁可以从偏向锁升级到轻量级锁,再升级的重量级锁(但是锁的升级是单向的,也就是说只能从低到高升级,不会出现锁的降级)

    写在前面

    今天我们来聊聊 Synchronized 里面的各种锁:偏向锁、轻量级锁、重量级锁,以及三个锁之间是如何进行锁膨胀的。先来一张图来总结
    在这里插入图片描述

    提前了解知识

    锁的升级过程

    锁的状态总共有四种:无锁状态、偏向锁、轻量级锁和重量级锁。随着锁的竞争,锁可以从偏向锁升级到轻量级锁,再升级的重量级锁(但是锁的升级是单向的,也就是说只能从低到高升级,不会出现锁的降级)

    Java 对象头

    因为在Java中任意对象都可以用作锁,因此必定要有一个映射关系,存储该对象以及其对应的锁信息(比如当前哪个线程持有锁,哪些线程在等待)。一种很直观的方法是,用一个全局map,来存储这个映射关系,但这样会有一些问题:需要对map做线程安全保障,不同的synchronized之间会相互影响,性能差;另外当同步对象较多时,该map可能会占用比较多的内存。所以最好的办法是将这个映射关系存储在对象头中,因为对象头本身也有一些hashcode、GC相关的数据,所以如果能将锁信息与这些信息共存在对象头中就好了。

    在JVM中,对象在内存中除了本身的数据外还会有个对象头,对于普通对象而言,其对象头中有两类信息:mark word和类型指针。另外对于数组而言还会有一份记录数组长度的数据。类型指针是指向该对象所属类对象的指针,mark word用于存储对象的HashCode、GC分代年龄、锁状态等信息。在32位系统上mark word长度为32bit,64位系统上长度为64bit。为了能在有限的空间里存储下更多的数据,其存储格式是不固定的,在32位系统上各状态的格式如下:
    在这里插入图片描述
    可以看到锁信息也是存在于对象的mark word中的。当对象状态为偏向锁(biasable)时,mark word存储的是偏向的线程ID;当状态为轻量级锁(lightweight locked)时,mark word存储的是指向线程栈中Lock Record的指针;当状态为重量级锁(inflated)时,为指向堆中的monitor对象的指针。

    全局安全点(safepoint)

    safepoint这个词我们在GC中经常会提到,简单来说就是其代表了一个状态,在该状态下所有线程都是暂停的。

    偏向锁

    一个线程反复的去获取/释放一个锁,如果这个锁是轻量级锁或者重量级锁,不断的加解锁显然是没有必要的,造成了资源的浪费。于是引入了偏向锁,偏向锁在获取资源的时候会在资源对象上记录该对象是偏向该线程的,偏向锁并不会主动释放,这样每次偏向锁进入的时候都会判断该资源是否是偏向自己的,如果是偏向自己的则不需要进行额外的操作,直接可以进入同步操作。

    偏向锁获取过程

    • 访问Mark Word中偏向锁标志位是否设置成1,锁标志位是否为01——确认为可偏向状态。
    • 如果为可偏向状态,则测试线程ID是否指向当前线程,如果是,进入步骤(5),否则进入步骤(3)。
    • 如果线程ID并未指向当前线程,则通过CAS操作竞争锁。如果竞争成功,则将Mark Word中线程ID设置为当前线程ID,然后执行(5);如果竞争失败,执行(4)。
    • 如果CAS获取偏向锁失败,则表示有竞争。当到达全局安全点(safepoint)时获得偏向锁的线程被挂起,偏向锁升级为轻量级锁,然后被阻塞在安全点的线程继续往下执行同步代码。
    • 执行同步代码。

    偏向锁的释放

    偏向锁的撤销在上述第四步骤中有提到。偏向锁只有遇到其他线程尝试竞争偏向锁时,持有偏向锁的线程才会释放锁,线程不会主动去释放偏向锁。偏向锁的撤销,需要等待全局安全点safepoint,它会首先暂停拥有偏向锁的线程A,然后判断这个线程A,此时有两种情况:
    在这里插入图片描述

    批量重偏向

    为什么有批量重偏向

    当只有一个线程反复进入同步块时,偏向锁带来的性能开销基本可以忽略,但是当有其他线程尝试获得锁时,就需要等到safe point时将偏向锁撤销为无锁状态或升级为轻量级/重量级锁。这个过程是要消耗一定的成本的,所以如果说运行时的场景本身存在多线程竞争的,那偏向锁的存在不仅不能提高性能,而且会导致性能下降。因此,JVM中增加了一种批量重偏向/撤销的机制。

    批量重偏向的原理

    • 首先引入一个概念epoch,其本质是一个时间戳,代表了偏向锁的有效性,epoch存储在可偏向对象的MarkWord中。除了对象中的epoch,对象所属的类class信息中,也会保存一个epoch值。

    • 每当遇到一个全局安全点时(这里的意思是说批量重偏向没有完全替代了全局安全点,全局安全点是一直存在的),比如要对class C 进行批量再偏向,则首先对 class C中保存的epoch进行增加操作,得到一个新的epoch_new

    • 然后扫描所有持有 class C 实例的线程栈,根据线程栈的信息判断出该线程是否锁定了该对象,仅将epoch_new的值赋给被锁定的对象中,也就是现在偏向锁还在被使用的对象才会被赋值epoch_new。

    • 退出安全点后,当有线程需要尝试获取偏向锁时,直接检查 class C 中存储的 epoch 值是否与目标对象中存储的 epoch 值相等, 如果不相等,则说明该对象的偏向锁已经无效了(因为(3)步骤里面已经说了只有偏向锁还在被使用的对象才会有epoch_new,这里不相等的原因是class C里面的epoch值是epoch_new,而当前对象的epoch里面的值还是epoch),此时竞争线程可以尝试对此对象重新进行偏向操作。

    轻量级锁

    轻量级锁的获取过程

    • 在代码进入同步块的时候,如果同步对象锁状态为偏向状态(就是锁标志位为“01”状态,是否为偏向锁标志位为“1”),虚拟机首先将在当前线程的栈帧中建立一个名为锁记录(Lock Record)的空间,用于存储锁对象目前的Mark Word的拷贝。官方称之为 Displaced Mark Word(所以这里我们认为Lock Record和 Displaced Mark Word其实是同一个概念)。这时候线程堆栈与对象头的状态如图所示:
      在这里插入图片描述

    • 拷贝对象头中的Mark Word复制到锁记录中。

    • 拷贝成功后,虚拟机将使用CAS操作尝试将对象头的Mark Word更新为指向Lock Record的指针,并将Lock record里的owner指针指向对象头的mark word。如果更新成功,则执行步骤(4),否则执行步骤(5)。

    • 如果这个更新动作成功了,那么这个线程就拥有了该对象的锁,并且对象Mark Word的锁标志位设置为“00”,即表示此对象处于轻量级锁定状态,这时候线程堆栈与对象头的状态如下所示:
      在这里插入图片描述

    • 如果这个更新操作失败了,虚拟机首先会检查对象的Mark Word是否指向当前线程的栈帧,如果是就说明当前线程已经拥有了这个对象的锁,现在是重入状态,那么设置Lock Record第一部分(Displaced Mark Word)为null,起到了一个重入计数器的作用。下图为重入三次时的lock record示意图,左边为锁对象,右边为当前线程的栈帧,重入之后然后结束。接着就可以直接进入同步块继续执行。
      在这里插入图片描述
      如果不是说明这个锁对象已经被其他线程抢占了,说明此时有多个线程竞争锁,那么它就会自旋等待锁,一定次数后仍未获得锁对象,说明发生了竞争,需要膨胀为重量级锁。

    轻量级锁的解锁过程

    • 通过CAS操作尝试把线程中复制的Displaced Mark Word对象替换当前的Mark Word。

    • 如果替换成功,整个同步过程就完成了。

    • 如果替换失败,说明有其他线程尝试过获取该锁(此时锁已膨胀),那就要在释放锁的同时,唤醒被挂起的线程。

    重量级锁

    重量级锁加锁和释放锁机制

    • 调用omAlloc分配一个ObjectMonitor对象,把锁对象头的mark word锁标志位变成 “10 ”,然后在mark word存储指向ObjectMonitor对象的指针
    • ObjectMonitor中有两个队列,_WaitSet_EntryList,用来保存ObjectWaiter对象列表(每个等待锁的线程都会被封装成ObjectWaiter对象),_owner指向持有ObjectMonitor对象的线程,当多个线程同时访问一段同步代码时,首先会进入 _EntryList 集合,当线程获取到对象的monitor 后进入 _Owner 区域并把monitor中的owner变量设置为当前线程同时monitor中的计数器count加1,若线程调用wait()方法,将释放当前持有的monitorowner变量恢复为null,count自减1,同时该线程进入WaitSet集合中等待被唤醒。若当前线程执行完毕也将释放monitor(锁)并复位变量的值,以便其他线程进入获取monitor(锁)。如下图所示
      在这里插入图片描述

    Synchronized同步代码块的底层原理

    同步代码块的加锁、解锁是通过 Javac 编译器实现的,底层是借助monitorentermonitorerexit,为了能够保证无论代码块正常执行结束 or 抛出异常结束,都能正确释放锁,Javac 编译器在编译的时候,会对monitorerexit进行特殊处理,举例说明:

    public class Hello {
        public void test() {
            synchronized (this) {
                System.out.println("test");
            }
        }
    }
    

    通过 javap -c 查看其编译后的字节码:

    public class Hello {
      public Hello();
        Code:
           0: aload_0
           1: invokespecial #1                  // Method java/lang/Object."<init>":()V
           4: return
      public void test();
        Code:
           0: aload_0
           1: dup
           2: astore_1
           3: monitorenter
           4: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;
           7: ldc           #3                  // String test
           9: invokevirtual #4                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
          12: aload_1
          13: monitorexit
          14: goto          22
          17: astore_2
          18: aload_1
          19: monitorexit
          20: aload_2
          21: athrow
          22: return
        Exception table:
           from    to  target type
               4    14    17   any
              17    20    17   any
    }
    

    从字节码中可知同步语句块的实现使用的是monitorentermonitorexit指令,其中monitorenter指令指向同步代码块的开始位置,monitorexit指令则指明同步代码块的结束位置,当执行monitorenter指令时,当前线程将试图获取mark word里面存储的monitor,当 monitor的进入计数器为 0,那线程可以成功取得monitor,并将计数器值设置为1,取锁成功。

    如果当前线程已经拥有 monitor 的持有权,那它可以重入这个 monitor ,重入时计数器的值也会加 1。倘若其他线程已经拥有monitor的所有权,那当前线程将被阻塞,直到正在执行线程执行完毕,即monitorexit指令被执行,执行线程将释放 monitor并设置计数器值为0 ,其他线程将有机会持有 monitor

    值得注意的是编译器将会确保无论方法通过何种方式完成,方法中调用过的每条 monitorenter 指令都有执行其对应 monitorexit 指令,而无论这个方法是正常结束还是异常结束。为了保证在方法异常完成时 monitorentermonitorexit 指令依然可以正确配对执行,编译器会自动产生一个异常处理器,这个异常处理器声明可处理所有的异常,它的目的就是用来执行 monitorexit 指令。从上面的字节码中也可以看出有两个monitorexit指令,它就是异常结束时被执行的释放monitor 的指令。

    同步方法底层原理

    同步方法的加锁、解锁是通过 Javac 编译器实现的,底层是借助ACC_SYNCHRONIZED访问标识符来实现的,代码如下所示:

    public class Hello {
        public synchronized void test() {
            System.out.println("test");
        }
    }
    

    方法级的同步是隐式,即无需通过字节码指令来控制的,它实现在方法调用和返回操作之中。JVM可以从方法常量池中的方法表结构(method_info Structure) 中的 ACC_SYNCHRONIZED 访问标志区分一个方法是否同步方法。当方法调用时,调用指令将会 检查方法的 ACC_SYNCHRONIZED访问标志是否被设置,如果设置了,执行线程将先持有monitor,然后再执行方法,最后在方法完成(无论是正常完成还是非正常完成)时释放monitor。在方法执行期间,执行线程持有了monitor,其他任何线程都无法再获得同一个monitor。如果一个同步方法执行期间抛出了异常,并且在方法内部无法处理此异常,那这个同步方法所持有的monitor将在异常抛到同步方法之外时自动释放。

    下面我们看看字节码层面如何实现:

    public class Hello {
      public Hello();
        Code:
           0: aload_0
           1: invokespecial #1                  // Method java/lang/Object."<init>":()V
           4: return
      public synchronized void test();
        Code:
           0: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;
           3: ldc           #3                  // String test
           5: invokevirtual #4                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
           8: return
    }
    

    锁的其他优化

    • 适应性自旋(Adaptive Spinning):从轻量级锁获取的流程中我们知道,当线程在获取轻量级锁的过程中执行CAS操作失败时,是要通过自旋来获取重量级锁的。问题在于,自旋是需要消耗CPU的,如果一直获取不到锁的话,那该线程就一直处在自旋状态,白白浪费CPU资源。解决这个问题最简单的办法就是指定自旋的次数,例如让其循环10次,如果还没获取到锁就进入阻塞状态。但是JDK采用了更聪明的方式——适应性自旋,简单来说就是线程如果自旋成功了,则下次自旋的次数会更多,如果自旋失败了,则自旋的次数就会减少。
    • 锁粗化(Lock Coarsening):锁粗化的概念应该比较好理解,就是将多次连接在一起的加锁、解锁操作合并为一次,将多个连续的锁扩展成一个范围更大的锁。举个例子:
    public  void lockCoarsening() {
        int i=0;
        synchronized (this){
            i=i+1;
        }
        synchronized (this){
            i=i+2;
        }
    }
    

    上面的两个同步代码块可以变成一个

    public  void lockCoarsening() {
        int i=0;
        synchronized (this){
            i=i+1;
            i=i+2;
        }
    }
    
    • 锁消除(Lock Elimination):锁消除即删除不必要的加锁操作的代码。比如下面的代码,下面的for循环完全可以移出来,这样可以减少加锁代码的执行过程
    public  void lockElimination() {
        int i=0;
        synchronized (this){
            for(int c=0; c<1000; c++){
                System.out.println(c);
            }
            i=i+1;
        }
    }
    
    展开全文
  • 文章目录线程安全优化一、线程安全概念不可变绝对线程安全相对线程安全线程兼容线程对立二、线程安全的实现方法互斥同步基本互斥手段就是synchronized另一种手段JUC下的ReentrantLock阻塞同步的问题:非阻塞...

    线程安全与锁优化

    一、线程安全概念

    为了更好的理解线程安全,我们不把线程安全看做是一个二元对立的选项来看,而是按照线程安全的”安全程度“由强至弱来排序。

    Java线程各种操作共享的数据分为五类:

    • 不可变
    • 绝对线程安全
    • 相对线程安全
    • 线程兼容
    • 线程对立

    不可变

    不可变的对象一定是线程安全的,无论是对象的方法实现还是方法的调用者,都不需要进行任何的线程安全保障措施。被final修饰的对象只要被正确构建出来,就永远是不可变的,也就是线程安全的。

    • 例1-1:

    String类型就是不可变类型,我们调用它的substring()、replace()方法都不会影响原来的值,只会返回一个新构造的字符串对象。

    绝对线程安全

    不管运行环境如何,调用者也不需要任何的同步措施,就可以达到线程安全。这种状态通常不可能达到或要付出非常大的代价。

    • 例1-2:

    Vector是一个线程安全的容器,但是仍然会出错。

    //线程一执行:
    for(int i=0;i<vector.size();i++){
        vector.remove(i);
    }
    //线程二执行
    for(int i=0;i<vector.size();i++){
        vector.get(i);
    }
    

    该情况下,可能在线程二执行了i++之后执行get(i)之前被阻塞调用了线程一,之后i位置的元素被移除了,此时线程二执行get(i)就会出错

    相对线程安全

    普遍意义上的线程安全,它保证对象单独的操作时线程安全的,但是对于一些特定顺序的连续调用就可能需要在调用端使用额外的同步手段来保证调用正确性。例1-2就是一个很好的例子。

    绝大部分线程安全类都属于这种类型。如Vector、HashTable、Collections的synchronizedCollection()方法包装的集合

    线程兼容

    线程兼容是指对象本身并不是线程安全的,但是可以通过调用端正确地使用同步手段保证对象可以在并发环境中使用。

    如ArrayList和HashMap就是线程兼容的。可以自行添加锁来保证安全

    线程对立

    无论是否采取同步措施,都无法在多线程环境下保证并发。

    如采取同步措施后出现的死锁问题

    二、线程安全的实现方法

    实现线程安全的方法有三种

    • 互斥同步
    • 非阻塞同步
    • 无同步

    互斥同步

    互斥同步是最常见的一种并发正确性保障手段。

    • 同步是指多个线程并发访问共享数据时,保证共享数据在同一时刻只被一条(或一些,使用信号量的时候)线程使用。
    • 互斥是实现同步的一种手段,临界区、互斥量、信号量都是主要实现方式

    互斥是因,同步是果。互斥是方法,同步是目的。

    最基本互斥手段就是synchronized

    synchronized关键字经过编译之后会在同步代码块的前后分别形成monitorenter和monitorexit这两个字节码指令。这两个字节码都需要一个reference类型的参数来指明要锁定和解锁的对象

    目前简易执行流程,与实际执行有出入

    在这里插入图片描述

    缺点:

    • 由于Java的线程是映射到操作系统的原生线程之上,如果阻塞和唤醒一条线程就需要从用户态转换到核心态,需要耗费处理器较多时间。如对于简单的同步块进行内核状态转换消耗的时间可能比业务代码执行时间还要长,使系统的性能较低。是一个重量级操作

      后期会优化在阻塞前加入一段自旋等待的过程,避免频繁切换状态。

    另一种手段JUC下的ReentrantLock

    在基本用法上ReentrantLock与synchronized很相似。都具备可重入性。

    区别:

    • ReentrantLock是表现在API层面的互斥锁,synchronized是表现在原生语法层面的互斥锁
    • ReentrantLock获取锁的等待可以被中断,synchronized不可以被中断
    • ReentrantLock可以实现公平锁(默认为非公平锁),synchronized则只能是非公平锁
    • ReentrantLock可以精确进行线程唤醒,synchronized只能粗略的进行线程唤醒

    在JDK1.5时ReentrantLock的性能比synchronized性能稳定且高的多。synchronized仍有很大的优化空间

    阻塞同步的问题:

    互斥同步的主要问题就是进行线程阻塞和唤醒带来的性能问题。因此这种同步方式被称为阻塞同步,属于悲观的并发策略。无论共享数据是否出现竞争都会进行加锁。**很出现很多不必要的状态切换、维护锁计数器和检查是否有被阻塞的线程需要唤醒等操作。**影响性能

    非阻塞同步

    随着硬件指令集的发展,我们可以使用**基于冲突检测的乐观并发策略。**通俗的说先进先操作,如果没有其他线程争用共享数据,那么操作就成功了,如果有争用产生了冲突,那就进行其他的补偿措施(一般为循环尝试)。这种操作不需要把线程挂起,因此被称为非阻塞同步。

    在这里插入图片描述

    实现方式CAS操作:

    CAS指令由三个操作数:CAS(V,A,B)

    • V:共享变量的内存地址
    • A:旧的预期值
    • B:新的预期值

    在硬件层面保证原子性

    问题:CAS操作的经典问题ABA问题

    在这里插入图片描述

    线程A读取了数据A,线程B将A修改为B后又修改为A,之后线程A再次访问数据A。这样就存在漏洞。大多数情况下ABA不会影响程序并发的争取性。可以为数据添加一个版本号时间戳来标记数据是否被修改过。

    无同步方案

    要保证线程安全不一定要同步。同步只是保障数据争用时的正确性的手段。如果一个方法不涉及共享数据,则无需任何同步措施保证正确性。

    可重入代码:

    可以在代码执行的任何时刻中断它,转而执行另一段代码,而控制权返回后,原来的程序不会出现任何错误。

    线程本地存储:

    如果一段代码中需要的数据必须与其他代码共享,可以试试将这些共享数据的代码放入同一个线程执行。如果可以,则无须同步也能保证线程之间不出现数据争用。

    三、锁优化

    自旋锁与自适应锁

    自旋锁

    由于互斥同步的阻塞对性能影响较大。并且在很多情况下对于共享数据的锁定状态只会持续很短一段时间,为了这段时间去挂起和恢复线程并不值得。所以当物理机可以让两个线程同时执行时,我们可以让请求锁的线程稍等一会并不将其挂起。为了让线程等待,我们只需要让线程执行一个忙循环(自旋),这就是自旋锁。

    自适应锁

    自适应锁就是对自旋锁的自旋次数进行适应性调整。

    如:一个锁对象曾经自旋成功,那么虚拟机认为这次仍然可能成功,进而允许他自旋等待更长的时间。如果一个锁对象自旋很少成功,那么以后获取这个锁时就减少自旋或不自旋。

    锁消除

    锁消除是指在虚拟机即时编译器在运行时发现一些代码上要求同步,但是实际上不可能出现对于共享数据的竞争,就会进行把同步操作进行省略。

    例:

    public String concatstring(String s1,String s2,String s3){
        return s1+s2+s3;
    }
    

    表面上没有锁的存在,实际上jdk会对String连接进行优化,于是以上代码就会变成new StringBuffer().append(s1).append(s2).append(s3).toString();,然而StringBuffer是线程安全的,在其内部就存在锁,但是此时根本无需锁的存在,这里就使用了JVM的锁消除。

    锁粗化

    在编写代码时,推荐将同步块的作用范围限制得尽量小。但是也有例外情况,如果一系列连续的操作都对同一个对象反复加锁和解锁比如在循环体内加锁。那么就需要不停的加锁和释放锁,及时没有线程竞争也会导致性能消耗。这时只需要将锁的作用域扩大到整个循环。只需要加一个锁就可以了。这就是锁粗化

    轻量级锁

    传统的互斥锁属于“重量级”锁。相对应的就是“轻量级”锁。是对“重量级”锁的补充。要理解轻量级锁必须先了解虚拟机的对象的内存布局。HotSpot虚拟机的对象头分为两部分,一部分存储对象自身的运行时数据,一部分存储指向方法区对象类型数据的指针,如果是数组对象的话,还有一部分用于存储数组长度。

    在这里插入图片描述

    Mark Word区域是实现轻量级锁与偏向锁的关键(随着锁标记位的不同,Mark Word的内容不断变化)。

    在这里插入图片描述

    代码进入同步代码块的时候,如果此同步对象没有被锁定,虚拟机首先将在当前线程的栈帧中建立一个名为锁记录(Lock Record)的空间。用于存储当前Mark Word的拷贝,之后尝试CAS操作,成功就修改Mark Word为指向Lock Record的指针并修改锁标记位为00。此时Mark Word内容参考上图。加锁流程图如下:

    在这里插入图片描述

    解锁过程流程图如下:

    在这里插入图片描述

    轻量级锁提升程序性能的依据是“对于绝大部分的锁,在整个同步周期内都不存在竞争”。

    偏向锁

    如果说轻量级锁是在无竞争的情况下使用CAS操作去消除同步使用的互斥量,那么偏向锁就是无竞争的情况下降整个同步都消除掉。

    偏向锁的“偏”是偏心的偏。他的意思是这个锁会偏向于第一个获得他的线程,在接下来的情况如果没有其他的线程要获取他,则持有偏向锁的线程永远不需要同步。而如果有其他的线程要获取这个锁时,偏向模式宣告结束,根据对象是否被锁定恢复到未锁定或轻量级锁定的状态。

    偏向锁优缺点:

    偏向锁可以提高带有同步但是无竞争的程序性能。但是一个共享数据总是被不同的线程访问,那么偏向模式就是多余的。

    展开全文
  • 轻量级锁、偏向锁、重量级锁详情

    千次阅读 热门讨论 2018-11-17 13:48:47
    这篇文章是上篇文章是否真的理解了偏向锁、轻量级锁、重量级锁(锁膨胀)、自旋锁、锁消除、锁粗化,知道重偏向吗?的补充,对于偏向锁,网上有些对于它的原理解读过于简单,简单得似乎是错误的,显眼的是对于Mark...

    这篇文章是上篇文章是否真的理解了偏向锁、轻量级锁、重量级锁(锁膨胀)、自旋锁、锁消除、锁粗化,知道重偏向吗?的补充,对于偏向锁

     

    这篇文章提出了对于一书“深入理解Java虚拟机”中的一张图的深入是否使用偏向锁解读,当然这张图是Oracle官方的,呵呵。还必须具有深入知道偏向锁、轻量级锁、重量级锁(锁膨胀)、自旋锁、锁消除、锁粗化这几个的过程,如果不知道。前面那个传送门可以去看一下,我是从操作系统层的PV操作的角度入手解读轻量级锁和偏向锁的,当然JVM底层实现调用操作系统的api的确是用的那个,针对于Monitor,C没有实现Monitor,Java却实现了,提供给我们很好的Monitor实现工具。像synchronized和ReetrantLock,不过这儿声明,synchronized单个不是Monitor,这儿给个我在一本书上看到Monitor(管程)的定义“管程由一些共享数据、一组能为并发进程所执行的作用在共享数据上的操作的集合、初始代码以及存取权组成。”,从这个上面解读,Monitor还包括很多东西,还和业务数据有关。不过在网上看的很多对于Java中Monitor的解读似乎很不符合这个原则,我也不知道什么原因,可能是英语转换成汉语让人误解的问题吧,这儿不详细讨论这个了。但是知道Monitor是用PV操作实现的。

    先给出这张图和一个Mark Word的结构:

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

      

    疑惑:

           1、重偏向是做什么的?

            2、在已经初始锁定的情况下 的偏向锁为什么还有锁定和 解锁?

            3、撤销偏向,怎么知道对象 有没有锁定?

    当时为了解除这些疑惑我baidu到了另外的解释:

    HotSpot支持存储释放偏向锁,以及偏向锁的批量重偏向和撤销。这个特性可以通过JVM的参数进行切换,而且这是默认支持的。Unlock状态下MarkWord的一个比特位用于标识该对象偏向锁是否被使用或者是否被禁止。如果该bit位为0,则该对象未被锁定;如果该bit位为1,则意味着该对象处于以下三种状态:

    • 匿名偏向(Anonymously biased)
      在此状态下thread_ptr为NULL(0),意味着还没有线程偏向于这个锁对象。第一个试图获取该锁的线程将会面临这个情况,使用原子CAS指令可将该锁对象绑定于当前线程。这是允许偏向锁的类对象的初始状态。
    • 可重偏向(Rebiasable)
      在此状态下,偏向锁的epoch字段是无效的(与锁对象对应的klass的mark_prototype的epoch值不匹配)。下一个试图获取锁对象的线程将会面临这个情况,使用原子CAS指令可将该锁对象绑定于当前线程。在批量重偏向的操作中,未被持有的锁对象都被至于这个状态,以便允许被快速重偏向。
    • 已偏向(Biased)
      这种状态下,thread ptr非空,且epoch为有效值——意味着其他线程正在使用这个锁对象。

    基于偏向锁对象需要使用hashcode字段作为偏向线程id标识的事实,被hash的对象不可被用作偏向锁。对于允许偏向的对象在进行hashcode计算时,首先要吊销(revoke)所有的偏向(不管是有效的还是无效的),然后使用CAS将计算好的hashcode值放到MarkWord中,尽管这仅仅适用于“identity hashcode(使用Object类的hashcode()方法进行计算)”。普通Java类型hashcode的计算需要重载Object的hashcode()方法,但不必要去显示调用这个方法;因此,对于没有显示调用Object#hashcode()方法的类的对象,仍然适用于偏向锁的机制——可被用作锁对象使用。

    HotSpot为所有加载的类型,在class元数据——InstanceKlass中保留了一个MarkWord原型——mark_prototype。这个值的bias位域决定了该类型的对象是否允许被偏向锁定。与此同时,当前的epoch位也被保留在prototype中。这意味着,对应class的新对象可以简单地直接拷贝这个原型值,而不必在后面进行修正。在批量重偏向(bulk rebias)的操作中,prototype的epoch位将会被更新;在批量吊销(bulk revoke)的操作中,prototype将会被置成不可偏向的状态——bias位被置0。

    偏向锁的获取依靠原子CAS指令将线程指针插入MarkWord中。其先决条件是:1.该对象处于匿名偏向状态;2.该对象处于可重偏向状态(一个锁对象仅能被一个线程偏向一次)。只要锁对象被偏向,递归锁定和解锁仅仅需要读取对象头以及对应Klass的prototype去验证偏向是否被吊销。

    HotSpot中偏向锁的撤销是JVM处于在全局安全点时被执行的。在撤销过程中,撤销者会遍历当前偏向线程的锁记录,藉此推断对象当前是否被锁定。如果发现锁对象被一个偏向线程持有,锁记录将被修改——如同轻量级锁被使用一样;如果锁对象未被持有,这是取决于触发撤销的原因,锁对象要么被禁止用作偏向锁,要么被禁止重新偏向于撤销线程。

    即使偏向锁的特性被打开,出于性能(启动时间)的原因在JVM启动后的的头4秒钟这个feature是被禁止的。这也意味着在此期间,prototype MarkWord会将它们的bias位设置为0,以禁止实例化的对象被偏向。4秒钟之后,所有的prototype MarkWord的bias位会被重设为1,如此新的对象就可以被偏向锁定了。

    获取偏向锁的步骤:

    1. 验证对象的bias位
      如果是0,则该对象不可偏向,应该使用轻量级锁算法。
    2. 验证对象所属InstanceKlass的prototype的bias位
      确认prototype的bias为是否被设置。如果没有设置,则该类所有对象全部不允许被偏向锁定;并且该类所有对象的bias位都需要被重置,使用轻量级锁替换。
    3. 校验epoch位
      校验对象的MarkWord的epoch位是否与该对象所属InstanceKlass的prototype的MarkWord的epoch匹配。如果不匹配,则表明偏向已过期,需要重新偏向。这种情况,偏向线程可以简单地使用原子CAS指令重新偏向于这个锁对象。
    4. 校验owner线程
      比较偏向线程ID与当前线程ID。如果匹配,则表明当前线程已经获得了偏向,可以安全返回。如果不匹配,对象锁被假定为匿名偏向状态,当前线程应该尝试使用CAS指令获得偏向。如果失败的话,就尝试撤销(很可能引入安全点),然后回退到轻量级锁;如果成功,当前线程成功获得偏向,可直接返回。

    从上面,我对于

    • 匿名偏向(Anonymously biased)
      在此状态下thread_ptr为NULL(0),意味着还没有线程偏向于这个锁对象。第一个试图获取该锁的线程将会面临这个情况,使用原子CAS指令可将该锁对象绑定于当前线程。这是允许偏向锁的类对象的初始状态。
    • 可重偏向(Rebiasable)
      在此状态下,偏向锁的epoch字段是无效的(与锁对象对应的klass的mark_prototype的epoch值不匹配)。下一个试图获取锁对象的线程将会面临这个情况,使用原子CAS指令可将该锁对象绑定于当前线程。在批量重偏向的操作中,未被持有的锁对象都被至于这个状态,以便允许被快速重偏向。
    • 已偏向(Biased)
      这种状态下,thread ptr非空,且epoch为有效值——意味着其他线程正在只有这个锁对象。

    疑惑了,疑惑如下:

         4、可重偏向这个状态是做什么的,为什么 Epoch的字段无效,还有就是epoch字段有什 么作用?

    对于这个过程:

    1. 验证对象的bias位
      如果是0,则该对象不可偏向,应该使用轻量级锁算法。
    2. 验证对象所属InstanceKlass的prototype的bias位
      确认prototype的bias为是否被设置。如果没有设置,则该类所有对象全部不允许被偏向锁定;并且该类所有对象的bias位都需要被重置,使用轻量级锁替换。
    3. 校验epoch位
      校验对象的MarkWord的epoch位是否与该对象所属InstanceKlass的prototype的MarkWord的epoch匹配。如果不匹配,则表明偏向已过期,需要重新偏向。这种情况,偏向线程可以简单地使用原子CAS指令重新偏向于这个锁对象。
    4. 校验owner线程
      比较偏向线程ID与当前线程ID。如果匹配,则表明当前线程已经获得了偏向,可以安全返回。如果不匹配,对象锁被假定为匿名偏向状态,当前线程应该尝试使用CAS指令获得偏向。如果失败的话,就尝试撤销(很可能引入安全点),然后回退到轻量级锁;如果成功,当前线程成功获得偏向,可直接返回。

    疑惑,疑惑如下:

          5、为什么校验epoch位,如果 InstanceKlass的prototype的MarkWord的 Epoch和对象的MarkWord的epoch位不 匹配表示 偏向已过期,可以重新偏向?

          6、为什么在校验owner线程,比较偏向 线程ID与当前线程ID如果不匹配,还要 尝试使用CAS指令获取偏向,并且如果 成功了还表示偏向成功?

    根据这两个还是没有从这些疑惑中找到相同点,寻找到合理的理解,公司可以翻墙,所以我google了下,查到一篇博客:

        https://pdfs.semanticscholar.org/edf9/54412a9b1ce955bea148199f325759779540.pdf

    从中知道了原来在偏向锁“可重偏向”是为了“在一个时间段内每一个时刻都是只有一个线程使用同一个对象,但是不是每一时刻都是同一个线程”而。

    • 到全局安全点的时候才停止所有线程。。
    • 增加类型C的epoch的值 定位当前阻塞的线程锁住了的类型C的实例对象并且修改他们的偏向epoch或者撤销偏向。
    • 释放在安全点阻塞的线程。

    疑惑:

          7、这个里面为什么 有类型的epoch和 实例对象的epoch?

          8、为什么要自增类型C的epoch的值?

          9、为什么只更新当前阻塞的线程锁住了的类型 C的实例对象的epoch?

    最后详细的品味,详细的想终于将一切想通了。

    总结疑惑:

    1、重偏向是做什么的?

    2、在已经初始锁定的情 况下的偏向锁为什么还 有锁定和解锁?

    3、撤销偏向,怎么知道 对象有没有锁定?

    4、可重偏向这个状态是 做什么的,为什么Epoch 的字段无效,还有就是 epoch字段有什么作用?

    5、这个里面为什么 有类型的epoch和实 例对象的epoch?

    6、为什么要增加类 型C的epoch的值?

    7、为什么只更新当 前阻塞的线程锁住了 的类型C的实例对象 的epoch?

    8、为什么校验epoch位,如果 InstanceKlass的prototype的MarkWord的 Epoch和对象的MarkWord的epoch位不 匹配表示 偏向已过期,可以重新偏向。

    9、为什么在校验owner线程,比较偏向 线程ID与当前线程ID如果不匹配,还要 尝试使用CAS指令获取偏向,并且如果 成功了还表示偏向成功?

    解决:

    1、重偏向不是针对“ 在一个时间段内每一个 时刻都是相同线程使用 同一个对象”的情景,而 是在不同时间不同线程 使用相同对象的情景, “重偏向” 是就是为了 更新线程ID。

    2、初始锁定也就是锁定,当然也有解锁。标志当前对象是否被线程占用。

    3、不是有个锁定和解锁吗,它就是通过这个知道的。

    4、可重偏向这个状态也 是针对“不同时间不同线 程使用相同对象的情景” 的情景,当对象中的epoch 和InstanceKlass中的epoch 值不相同的时候,说明这 个对象没有其它线程使用 了,所以对象的epoch字 段无效,下一个线程可以 继续使用,并且偏向。 Epoch其实就是为了标志 对象是否被线程锁住。

    5、因为需要知道有 哪些类型C的实例对象 被阻塞的线程锁住 了,因为满足这个条 件的说明是活动的, 如果其他线程在这个 时候来发生竞争,那 么就CAS失败,进入 轻量级锁。

    6、因为为了让上次 锁住的对象但是这次 已经不再有线程偏向 区别开。

    7、这个问题上面 已经回答了,因为 阻塞的就是正在发 生偏向的,偏向还 没有失效。失效了 的可以重偏向。

    8、校验epoch位是为了知道该对象 是否处于活动状态,如果确认和 InstanceKlass不相同,说明上次锁住这 个对象偏向的线程已经不再存活,可以 重新偏向了。

    9、因为校验ower线程,比较当前线程 ID和对象里面的ID如果不相等,还有 可能可以发生重偏向,它的场景是“ 在一个时间段内每一个时刻都是只 有一个线程使用同一个对象,但是不 是每一时刻都是同一个线程”。

    下面是我在网上找到的流程图,这里面完美总结了,只不过倒数3位不但是否偏向,而且表示是否禁用偏向:

    下面附上偏向锁升级为轻量级锁的步凑 :

          1、到全局安全点的时候才停止所有线程。

         2、偏移所有者的堆栈被遍历,并且这个锁记录锁关联的对象将被 填充成如果这个对象发生轻量级锁生成的值。

         3、对象的标记字被更新为指向堆栈上最古老的关联锁记录 。

         4、释放在安全点阻塞的线程。

    偏向锁没有那么简单

    展开全文
  • 之前做过一个测试,详情见这篇文章《多线程 +1操作的种实现方式,及效率对比》,当时对这个测试结果很疑惑,反复执行过多次,发现结果是一样的: 1. 单线程下synchronized效率最高(当时感觉它的效率应该是最差才...
  • 在多线程并发编程中Synchronized一直是元老级角色,很多人都会称呼它为重量级锁,但是随着Java SE1.6对Synchronized进行了各种优化之后,有些情况下它并不那么重了,Java SE1.6中为了减少获得锁和释放锁带来的性能...
  • 偏向锁、轻量级锁、重量级锁解析

    千次阅读 2021-02-19 21:22:17
    Java 对象头 在32位虚拟机和64位虚拟机的 Mark Word 所占用的字节大小不一样,32位虚拟机的 Mark Word 和 class Pointer ...偏向锁、轻量级锁的状态转化及对象Mark Word的关系 偏向锁的获得和撤销流程 时序图 流程图
  • 偏向锁,轻量级锁与重量级锁的区别与膨胀

    万次阅读 多人点赞 2017-03-19 20:44:01
    一直被这三个锁的膨胀问题所困扰,不知道到底实在什么时候会有偏向锁升级到轻量级锁,什么时候由轻量级锁升级到重量级锁。找到好久,也没有找到简洁明了的答案。  综合多个方面的描述综合自己的理解,特地记录下来...
  • 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...
  • 目录 一、Synchronized使用场景 二、Synchronized实现原理 三、的优化 1、升级 2、粗化 ...3、消除 ...Synchronized是一个同步...什么情况下会数据不安全呢,要满足两个条件:一是数据共享(临界资源),二...
  • synchronized原理分析初识 synchronizedsynchronized 用法锁是如何存储的synchronized 锁升级偏向锁偏向锁的获取偏向锁的撤销偏向锁及撤销流程图偏向锁注意事项轻量级锁轻量级锁加锁轻量级锁解锁轻量级锁及膨胀流程...
  • Java面试--偏向锁、自旋锁、轻量级锁、重量级锁

    千次阅读 多人点赞 2018-08-08 09:41:59
    (面试题)讲下偏向锁、自旋锁、轻量级锁、重量级锁 一、自旋锁 如果持有锁的线程能在很短时间内释放锁资源,那么那些等待竞争锁的线程就不需要做内核态和用户态之间的切换进入阻塞挂起状态,它们只需要等一等...
  • 一、简介 在讲解这些概念之前,我们要明确的是这些不等同于Java API中的ReentratLock这种,这些是概念上的,是JDK1.6中为了对synchronized同步关键字进行优化而产生的的机制。这些的启动和关闭策略可以...
  • 自旋可以使线程在没有取得的时候,不被挂起,而转去执行一个空循环,(即所谓的自旋,就是自己执行空循环),若在若干个空循环后,线程如果可以获得,则继续执行。若线程依然不能获得,才会被挂起。 使用...
  • 为什么出现CAS? 我们知道synchronized关键字不论是实现同步方法还是同步代码块,都需要首先执行...monitor机制是JDK1.6之前synchronized(内建锁)底层原理,又称为JDK1.6重量级锁。线程的阻塞和唤醒均...
  • 2018年6月份,网上曝出三秒打开智能的“小黑盒”,前天央视又再次报道,大批智能存在安全隐患,对于智能已经“上车”的用户而言,难免会有担忧,近期也有不少亲戚朋友在问,如何提升安全防护,小编认为,...
  • Java线程并发中常见的锁--自旋锁 偏向锁 轻量级锁 轻量级锁
  • 五,轻量级锁 六,自旋锁 SpinLock 七,重量级锁 八,在应用层提高锁效率的方案 一,概述 什么是java的锁? 为什么java要有锁? java的锁为什么需要优化? 怎么优化的? 1,java中使用synchronized关键字...
  • 基础知识之一:的类型从宏观上分为:(1)乐观;(2)悲观。(1)乐观乐观是一种乐观思想,即认为读多写少,遇到并发写的可能性低,每次去拿数据的时候都认为别人不会修改,所以不会上,但是在更新的...
  • 今天来讲一下偏向锁、轻量级锁、重量级锁的升级以及区别。 锁的状态: 无锁状态 偏向锁状态 轻量级锁状态 重量级锁状态 四种状态会随着竞争的情况逐渐升级,而且是不可逆的过程,即不可降级。 要注意的是...
  • 在学习sychronized关键字及其实现细节的时候,发现java中的三种锁,偏向锁,轻量级锁,重量级锁其实也有很多值得探究的地方,引入偏向锁是为了在无多线程竞争的情况下尽量减少不必要的轻量级锁执行路径,因为轻量...
  • 今天总结了锁升级(偏向锁、轻量级锁、重量级锁)和锁优化下面开始总结。 其实这些内容都是JVM对锁进行的一些优化,为什么分开讲,原因是锁升级比较重要,也比较难。 一、锁升级 在1.6之前java中不存在只存在...
  • 理解的基础知识 如果想要透彻的理解Java的来龙去脉,需要先了解以下基础知识。 基础知识之一:的类型 从宏观上分类,分为悲观与乐观。 乐观 乐观是一种乐观思想,即认为读多写少,遇到并发写的...
  • 大多数人都会称呼其为重量级锁,但是随着JAVA1.6对synchronized的优化,其变得不再那么重了。1.6中为了减少获得锁和释放锁带来的性能消耗而引入的偏向锁和轻量级锁,以及锁的存储结构和升级过程。下面我们一起来探究...
  • HotSpot虚拟机中,对象在内存中存储的布局可以分为三块区域:对象头(Object Header)、实例数据(Instance Data)和对齐填充(Padding)。 ...那么这个时候轻量级锁就会膨胀为重量级锁。  
  • Java程序员面试必备,深入浅出Java锁优化。偏向锁,轻量级锁,锁消除,锁粗化,自旋锁全总结
  • 各种锁策略1、乐观锁VS悲观锁2、读写锁3、重量级锁vs轻量级锁.4、挂起等待锁VS自旋锁5、公平锁Vs非公平锁6、可重入锁7、死锁的典型场景 1、乐观锁VS悲观锁 乐观锁: 世界大概率是和平的,多个线程竞争一 把锁的概率会...
  • 接触过线程安全的同学想必都使用过synchronized这个关键字,在java同步代码快中,synchronized的使用方式无非有两个: 通过对一个对象进行加锁来实现同步,如下面代码。 synchronized(lockObject){ //代码 } ...
  • 根据竞争状态的激烈程度,会自动进行升级,不能降级(为了提高获取) 一、偏向 由于老版本的内建synchronized存在最大的问题:在存在线程竞争的情况下会出现线程的阻塞以及唤醒带来的性能问题,这是一...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 183,308
精华内容 73,323
关键字:

几类锁最安全