前言
目前正在出一个查漏补缺专题
系列教程, 篇幅会较多, 喜欢的话,给个关注❤️ ~
本专题主要以Java
语言为主, 好了, 废话不多说直接开整吧~
Q1 & 请说说对synchronized的理解
在Java
中,关键字synchronized
用于实现多线程之间的同步。它可以应用于方法或代码块,并确保在同一时间只有一个线程可以访问被同步的代码段.
- 保证原子性:
synchronized
关键字用于对临界区代码进行加锁,确保多个线程无法同时执行被同步的代码块或方法。这样可以保证代码块或方法中的操作是原子
的, 即要么全部执行完毕,要么不执行,从而避免了竞态条件(race condition
)的问题。 - 内置锁(
Intrinsic Lock
):在Java中,每个对象都有一个内置的锁,也称为监视器锁或互斥锁。当一个线程进入synchronized
代码块时,它必须首先获得对象的内置锁,其他线程必须等待直到锁被释放。这样确保了同一时间只有一个线程能够执行被同步的代码块。 - 互斥性和可见性:
synchronized
关键字不仅提供了互斥访问,还确保了可见性。当一个线程获取到锁时,它会清空工作内存中的变量副本,强制从主内存中重新加载变量的值。这样可以确保线程在访问变量时获取最新的值,而不是使用过期的副本。 - 锁的粒度:
- 对象锁:当使用
synchronized
修饰实例方法时,锁定的是当前对象实例。这意味着同一时间只有一个线程可以访问该实例的synchronized
方法,不同的实例之间互不影响。 - 类锁:当使用
synchronized
修饰静态方法时,锁定的是整个类对象。这意味着同一时间只有一个线程可以访问该类的任意一个synchronized
静态方法,无论是不同实例还是相同实例。
- 重入性:
Java
中的synchronized
关键字支持重入性。也就是说,如果一个线程已经获得了一个对象的锁,它可以再次获取该对象的锁而不会被阻塞。这种机制允许线程在同步代码块内部调用其他同步方法,避免了自己阻塞自己的情况。
总之,Java
中的synchronized
关键字提供了一种简单而有效的方法来确保多线程之间的同步和线程安全性。它通过使用内置锁、互斥性和可见性保证了临界区代码的原子性执行,避免了数据竞争和数据不一致的问题。
下面我们通过一些例子复习一下:
- 同步代码块(
Synchronized Blocks
):除了使用synchronized
修饰整个方法外,还可以使用synchronized
修饰一段代码块,称为同步代码块。这样可以在方法中只对某一部分代码进行同步,而不是整个方法。
public void someMethod() { // 非同步代码 synchronized (this) { // 需要同步的代码 } // 非同步代码 }
在上面的示例中,使用synchronized(this)
将某个对象作为锁来同步代码块,只有一个线程可以进入同步代码块,其他线程需要等待。
- 同步方法(
Synchronized Methods
):这是synchronized
的常见用法,将关键字直接应用于方法上,以实现整个方法的同步。当一个线程进入同步方法时,它会获得方法所属对象的锁,其他线程需要等待。
public synchronized void someMethod() { // 需要同步的代码 }
同步静态方法(Synchronized Static Methods)
:类级别的方法可以使用synchronized
关键字进行同步。与同步方法类似,但是锁的范围是该方法所在的类对象。
public static synchronized void someMethod() { // 需要同步的代码 }
同步块的对象锁(Object Lock of Synchronized Blocks)
:在同步代码块中,可以使用任意的对象作为锁,而不仅仅是this
关键字。这使得我们可以更细粒度地控制同步。
public void someMethod() { Object lock = new Object(); // 非同步代码 synchronized (lock) { // 需要同步的代码 } // 非同步代码 }
同步锁的重入(Reentrant Synchronization)
:在Java
中,一个线程在获得一个对象锁后,可以再次获得该对象的锁。这种重入机制可以避免线程死锁
。
public synchronized void methodA() { // 执行一些操作 methodB(); // 可重入,可以再次获得锁 // 执行一些操作 } public synchronized void methodB() { // 执行一些操作 }
Q2 & synchronized锁升级有了解过吗,它是怎么样的一个过程?
锁升级是指在Java
中,synchronized
关键字在不同的情况下可以升级使用不同级别的锁,以提高性能和减少开销。Java中的锁升级主要涉及到偏向锁、轻量级锁和重量级锁这三个级别。
偏向锁(Biased Locking)
: 偏向锁是指当只有一个线程访问同步块时,为了减少同步开销,JVM
会自动将对象的锁记录下来,标记为偏向锁状态。当其他线程访问该同步块时,不需要竞争锁,而是直接获取锁。- 锁升级过程:
- 初始状态:对象没有锁标记。
- 偏向锁申请:当第一个线程访问同步块时,JVM将该线程ID记录在对象头部,并将对象的标记状态设置为偏向锁。
- 偏向锁撤销:当其他线程尝试获取锁时,发现对象的偏向锁被占用,会撤销偏向锁,升级为轻量级锁。
public class BiasedLockExample { private static final Object lock = new Object(); public static void main(String[] args) { synchronized (lock) { // 同步块 } } }
轻量级锁(Lightweight Locking)
:轻量级锁
是指当多个线程轻度竞争同步块时,JVM
会将对象的锁记录在线程的栈帧
中,而不是在对象头中。线程在进入同步块之前,通过CAS
(比较并交换)操作尝试获取锁。如果CAS
成功,则表示获取锁成功,进入同步块;如果CAS
失败,表示存在竞争,升级为重量级锁。- 锁升级过程:
- 初始状态:对象没有锁标记。
- 轻量级锁
申请
:第一个线程进入同步块时,JVM
将锁的记录信息复制到线程的栈帧
中,并将对象的标记状态设置为轻量级锁
。 - 轻量级锁
竞争
:当其他线程尝试获取锁时,会使用CAS
操作来竞争锁。如果CAS
成功,表示获取锁成功,进入同步块;如果CAS
失败,表示存在竞争,升级为重量级锁
。
public class LightweightLockExample { private static final Object lock = new Object(); public static void main(String[] args) { synchronized (lock) { // 同步块 } } }
重量级锁(Heavyweight Locking)
: 重量级锁是指当多个线程激烈竞争同步块时,JVM
会将对象的锁升级为重量级锁,使用操作系统提供的互斥量
来实现锁机制。重量级锁涉及到线程的阻塞和唤醒操作,开销较大。- 锁升级过程:
- 初始状态:对象没有锁标记。
- 重量级锁申请:当多个线程轮流竞争同步块时,锁会直接升级为重量级锁,通过操作系统提供的互斥量来实现锁机制。
public class HeavyweightLockExample { private static final Object lock = new Object(); public static void main(String[] args) { synchronized (lock) { // 同步块 } } }
需要注意的是,锁升级的过程是由JVM
自动完成的,开发人员无需显式
地控制锁升级。JVM
会根据同步竞争的情况来自动
选择合适的锁级别,以提供更好的性能和效率。
结束语
大家可以针对自己薄弱的地方进行复习, 然后多总结,形成自己的理解,不要去背~
本着把自己知道的都告诉大家,如果本文对您有所帮助,点赞+关注
鼓励一下呗~
相关文章
项目源码(源码已更新 欢迎star⭐️)
往期设计模式相关文章
- 一起来学设计模式之认识设计模式
- 一起来学设计模式之单例模式
- 一起来学设计模式之工厂模式
- 一起来学设计模式之建造者模式
- 一起来学设计模式之原型模式
- 一起来学设计模式之适配器模式
- 一起来学设计模式之桥接模式
- 一起来学设计模式之组合模式
- 一起来学设计模式之装饰器模式
- 一起来学设计模式之外观模式
- 一起来学设计模式之享元模式
- 一起来学设计模式之代理模式
- 一起来学设计模式之责任链模式
- 一起来学设计模式之命令模式
- 一起来学设计模式之解释器模式
- 一起来学设计模式之迭代器模式
- 一起来学设计模式之中介者模式
- 一起来学设计模式之备忘录模式
- 一起来学设计模式之观察者模式
- 一起来学设计模式之状态模式
- 一起来学设计模式之策略模式
- 一起来学设计模式之模板方法模式
- 一起来学设计模式之访问者模式
- 一起来学设计模式之依赖注入模式
设计模式项目源码(源码已更新 欢迎star⭐️)
Kafka 专题学习
- 一起来学kafka之Kafka集群搭建
- 一起来学kafka之整合SpringBoot基本使用
- 一起来学kafka之整合SpringBoot深入使用(一)
- 一起来学kafka之整合SpringBoot深入使用(二)
- 一起来学kafka之整合SpringBoot深入使用(三)
项目源码(源码已更新 欢迎star⭐️)
ElasticSearch 专题学习
- 利用docker搭建es集群
- 一起来学ElasticSearch(一)
- 一起来学ElasticSearch(二)
- 一起来学ElasticSearch(三)
- 一起来学ElasticSearch(四)
- 一起来学ElasticSearch(五)
- 一起来学ElasticSearch(六)
- 一起来学ElasticSearch(七)
- 一起来学ElasticSearch(八)
- 一起来学ElasticSearch(九)
- 一起来学ElasticSearch(十)
- 一起来学ElasticSearch之整合SpringBoot(一)
- 一起来学ElasticSearch之整合SpringBoot(二)
- 一起来学ElasticSearch之整合SpringBoot(三)
项目源码(源码已更新 欢迎star⭐️)
往期并发编程内容推荐
- Java多线程专题之线程与进程概述
- Java多线程专题之线程类和接口入门
- Java多线程专题之进阶学习Thread(含源码分析)
- Java多线程专题之Callable、Future与FutureTask(含源码分析)
- 面试官: 有了解过线程组和线程优先级吗
- 面试官: 说一下线程的生命周期过程
- 面试官: 说一下线程间的通信
- 面试官: 说一下Java的共享内存模型
- 面试官: 有了解过指令重排吗,什么是happens-before
- 面试官: 有了解过volatile关键字吗 说说看
- 面试官: 有了解过Synchronized吗 说说看
- Java多线程专题之Lock锁的使用
- 面试官: 有了解过ReentrantLock的底层实现吗?说说看
- 面试官: 有了解过CAS和原子操作吗?说说看
- Java多线程专题之线程池的基本使用
- 面试官: 有了解过线程池的工作原理吗?说说看
- 面试官: 线程池是如何做到线程复用的?有了解过吗,说说看
- 面试官: 阻塞队列有了解过吗?说说看
- 面试官: 阻塞队列的底层实现有了解过吗? 说说看
- 面试官: 同步容器和并发容器有用过吗? 说说看
- 面试官: CopyOnWrite容器有了解过吗? 说说看
- 面试官: Semaphore在项目中有使用过吗?说说看(源码剖析)
- 面试官: Exchanger在项目中有使用过吗?说说看(源码剖析)
- 面试官: CountDownLatch有了解过吗?说说看(源码剖析)
- 面试官: CyclicBarrier有了解过吗?说说看(源码剖析)
- 面试官: Phaser有了解过吗?说说看
- 面试官: Fork/Join 有了解过吗?说说看(含源码分析)
- 面试官: Stream并行流有了解过吗?说说看
推荐 SpringBoot & SpringCloud (源码已更新 欢迎star⭐️)
- springboot-all
地址
: github.com/qiuChenglei…- SpringBoot系列教程合集
- 一起来学SpringCloud合集
- SpringCloud整合 Oauth2+Gateway+Jwt+Nacos 实现授权码模式的服务认证(一)
- SpringCloud整合 Oauth2+Gateway+Jwt+Nacos 实现授权码模式的服务认证(二)