synchronized 知识点整理:特性、用法、锁机制

张开发
2026/4/3 12:25:20 15 分钟阅读
synchronized 知识点整理:特性、用法、锁机制
一、synchronized的特性在 Java 多线程编程中 synchronized 是解决线程安全问题最基础、最常用的关键字。它通过锁机制保证原子性、可见性与有序性。本文将从核心特性、使用方式、底层锁机制三个维度完整梳理 synchronized 的关键知识点。1.互斥synchronized会起到独占互斥效果某个线程执行到某个对象的synchronized中时其他线程如果也执行到同一个synchronized就会阻塞等待。进入synchronized修饰的代码块相当于加锁退出synchronized的修饰的代码块就会阻塞等待两个线程竞争同一把锁才会产生阻塞等待两个线程分别尝试获取两把不同的锁不会产生竞争。2.保证内存可见性线程释放锁时会将工作内存中修饰的共享变量刷新到主内存中线程获取锁时会清空工作内存中共享变量的值从主内存重新读取最新值这避免了多线程因CPU缓存、指令重排序等问题导致读取旧数据的情况。二、synchronized的使用synchronized需要搭配一个具体的对象来使用1、修饰代码块明确指定锁哪个对象锁任意对象public class Demo22 { private Object lockernew Object(); public void method(){ synchronized (locker){ } } }锁当前对象thispublic class Demo22 { public void method(){ synchronized (this){ } } }2.直接修饰普通方法锁的synchronizedDemo对象public class SynchronizedDemo{ public synchronized void method(){ } }这个等价于synchronizedthis3.修饰静态方法锁的SynchronizedDemo类对象public class SynchronizedDemo{ public synchronized static void method(){ } }三、synchronized的锁机制1.自适应锁锁升级流程synchronized会根据锁竞争激烈程度自动升级锁状态核心对比三组策略悲观锁 VS 乐观锁悲观锁在加锁的时候预测接下来的锁竞争的情况非常激烈就需要针对这样的激烈情况额外做一些工作。乐观锁在加锁的时候预测接下来的锁竞争的情况不激烈就不需要做额外工作重量级锁 VS 轻量级锁重量级锁是当悲观的场景下此时要付出更多的代价开销大轻量级锁应对乐观的场景此时付出的代价就会更小开销小挂起等待锁 VS 自旋锁挂起等待锁是操作系统内核级别的加锁的时候发现竞争就会使该线程进入阻塞状态后续就需要内核进行唤醒了。自旋锁是应用程序级别的加锁的时候发现竞争一般也不是进入阻塞而是通过忙等的形式来进行等待。synchronized在以上的三种锁机制中是自适应的自适应的过程锁升级无锁-偏向锁-自旋锁-重量级锁偏向锁进行synchronized一开始不是真的加锁而是只是简单做一个标记这个标记非常轻量相比于加锁解锁来说效率很高如果没有其他线程来竞争这个锁最终当前线程执行到解锁代码也就只是简单清除上述标记即可。如果有其他线程来竞争就抢先一步在另一个线程拿到锁之前抢先拿到锁。轻量级锁采用自旋方式等待锁避免线程阻塞切换开销。重量级锁竞争激励、自旋无效时升级为内核级挂去等待锁线程进入阻塞。2.非读写锁——普通互斥锁读写锁是它将对共享资源的访问分为“读操作”和“写操作”允许多个线程同时读但是只允许一个线程写且写操作会阻塞使用读和写。读锁和读锁之间不是互斥的不会产生阻塞。写锁和读锁之间会产生互斥写锁和写锁之间也会互斥。而synchronized是普通互斥锁读和写都独占锁即使多个读操作也需排队。3.可重入锁synchronized同步块对于同一条线程来说是可重入的不会出现自己把自己锁死的问题当重入次数和释放对应次数相等时才算是真正解锁。4.非公平锁假设有A、B、C三个线程A先获取到了锁然后B尝试获取锁然后C再尝试获取锁此时B和C都在阻塞队列中排队等待但是当A释放锁之后并没有执行B比C先来的这种公平规则而是B和C重新竞争。

更多文章