18.3.2 synchronized关键字实现原理

1. synchronized基础概念

1.1 synchronized的作用和特点

public class SynchronizedBasics {
    
    private int count = 0;
    private final Object lock = new Object();
    
    // 1. 修饰实例方法
    public synchronized void incrementInstance() {
        count++;
        System.out.println("实例方法同步,count = " + count);
    }
    
    // 2. 修饰静态方法
    public static synchronized void incrementStatic() {
        System.out.println("静态方法同步");
    }
    
    // 3. 修饰代码块 - 实例对象锁
    public void incrementBlock() {
        synchronized (this) {
            count++;
            System.out.println("实例对象锁,count = " + count);
        }
    }
    
    // 4. 修饰代码块 - 类锁
    public void incrementClassLock() {
        synchronized (SynchronizedBasics.class) {
            System.out.println("类锁同步");
        }
    }
    
    // 5. 修饰代码块 - 自定义锁
    public void incrementCustomLock() {
        synchronized (lock) {
            count++;
            System.out.println("自定义锁,count = " + count);
        }
    }
}

1.2 synchronized锁的分类

实例方法锁

this对象

当前实例的所有synchronized实例方法

synchronized void method()

静态方法锁

Class对象

当前类的所有synchronized静态方法

static synchronized void method()

实例对象锁

指定对象

使用同一对象的synchronized块

synchronized(this)

类锁

Class对象

使用同一Class对象的synchronized块

synchronized(Class.class)

自定义锁

自定义对象

使用同一自定义对象的synchronized块

synchronized(lock)

2. synchronized底层实现原理

2.1 字节码层面的实现

public class SynchronizedBytecode {
    
    private int value = 0;
    
    // 同步方法的字节码实现
    public synchronized void syncMethod() {
        value++;
    }
    
    // 同步代码块的字节码实现
    public void syncBlock() {
        synchronized (this) {
            value++;
        }
    }
    
    /*
     * 字节码分析:
     * 
     * 同步方法:
     * - 方法访问标志包含ACC_SYNCHRONIZED
     * - JVM通过检查方法访问标志来实现同步
     * 
     * 同步代码块:
     * - 使用monitorenter指令进入同步块
     * - 使用monitorexit指令退出同步块
     * - 编译器会确保每个monitorenter都有对应的monitorexit
     */
}

2.2 Monitor机制详解

public class MonitorMechanism {
    
    private final Object monitor = new Object();
    private int sharedResource = 0;
    
    /*
     * Monitor(监视器)是synchronized的核心实现机制
     * 
     * Monitor结构:
     * - Owner: 当前持有锁的线程
     * - EntryList: 等待获取锁的线程队列
     * - WaitSet: 调用wait()方法等待的线程集合
     * - Count: 重入计数器
     */
    
    public void demonstrateMonitorMechanism() {
        ExecutorService executor = Executors.newFixedThreadPool(5);
        
        for (int i = 0; i < 10; i++) {
            final int threadId = i;
            executor.submit(() -> {
                acquireMonitor(threadId);
            });
        }
        
        executor.shutdown();
    }
    
