synchronized实现原理总结

synchronized用于多线程同步访问临界区,保证线程安全

实现原理

基于对象头的MarkWord存储锁状态,实现获取锁,释放锁以及锁升级

所以首先要了解对象头,在未开启指针压缩情况下:
对象头 = 8byte的MarkWord + 8byte的ClassPointer
开启指针压缩后:
对象头 = 8byte的MarkWord + 4byte的ClassPointer + 4byte的对齐数据
对齐是因为64位的JVM寻址空间是8byte,必须为8byte的整数倍

以下程序可以验证:JDK8自动开启指针压缩
关闭指针压缩:-XX:-UseCompressedOops
在这里插尬入图片描述在这里插入图片描述
测试代码

import org.openjdk.jol.info.ClassLayout;

/**
 * 测试对象头
 */
public class T14_Object_Header {
    public static void main(String[] args){
        Object o = new Object();
        System.out.println(ClassLayout.parseInstance(o).toPrintable());
    }
}

JVM源码中锁在对象头上的标识枚举

enum {   locked_value             = 0,//00 轻量级锁
         unlocked_value           = 1,//01 无锁
         monitor_value            = 2,//10 监视器锁,也叫膨胀锁,也叫重量级锁
         marked_value             = 3,//11 GC标记
         biased_lock_pattern      = 5 //101 偏向锁
};

锁升级

在这里插入图片描述
无锁:刚new出来的对象,无任何锁竞争
偏向锁:一段同步代码一直被一个线程所访问,对象会在对象头上标识该线程,那么该线程会自动获取到锁
自旋锁:多个线程竞争同步代码,会以自旋和CAS的方式获取对象的锁
重量级锁:CAS竞争激烈,升级到操作系统的申请锁,由操作系统决定是否获取到锁

测试代码

JDK6后默认开启偏向锁,但是会延时加载,使用JVM参数取消延时加载

-XX:+UseBiasedLocking -XX:BiasedLockingStartupDelay=0

import org.openjdk.jol.info.ClassLayout;

/**
 * 测试锁升级   -XX:+UseBiasedLocking -XX:BiasedLockingStartupDelay=0
 */
public class T14_Object_Header_None_Lock {
    public static void main(String[] args) throws InterruptedException {
        Object o = new Object();
        System.out.println("before lock");
        System.out.println(ClassLayout.parseInstance(o).toPrintable());
        synchronized (o) {
            System.out.println("locking...........");
            System.out.println(ClassLayout.parseInstance(o).toPrintable());
        }
        System.out.println("after lock");
        System.out.println(ClassLayout.parseInstance(o).toPrintable());
    }
}

获取偏向锁和撤销偏向锁流程
在这里插入图片描述
自旋锁升级重量级锁流程
在这里插入图片描述

CAS原理

操作:CAS有3个操作数,内存值V,旧的预期值A,要修改的新值B。如果A=V,那么把B赋值给V,返回V;如果A!=V,直接返回V
实现:JNI调用native方法:unsafe.compareAndSwapInt(this, valueOffset, expect, update);
底层lock cmpxchg指令,lock用于多CPU情况下保证单CPU执行操作,cmpxchg用于比较替换

synchronized的特性

原子性和可见性:多个线程是同步的方式访问临界区的,所以具有天然的原子性和可见性
可重入:如果是一个同步方法调用另外一个同步方法,有一个方法加了锁,另外一个方法也需要加锁,加的是同一把锁也是同一个线程,那这个时候申请仍然会得到该对象的锁
不可逆:锁升级的流程是不可逆转的

synchronized的用法

同步代码块和同步方法

package com.example.code.juc;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

public class T15_Sync {
    private int count1 = 10;
    private int count2 = 10;

    public void m1() {
        synchronized (this) {
            count1--;
            System.out.print("count = " + count1 + "   ");
        }
    }

    public synchronized void m2() {
        count2--;                            // 等价 synchronized (this)
        System.out.print("count = " + count2 + "   ");
    }


    public static void main(String[] args) throws InterruptedException {
        ExecutorService executorService = Executors.newFixedThreadPool(10);

        T15_Sync t = new T15_Sync();
        for (int i = 0; i < 10; i++) {
            executorService.submit(new Thread(t::m1, "t" + i + "m1"));
        }

        executorService.awaitTermination(3, TimeUnit.SECONDS);
        System.out.println("m1结束!!!");


        for (int i = 0; i < 10; i++) {
            executorService.submit(new Thread(t::m2, "t" + i + "m2"));
        }

        executorService.awaitTermination(3, TimeUnit.SECONDS);
        System.out.println("m2结束!!!");
    }
}

同步静态方法

package com.example.code.juc;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

public class T16_Sync {
    private static int count3 = 10;
    private static int count4 = 10;

    public static void m3() {
        synchronized (T16_Sync.class) {
            count3--;
            System.out.print("count = " + count3 + "   ");
        }
    }

    public synchronized static void m4() {   // 等价 synchronized (T01_Synchronized.class)
        count4--;
        System.out.print("count = " + count4 + "   ");
    }

    public static void main(String[] args) throws InterruptedException {
        ExecutorService executorService = Executors.newFixedThreadPool(10);

        for (int i = 0; i < 10; i++) {
            executorService.submit(new Thread(() -> {
                T16_Sync.m3();
            }, "t" + i + "m3"));
        }

        executorService.awaitTermination(3, TimeUnit.SECONDS);
        System.out.println("m3结束!!!");

        for (int i = 0; i < 10; i++) {
            executorService.submit(new Thread(() -> {
                T16_Sync.m4();
            }, "t" + i + "m4"));
        }

        executorService.awaitTermination(3, TimeUnit.SECONDS);
        System.out.println("m4结束!!!");
    }
}
  • 4
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值