当前位置: 首页 > news >正文

北京JAVA基础面试30天打卡03

1.AQS(AbstractQueuedSynchronizer)

AQS(AbstractQueuedSynchronizer) 是 Java 并发包(java.util.concurrent)中的一个核心框架类,用于构建锁和同步器(如 ReentrantLock、Semaphore、CountDownLatch 等)。它提供了一种基于队列的同步机制,管理线程的阻塞和唤醒。

核心思想

AQS 通过一个 FIFO 队列(基于 CLH 锁队列的变种)和一个 状态变量(int state)来实现线程同步:

  • 状态变量:表示锁或同步器的状态(如锁是否被占用,计数器的值等)。
  • 队列:维护等待获取锁的线程,线程进入队列后会被阻塞,直到满足条件被唤醒。
  • CAS 操作:通过 Compare-And-Swap(如 compareAndSetState)实现状态的原子更新。
工作原理
  1. 状态管理:AQS 维护一个 volatile int state,通过 CAS 操作修改状态。例如,ReentrantLock 中 state=0 表示锁空闲,state>0 表示锁被占用。

  2. 队列管理:当线程无法获取锁时,加入 AQS 的等待队列(CLH 队列),线程会被挂起(LockSupport.park)。

  3. 获取/释放

    • 获取锁:子类实现 tryAcquire 方法,尝试更新 state。成功则获取锁,失败则进入队列。
    • 释放锁:子类实现 tryRelease 方法,更新 state,并唤醒队列中的下一个线程(LockSupport.unpark)。
  4. 条件队列:AQS 支持 Condition 接口(如 ConditionObject),用于实现线程的条件等待(如 await 和 signal)。

核心方法
  • 模板方法

    (由 AQS 提供,子类实现):

    • tryAcquire(int):尝试获取锁。
    • tryRelease(int):尝试释放锁。
    • tryAcquireShared(int):尝试共享式获取资源。
    • tryReleaseShared(int):尝试共享式释放资源。
    • isHeldExclusively():判断锁是否独占。
  • 核心 API

    • acquire(int):获取锁(独占模式),包括尝试获取和入队阻塞。
    • release(int):释放锁,唤醒队列中的线程。
    • acquireShared(int) / releaseShared(int):共享模式的获取和释放。
使用场景

AQS 是许多 JUC 工具类的底层实现:

  • ReentrantLock:基于 AQS 实现可重入锁,state 表示锁的重入次数。
  • ReentrantReadWriteLock:读写锁,state 高 16 位表示读锁计数,低 16 位表示写锁状态。
  • Semaphore:信号量,state 表示可用许可数。
  • CountDownLatch:倒计数器,state 表示剩余计数。
  • CyclicBarrier:state 用于管理屏障状态。
优点
  • 灵活性:通过模板方法,子类可以自定义锁的语义。
  • 高效性:基于 CAS 和队列,减少上下文切换。
  • 可扩展性:支持独占锁、共享锁、条件等待等。

2. Synchronized 与 ReentrantLock 的区别

SynchronizedReentrantLock 都是 Java 中用于实现线程同步的机制,但它们在功能、性能和使用方式上有显著区别。

Synchronized
  • 定义:Java 关键字,内置的锁机制,由 JVM 管理。

  • 特点

    • 使用简单:通过 synchronized 关键字修饰代码块或方法,自动获取和释放锁。
    • 独占锁:同一时间只有一个线程可以持有锁。
    • 可重入:同一线程可以多次获取同一锁(锁计数器递增)。
    • 不可中断:线程在等待锁时无法被中断。
    • 自动释放:锁在代码块结束或异常时自动释放。
    • 无条件等待:不支持 Condition 机制,无法实现复杂等待/通知逻辑。
    • 性能:在 Java 6 之后,JVM 对 synchronized 进行了优化(如锁消除、锁粗化、偏向锁、轻量级锁),性能接近 ReentrantLock。
ReentrantLock
  • 定义:基于 AQS 实现的显式锁,位于 java.util.concurrent.locks 包。

  • 特点

    • 显式锁:需要手动调用 lock() 和 unlock() 获取/释放锁。
    • 可重入:与 synchronized 类似,支持重入。
    • 可中断:支持 lockInterruptibly(),允许线程在等待锁时被中断。
    • 公平/非公平:支持公平锁(按等待顺序分配)和非公平锁(默认,允许插队)。
    • 条件等待:支持 Condition 对象,可实现多个等待队列(如生产者-消费者模型)。
    • 灵活性:支持超时获取锁(tryLock(timeout))。
    • 手动释放:需在 finally 块中调用 unlock(),否则可能导致死锁。
