Synchronized关键字的底层原理?
创始人
2025-07-14 13:31:55
0

1. synchronized的基本使用

在现实场景中,抢票代码,如果不加锁,就会出现超卖或者一张票卖给多个人

Synchronized对象锁采用互斥的方式让同一时刻至多只有一个线程能持有对象锁,其它线程再想获取这个对象锁时就会阻塞住,代码如下

public class synchronizedTest {
    // 创建一个静态对象作为锁
    static Object lock = new Object();
    // 初始票数
    int ticketNum = 20;

    // 获取票的方法,使用 synchronized 修饰确保线程安全
    public synchronized void getTicket() {
        // 使用当前对象作为锁
        synchronized (this) {
            // 如果票数已经为零,则返回
            if (ticketNum <= 0) {
                return;
            }
            System.out.println(Thread.currentThread().getName() + "抢到一张票,剩余:" + ticketNum);
            // 非原子性操作,扣除一张票
            ticketNum--;
        }
    }

    public static void main(String[] args) {
        // 创建 synchronizedTest 实例
        synchronizedTest synchronizedTest = new synchronizedTest();
        // 创建并启动 20 个线程
        for (int i = 0; i < 20; i++) {
            // 调用获取票的方法
            new Thread(() -> synchronizedTest.getTicket()).start();
        }
    }
}

通过以上代码,加synchronized锁,就可以防止超卖

特别说明:synchronized 关键字的底层实现涉及到 Java 虚拟机中的监视器(Monitor)机制。每个 Java 对象都与一个 Monitor 相关联,Monitor 负责对象的锁定和解锁,以及线程的阻塞和唤醒。

2. Monitor

Monitor 被翻译为监视器,是由jvm提供,c++语言实现

使用一下简单代码中查看monitor,通过javap命令查看clsss的字节码

public class MonitorTest {
    static final Object lock = new Object();
    static int counter = 0;
    public static void main(String[] args) {
        synchronized (lock) {
            counter++;
        }
    }
}

图片图片

  • monitorenter: 上锁开始的地方
  • monitorexit:  解锁的地方
  • 其中被monitorenter和monitorexit包围住的指令就是上锁的代码

思考:为什么会出现两个monitorexit

有两个monitorexit的原因,第二个monitorexit是为了防止锁住的代码抛异常后不能及时释放锁在使用了synchornized代码块时需要指定一个对象,所以synchornized也被称为对象锁

monitor主要就是跟这个对象产生关联,如下图

图片图片

Monitor内部具体的存储结构:

  • Owner:存储当前获取锁的线程的,只能有一个线程可以获取
  • EntryList:关联没有抢到锁的线程,处于Blocked状态的线程
  • WaitSet:关联调用了wait方法的线程,处于Waiting状态的线程

具体的流程:

  • 代码进入synchorized代码块,先让lock(对象锁)关联的monitor,然后判断Owner是否有线程持有
  • 如果没有线程持有,则让当前线程持有,表示该线程获取锁成功
  • 如果有线程持有,则让当前线程进入entryList进行阻塞,如果Owner持有的线程已经释放了锁,在EntryList中的线程去竞争锁的持有权(非公平)
  • 如果代码块中调用了wait()方法,则会进去WaitSet中进行等待

3.面试题

面试官:synchronized关键字的底层原理?

  • Synchronized【对象锁】
  • 采用互斥的方式让同一时刻至多只有一个线程能持有【对象锁】
  • 它的底层由monitor实现的,monitor是jvm级别的对象( C++实现),线程获得锁需要使用对象(锁)关联monitor
  • 在monitor内部有三个属性,分别是owner、entrylist、waitset
  • 其中owner是关联的获得锁的线程,并且只能关联一个线程;entrylist关联的是处于阻塞状态的线程;waitset关联的是处于Waiting状态的线程

相关内容

热门资讯

如何允许远程连接到MySQL数... [[277004]]【51CTO.com快译】默认情况下,MySQL服务器仅侦听来自localhos...
如何利用交换机和端口设置来管理... 在网络管理中,总是有些人让管理员头疼。下面我们就将介绍一下一个网管员利用交换机以及端口设置等来进行D...
施耐德电气数据中心整体解决方案... 近日,全球能效管理专家施耐德电气正式启动大型体验活动“能效中国行——2012卡车巡展”,作为该活动的...
Windows恶意软件20年“... 在Windows的早期年代,病毒游走于系统之间,偶尔删除文件(但被删除的文件几乎都是可恢复的),并弹...
20个非常棒的扁平设计免费资源 Apple设备的平面图标PSD免费平板UI 平板UI套件24平图标Freen平板UI套件PSD径向平...
德国电信门户网站可实时显示全球... 德国电信周三推出一个门户网站,直观地实时提供其安装在全球各地的传感器网络检测到的网络攻击状况。该网站...
为啥国人偏爱 Mybatis,... 关于 SQL 和 ORM 的争论,永远都不会终止,我也一直在思考这个问题。昨天又跟群里的小伙伴进行...
《非诚勿扰》红人闫凤娇被曝厕所... 【51CTO.com 综合消息360安全专家提醒说,“闫凤娇”、“非诚勿扰”已经被黑客盯上成为了“木...