查漏补缺第二期(synchronized & 锁升级)

本文涉及的产品
检索分析服务 Elasticsearch 版,2核4GB开发者规格 1个月
简介: 前言目前正在出一个查漏补缺专题系列教程, 篇幅会较多, 喜欢的话,给个关注❤️ ~本专题主要以Java语言为主, 好了, 废话不多说直接开整吧~Q1 & 请说说对synchronized的理解在Java中,关键字synchronized用于实现多线程之间的同步。它可以应用于方法或代码块,并确保在同一时间只有一个线程可以访问被同步的代码段.

前言

目前正在出一个查漏补缺专题系列教程, 篇幅会较多, 喜欢的话,给个关注❤️ ~

本专题主要以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 专题学习

项目源码(源码已更新 欢迎star⭐️)

ElasticSearch 专题学习

项目源码(源码已更新 欢迎star⭐️)

往期并发编程内容推荐

推荐 SpringBoot & SpringCloud (源码已更新 欢迎star⭐️)

博客(阅读体验较佳)






















































相关文章
|
4月前
|
Java 开发者 C++
Java多线程同步大揭秘:synchronized与Lock的终极对决!
Java多线程同步大揭秘:synchronized与Lock的终极对决!
92 5
|
4月前
|
安全 Java 开发者
Java多线程同步:synchronized与Lock的“爱恨情仇”!
Java多线程同步:synchronized与Lock的“爱恨情仇”!
90 5
|
4月前
|
Java
多线程同步新姿势:Lock接口助你“一统江湖”!
多线程同步新姿势:Lock接口助你“一统江湖”!
53 2
|
4月前
|
存储 安全 Java
解锁Java并发编程奥秘:深入剖析Synchronized关键字的同步机制与实现原理,让多线程安全如磐石般稳固!
【8月更文挑战第4天】Java并发编程中,Synchronized关键字是确保多线程环境下数据一致性与线程安全的基础机制。它可通过修饰实例方法、静态方法或代码块来控制对共享资源的独占访问。Synchronized基于Java对象头中的监视器锁实现,通过MonitorEnter/MonitorExit指令管理锁的获取与释放。示例展示了如何使用Synchronized修饰方法以实现线程间的同步,避免数据竞争。掌握其原理对编写高效安全的多线程程序极为关键。
71 1
|
4月前
|
Java 开发者
解锁Java并发编程的秘密武器!揭秘AQS,让你的代码从此告别‘锁’事烦恼,多线程同步不再是梦!
【8月更文挑战第25天】AbstractQueuedSynchronizer(AQS)是Java并发包中的核心组件,作为多种同步工具类(如ReentrantLock和CountDownLatch等)的基础。AQS通过维护一个表示同步状态的`state`变量和一个FIFO线程等待队列,提供了一种高效灵活的同步机制。它支持独占式和共享式两种资源访问模式。内部使用CLH锁队列管理等待线程,当线程尝试获取已持有的锁时,会被放入队列并阻塞,直至锁被释放。AQS的巧妙设计极大地丰富了Java并发编程的能力。
51 0
|
4月前
|
安全 Java 调度
震撼揭秘!手撕并发编程迷雾,Semaphore与CountDownLatch携手AQS共享模式,让你秒懂并发神器背后的惊天秘密!
【8月更文挑战第4天】在Java并发编程中,AbstractQueuedSynchronizer (AQS) 是核心框架,支持独占锁与共享锁的实现。本文以Semaphore与CountDownLatch为例,深入解析AQS共享模式的工作原理。Semaphore通过AQS管理许可数量,控制资源的并发访问;而CountDownLatch则利用共享计数器实现线程间同步。两者均依赖AQS提供的tryAcquireShared和tryReleaseShared方法进行状态管理和线程调度,展示了AQS的强大功能和灵活性。
46 0
|
7月前
|
监控 安全 Java
CompletableFuture探秘:解锁Java并发编程的新境界
CompletableFuture探秘:解锁Java并发编程的新境界
247 0
|
存储 安全 Java
大白话讲解synchronized锁升级套路
synchronized锁是啥?锁其实就是一个对象,随便哪一个都可以,Java中所有的对象都是锁,换句话说,Java中所有对象都可以成为锁。 这次我们主要聊的是synchronized锁升级的套路
132 0
synchronized锁升级原理剖析 ✨ 每日积累
synchronized锁升级原理剖析 ✨ 每日积累
synchronized锁升级原理剖析 ✨ 每日积累
|
存储 安全 Java
小白也能看懂的锁升级过程和锁状态
小白也能看懂的锁升级过程和锁状态
271 0
小白也能看懂的锁升级过程和锁状态