区别总结
特性SynchronizedReentrantLock
实现方式JVM 内置,关键字JUC 包,基于 AQS
使用方式自动获取/释放锁手动 lock() / unlock()
可中断性不可中断可中断(lockInterruptibly)
公平性非公平锁可选公平锁或非公平锁
条件等待无 Condition 支持支持 Condition(多等待队列)
灵活性简单但功能有限功能丰富(超时、尝试锁等)
性能Java 6 后优化,接近 ReentrantLock稍高(尤其在复杂场景下)
异常处理自动释放锁需手动释放(finally 块)
使用场景
  • Synchronized:适合简单同步场景,如方法级或代码块级锁,代码简洁,适合快速开发。
  • ReentrantLock:适合需要高级功能的场景,如公平锁、可中断锁、条件等待、超时获取锁等。

代码示例

java

// Synchronizedsynchronized (obj) {// 同步代码块
}// ReentrantLock
ReentrantLock lock = new ReentrantLock();try {lock.lock();// 同步代码块
} finally {lock.unlock();
}

3. Java 中 volatile 关键字的作用

volatile 是 Java 中的一个关键字,用于修饰变量,确保变量在多线程环境下的可见性有序性,但不保证原子性

作用
  1. 保证可见性

    • 当一个线程修改了 volatile 变量的值,新值对其他线程立即可见。
    • 这是因为 volatile 变量的读写操作会直接与主内存交互,绕过线程的本地缓存(工作内存)。
    • 解决了多线程环境下缓存不一致的问题。
  2. 防止指令重排序

    • volatile 变量的读写操作会添加内存屏障(Memory Barrier),防止 JVM 或 CPU 进行指令重排序。
    • 确保代码的执行顺序与程序顺序一致(如初始化对象的正确性)。
  3. 不保证原子性

    • volatile 仅保证读写的原子性,但对复合操作(如 i++)不保证原子性。
    • 例如,volatile int i 的 i++ 操作分为读、改、写三步,多个线程可能交错执行,导致数据不一致。
使用场景
  • 状态标志:如 volatile boolean running = true,用于控制线程的启动/停止。
  • 单次写入,多次读取:如配置变量,初始化后只读不写。
  • 配合其他机制:与 synchronized 或 Atomic 类结合使用,解决原子性问题。
示例

java

class VolatileExample {volatile boolean flag = false;void writer() {flag = true; // 写入对其他线程立即可见}void reader() {if (flag) { // 读取到最新值System.out.println("Flag is true");}}
}
volatile 与 synchronized 的区别
  • volatile
    • 仅保证变量的可见性和有序性,不保证复合操作的原子性。
    • 轻量级,适用于简单场景(如标志位)。
  • synchronized
    • 保证原子性、可见性和有序性。
    • 重量级,适用于需要锁保护的复杂同步场景。
注意事项
  • volatile 不适合需要原子性的场景(如计数器),应使用 AtomicInteger 或 synchronized。
  • volatile 的性能开销低于 synchronized,但仍需谨慎使用,避免滥用。

总结

  • AQS:Java 并发框架的核心,基于状态变量和队列实现锁和同步器,广泛用于 JUC 工具类。
  • Synchronized vs ReentrantLock:Synchronized 简单但功能有限,ReentrantLock 提供更多灵活性(如公平锁、条件等待)。
  • volatile:确保变量的可见性和有序性,适合状态标志等场景,但不保证原子性。
  • 明天二次补充拓展,希望大家坚持下去,不见彩虹也有阳光~
http://www.lryc.cn/news/612125.html

相关文章:

  • PDF注释的加载和保存的实现
  • Go语言数据类型深度解析:位、字节与进制
  • Git 乱码文件处理全流程指南:从识别到彻底清除
  • NodeJs学习日志(1):windows安装使用node.js 安装express,suquelize,sqlite,nodemon
  • 将英文PDF文件完整地翻译成中文的4类方式
  • jspdf或react-to-pdf等pdf报错解决办法
  • 使用阿里云服务器部署dify实战
  • Linux_详解进程信号
  • Python在大数据时代的角色与挑战:连接数据与智能的关键引擎
  • 大数据之HBase
  • 数字驾驶舱是什么意思?如何搭建驾驶舱
  • Hive【应用 04】常用DDL操作(数据库操作+创建表+修改表+清空删除表+其他命令)
  • 技术博客:从HTML提取到PDF生成的完整解决方案
  • 周志华院士西瓜书实战(二)MLP+SVM+贝叶斯分类器+决策树+集成学习
  • 19day-人工智能-机器学习-分类算法-决策树
  • 在LLM小型化趋势下,AI Infra需要做出哪些相应调整?
  • TrustZone技术详解————这篇是AI写的包括图
  • [滑动窗口]904. 水果成篮
  • Vue Router 路由的创建和基本使用(超详细)
  • BM89 合并区间
  • Diamond基础1:认识Lattice器件
  • 三维偏序 -- cdq 套 cdq
  • 一文读懂:什么是CLIP
  • 目录遍历漏洞学习
  • 560. 和为 K 的子数组 - 前缀和思想
  • kubeadm-k8s 中的 etcd 备份与恢复
  • Nginx 跨域(CORS)配置详细介绍
  • 【教程】C++编译官方CEF3
  • [Oracle] NVL()函数
  • Python:文件管理