Java:保证线程安全的加锁机制之synchronized

前言

   在解决线程安全的方法里,有一个方法是阻塞同步,这篇文章就来详细说其中的synchronized

一、介绍

   synchronized是较早提出一个加锁机制,它是可以自动加锁解锁的一个可重入锁

二、synchronized的用法

  1. 作用:提供了一种锁,能够保证共享变量的互斥访问,从而防止数据不一致问题的出现。
  2. 用法
    (1)加在方法声明中:
    public synchronized void method(){
        //给调用该方法的对象加锁
    }

注意:给方法加锁实际是给调用该方法的对象加锁,但并不能使调用该方法的多个对象在执行顺序上互斥。
         (2)给代码块加锁:

    synchronized (list){
            //给list加锁
    }

     3.synchronized可以保证并发编程的三大特性:原子性,有序性,可见性。

三、synchronized的原理

   我们反编译一个简单的同步代码块,会发现当一个线程访问synchronized修饰的同步代码块时,会使用这两个指令:

1.monitorentermonitorexit

(1)monitorenter:每一个对象都是一个监视器锁monitor,monitorenter就是当前线程尝试获取这个monitor。获取锁时分两种情况(实际是三种):

         ①线程尚未获取到monitor:如果成功获取,monitor的计数器就+1(初始值是0);如果该monitor已经被占有,就会进入Blocked阻塞状态,直到计数器再次变为0,再次去获取。

         ②线程已经获取到monitor:直接进入,monitor的计数器+1。

(2)monitorexit:当前线程释放对monitor的所有权,monitor的计数器-1。
(为什么不直接清零呢?因为一个线程可能需要多次获取这把锁,A操作使用了这把锁并完成,说不定还有B操作也要用这把锁,AB操作是线性的,而不是循环的。可以理解为多次获取是嵌套着获取每一层获取到后就+1,返回上一层就-1。)

   但是monitor具体是个什么呢,它是怎么存储的呢?看以下对象头的概念:

2.对象头:为了实现一些额外的功能,java中的每一个对象里都会有一些标记字段,这些标记字段就组成了对象头。

   对象头中通常由以下部分组成:

(1)MarkWord:用于存储对象自身的数据,如HashCode,锁状态标志位,偏向的线程ID等。
在这里插入图片描述
(2)class pointer:class pointer用来存储对象的类型指针。该指针指向它的类元数据,JVM通过这个指针确定对象是哪个类的实例

(3)array length:如果对象是一个数组,那么对象头还需要存储数组的长度array length。

   synchronized加锁原理就是改变该对象的对象头中的mark word中的数据,具体的过程如下:

3.synchronized的加锁过程:

(0)首先,当一个对象还没有被当成一把锁的时候,这个对象的对象头中的markword是无锁状态是否是偏向锁是0,锁标志位是01(参照上文markword图表)

(1)当这个对象被认为是同步锁并且有一个线程拿到了这把锁时,这个锁就成了偏向锁状态,记录偏向的线程ID,是否是偏向锁标志位变成1,但锁标志位还是01
         当这个线程继续获取这把锁时,如果系统检查该锁的monitor中markword的是否是偏向锁标志位是1,锁标志位是01,并且线程ID也是它自己,就可以让它持续访问这把锁。

(2)当来了除了已占有锁的线程以外的其他线程时,系统发现保存的线程ID和来获取锁的线程ID不一样,就不让他获取。于是这个新来的线程就会使用CAS操作(Compare And Swap,在上篇文章的第三部分讲到了具体原理)来继续获取这把锁:
         原先存放在markword的线程ID自带的一个参数与当前markword存放线程ID的地址中的值相比较,如果相等,就将markword中的线程ID换成新来线程的线程ID。(在各个线程中都有一块内存来保存要抢占的锁的markword的引用。如果这块引用使用CAS保存下来了,就说明这个线程抢占这把锁成功了,成功了就会把标志位修改成00,执行锁中的代码。)
         如果这步的CAS失败,就会将这个锁升级成轻量级锁标志位修改成00(因为该锁存在竞争所以要升级成更重的。)

(3)接下来继续抢占。没成功,就是轻量级锁抢占失败。轻量级锁失败了,就会使用自旋锁不断的去抢锁(也不会一直抢占,有一个阈值限制),抢到了就执行锁中的代码,没抢到就会将这把锁升级成重量级锁

(4)重量级锁的状态下,所有未抢占到锁的线程都会被阻塞。

   synchronized加锁原理是非常重要的知识点,尤其是加锁的具体过程的描述,必须要熟记!!!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值