    private void acquireMonitor(int threadId) {
        synchronized (monitor) {
            System.out.println("线程" + threadId + "获得monitor,开始执行");
            
            try {
                Thread.sleep(100);
                sharedResource++;
                System.out.println("线程" + threadId + "处理完毕,sharedResource = " + sharedResource);
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
            
            System.out.println("线程" + threadId + "释放monitor");
        }
    }
    
    // 演示wait/notify机制
    public void demonstrateWaitNotify() {
        final Object waitMonitor = new Object();
        
        // 等待线程
        Thread waiterThread = new Thread(() -> {
            synchronized (waitMonitor) {
                try {
                    System.out.println("等待线程进入WaitSet");
                    waitMonitor.wait(); // 进入WaitSet,释放monitor
                    System.out.println("等待线程被唤醒,重新获得monitor");
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                }
            }
        });
        
        // 通知线程
        Thread notifierThread = new Thread(() -> {
            try {
                Thread.sleep(2000);
                synchronized (waitMonitor) {
                    System.out.println("通知线程获得monitor,准备唤醒等待线程");
                    waitMonitor.notify();
                    System.out.println("通知线程发出notify信号");
                }
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        });
        
        waiterThread.start();
        notifierThread.start();
    }
}

3. synchronized锁优化机制

3.1 JVM锁优化策略

public class SynchronizedOptimization {
    
    private int counter = 0;
    
    /*
     * JVM对synchronized的优化:
     * 1. 偏向锁(Biased Locking)
     * 2. 轻量级锁(Lightweight Locking)
     * 3. 重量级锁(Heavyweight Locking)
     * 4. 锁消除(Lock Elimination)
     * 5. 锁粗化(Lock Coarsening)
     */
    
    // 演示偏向锁
    public void demonstrateBiasedLock() {
        System.out.println("=== 偏向锁演示 ===");
        
        // 单线程环境下,synchronized会优化为偏向锁
        for (int i = 0; i < 1000000; i++) {
            synchronized (this) {
                counter++; // 偏向锁:记录线程ID,无需CAS操作
            }
        }
        
        System.out.println("偏向锁执行完毕,counter = " + counter);
    }
    
    // 演示轻量级锁
    public void demonstrateLightweightLock() {
        System.out.println("=== 轻量级锁演示 ===");
        
        Thread thread1 = new Thread(() -> {
            for (int i = 0; i < 500000; i++) {
                synchronized (this) {
                    counter++; // 轻量级锁:使用CAS操作
                }
            }
        });
        
        Thread thread2 = new Thread(() -> {
            for (int i = 0; i < 500000; i++) {
                synchronized (this) {
                    counter++; // 当有竞争时,偏向锁升级为轻量级锁
                }
            }
        });
        
        thread1.start();
        thread2.start();
        
        try {
            thread1.join();
            thread2.join();
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
        
        System.out.println("轻量级锁执行完毕,counter = " + counter);
    }
    
    // 演示锁消除
    public void demonstrateLockElimination() {
        System.out.println("=== 锁消除演示 ===");
        
        // JVM会检测到这个锁没有逃逸到方法外部,会消除这个锁
        for (int i

剩余60%内容,订阅专栏后可继续查看/也可单篇购买

Java面试圣经 文章被收录于专栏

Java面试圣经,带你练透java圣经

全部评论

相关推荐

📍面试公司:联想(Lenovo)🕐面试时间:2025年08月23日💻面试岗位:C++研发工程师❓面试问题:一、现代C++特性与语言演进&nbsp;(C++11/14/17/20)1.​​右值引用与移动语义​​:解释std::move和std::forward的区别?完美转发是如何实现的?2.​​智能指针进阶​​:std::shared_ptr的线程安全性如何?std::weak_ptr如何解决循环引用?3.​​C++17/20新特性​​:谈谈你对std::optional,&nbsp;std::variant,&nbsp;std::string_view的理解。C++20的Coroutines(协程)有什么优势?4.​​类型推导与模板​​:auto和decltype有什么区别?模板参数包(Parameter&nbsp;Pack)如何展开?二、内存管理新范式1.​​内存池技术​​:如何自己实现一个内存池?2.​​检测与优化​​:除了Valgrind,还有哪些工具(如ASAN、MSAN)可用于检测内存问题?如何重载new和delete来跟踪内存分配?三、并发编程与现代多线程1.​​原子操作与内存模型​​:std::atomic&lt;T&gt;是如何保证原子性的?解释一下内存序(Memory&nbsp;Order):memory_order_relaxed、memory_order_acquire、memory_order_release的区别和应用场景。2.​​无锁编程​​:什么是无锁(Lock-Free)数据结构?尝试实现一个无锁的队列或栈。3.​​协程​​:C++20的协程底层机制是什么?co_await、co_yield、co_return分别做了什么?四、STL容器与算法新特性1.​​新容器​​:std::unordered_map的负载因子和再哈希策略是怎样的?C++23引入了哪些新容器?2.​​算法复杂度与选择​​:std::sort用的是哪种排序算法?什么情况下会退化为O(n²)?如何避免?五、系统设计与性能优化1.​​设计线程安全的LRU缓存​​:要求get和put操作的时间复杂度为O(1),并考虑高并发场景。2.​​零拷贝技术​​:如何在Linux下使用sendfile或splice实现零拷贝文件传输?3.​​高性能日志系统​​:如何设计一个每秒处理千万级日志条目且保证零丢失的采集系统?六、设计模式与架构演进1.​​现代C++下的设计模式​​:如何使用移动语义和智能指针实现单例模式、工厂模式?2.​​分布式系统概念​​:如何理解分布式缓存中的缓存击穿、雪崩和穿透?如何设计一个防护系统?七、手撕代码题目更新1.​​实现一个移动语义优化的字符串类​​(MiniString),要求支持拷贝构造、移动构造、析构。2.​​实现一个简化版的std::shared_ptr​​(MySharedPtr),模拟引用计数。3.​​实现一个线程安全的环形缓冲区(Ring&nbsp;Buffer)​​,支持多生产者和多消费者。🙌面试感想:联想的C++面试很​​现代化和深度化​​。面试官不仅考察传统的语言特性和底层原理,还会深入询问​​C++17/20的新特性、无锁编程、协程、高性能系统设计​​等前沿话题。手撕代码环节的题目综合性更强,常要求实现一个小型的数据结构或系统组件,并考虑线程安全和性能。项目经验部分问得非常细,要求候选人能清晰说明技术选型、性能优化证据链和故障排查路径。整体感觉面试官水平很高,乐于追问,氛围既有挑战性又很专业。
查看19道真题和解析
点赞 评论 收藏
分享
1.&nbsp;没有考虑过留在之前实习过的公司吗?2.&nbsp;你主要用的语言是&nbsp;Java&nbsp;还是&nbsp;Go?Go&nbsp;的底层你了解吗?3.&nbsp;你过去哪一段项目是你觉得比较有挑战的?能具体聊聊吗?4.&nbsp;要不先讲讲你现在在字节的项目?你介绍一下?5.&nbsp;你做的这个&nbsp;SDK&nbsp;是在解决什么问题?什么叫同步/异步?6.&nbsp;老系统和新系统,你们为什么要做迁移?老系统代码量和问题在哪里?7.&nbsp;你总结一下你做的这个&nbsp;SDK&nbsp;的核心功能,能提炼为三点吗?8.&nbsp;你的&nbsp;SDK&nbsp;是放在业务系统里的吗?9.&nbsp;如果&nbsp;SDK&nbsp;需要升级,怎么推动所有调用方升级?10.&nbsp;聊聊你在快手的项目,哪个部分最有挑战?11.&nbsp;算法:两数之和12.&nbsp;你为什么要用哈希表来做?和暴力循环&nbsp;O(n²)&nbsp;的方法相比,哈希表有什么好处?13.&nbsp;如果数组有上千万的数据,你的哈希表能装得下吗?14.&nbsp;如果内存放不下所有数据,你会怎么处理?(分块/落盘/分文件…)15.&nbsp;有没有更高效的方案?16.&nbsp;你的方法只能找到一组解,如果有多组解怎么办?17.&nbsp;你觉得现在的&nbsp;O(n)&nbsp;算法还有优化的空间吗?18.&nbsp;假设你在浏览器输入一个网站的&nbsp;URL,然后点确认,到最后看到网站页面,中间发生了什么?19.&nbsp;HTTP&nbsp;和&nbsp;HTTPS&nbsp;的区别是什么?HTTPS&nbsp;的安全性是怎么保证的?20.&nbsp;HTTPS&nbsp;的证书交换、加密解密的过程是怎么样的?21.&nbsp;HTTP/2&nbsp;和&nbsp;HTTP/1.1&nbsp;有什么区别?HTTP/2&nbsp;做了哪些优化?22.&nbsp;你最近在看什么技术?对什么方向比较感兴趣?
发面经攒人品
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务