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

Java并发编程笔记

一、JUC介绍

1. 为什么需要JUC?
  • 传统并发缺陷synchronized关键字存在性能瓶颈(重量级锁)、缺乏灵活性(不可中断、非公平)。
  • JUC优势
    • 提供更细粒度的锁控制(如ReentrantLock的可中断、超时获取锁)。
    • 非阻塞算法提升性能(如CAS替代锁竞争)。
    • 丰富的并发工具(线程池、并发容器、同步器等)。
2. JUC的设计思想
  • 分工:通过线程池管理线程资源(如ThreadPoolExecutor)。
  • 协作:利用同步工具协调线程执行顺序(如CountDownLatch)。
  • 互斥:通过锁和原子类保证线程安全(如ReentrantLockAtomicInteger)。

二、JUC重点


1. 锁机制:AQS(AbstractQueuedSynchronizer)
核心原理
  • CLH队列:通过双向链表实现线程排队,避免自旋导致的CPU浪费。
  • 状态变量(state):通过volatile修饰的int值表示锁状态(如重入次数)。
  • 模板方法模式:子类实现tryAcquire/tryRelease定义锁获取和释放逻辑。
面试高频问题
  • Q:AQS如何实现公平锁与非公平锁?
    // 非公平锁(默认)
    final boolean nonfairTryAcquire(int acquires) {
        // 直接尝试获取锁,不检查队列
    }
    
    // 公平锁
    protected final boolean tryAcquire(int acquires) {
        // 先检查队列中是否有等待线程
        if (hasQueuedPredecessors()) return false;
        // ...
    }
    
  • Q:AQS的唤醒机制如何避免“惊群效应”?
    • 仅唤醒队列中第一个可用线程,而非所有线程。

2. 显式锁:ReentrantLock vs synchronized
对比维度ReentrantLocksynchronized
锁获取方式需手动lock()/unlock()自动获取和释放(代码块或方法)
可中断性支持(lockInterruptibly()不支持
公平性支持公平与非公平(构造函数指定)仅非公平
条件变量支持多条件(newCondition()单一等待队列
性能高并发场景更优优化后(偏向锁、轻量级锁)性能接近
使用示例
ReentrantLock lock = new ReentrantLock();
Condition condition = lock.newCondition();

lock.lock();
try {
    while (queue.isEmpty()) {
        condition.await();  // 释放锁并等待
    }
    // 业务逻辑
} finally {
    lock.unlock();
}

3. 并发容器
ConcurrentHashMap
  • JDK 7 vs JDK 8
    • JDK7:分段锁(Segment),每个段独立加锁。
    • JDK8CAS + synchronized锁单个链表头节点,粒度更细。
  • 关键方法
    • putVal():通过spread(hash)计算索引,CAS插入节点。
    • size():基于CounterCell的分段统计,避免竞争。
CopyOnWriteArrayList
  • 适用场景:读多写少(如监听器列表)。
  • 实现原理:写操作时复制新数组,替换旧引用(保证最终一致性)。

4. 线程池(ThreadPoolExecutor)
核心参数
public ThreadPoolExecutor(
    int corePoolSize,      // 核心线程数(长期保留)
    int maximumPoolSize,  // 最大线程数
    long keepAliveTime,   // 非核心线程空闲存活时间
    TimeUnit unit,
    BlockingQueue<Runnable> workQueue, // 任务队列
    RejectedExecutionHandler handler   // 拒绝策略
)
任务处理流程
  1. 提交任务,若核心线程未满,创建新线程执行。
  2. 核心线程已满,任务进入阻塞队列。
  3. 队列已满,创建非核心线程执行。
  4. 线程数达最大值且队列满,触发拒绝策略。
拒绝策略
  • AbortPolicy(默认):抛出RejectedExecutionException
  • CallerRunsPolicy:由提交任务的线程直接执行。
  • DiscardOldestPolicy:丢弃队列最旧任务,重试提交。
  • DiscardPolicy:静默丢弃新任务。

5. 同步工具类
CountDownLatch vs CyclicBarrier
对比项CountDownLatchCyclicBarrier
重置性一次性可重复使用
等待动作主线程等待其他线程完成所有线程相互等待
核心方法countDown() + await()await()
典型场景启动准备、任务分阶段提交多线程计算后合并结果
Semaphore
  • 作用:控制同时访问资源的线程数(如限流)。
  • 示例:数据库连接池管理。
    Semaphore semaphore = new Semaphore(10); // 允许10个并发
    semaphore.acquire();   // 获取许可
    try {
        // 访问资源
    } finally {
        semaphore.release();
    }
    

三、JUC面试题

1. volatile关键字的作用?
  • 可见性:保证变量修改后立即同步到主内存。
  • 禁止指令重排序:通过内存屏障实现(如单例模式的双重检查锁)。
2. CAS的ABA问题如何解决?
  • 版本号机制:使用AtomicStampedReference记录变量版本。
3. 线程池如何避免内存泄漏?
  • 务必关闭线程池:调用shutdown()shutdownNow()
  • 使用有界队列:避免任务无限堆积导致OOM。

相关文章:

  • unity3d端监听 uri scheme
  • 解决Docker端口映射后外网无法访问的问题
  • Leetcode-100 回溯法-单词搜索
  • c#中的virtual方法
  • redis错误分析 forceUnlock的问题说明
  • #基于Django实现机器学习医学指标概率预测网站
  • 双塔模型2之如何选择正确的正负样本
  • Matlab基础知识与常见操作【无痛入门】
  • GPT Workspace体验
  • # 基于 OpenCV 的选择题自动批改系统实现
  • 预测地震的方法,如何使用AI和量子传感器发挥作用?
  • 基于PySide6与CATIA API的装配体位置管理工具开发实践
  • 使用Python爬虫获取淘宝App商品详情
  • HTML5贪吃蛇游戏开发经验分享
  • 在DE2-115板子上用 Verilog编程实现一个 分秒计数器,并具备按键暂停、按键消抖功能
  • 拼多多 anti-token unidbg 分析
  • androidstudio安装完成后创建新的示例项目编译报错解决
  • VRRP交换机三层架构综合实验
  • Java 图书管理系统
  • 预览器的使用-查看多端设备预览效果
  • js做各类图表网站/北京疫情太严重了
  • avada主题做网站/站长之家域名查询
  • 网站建设 英语词汇/百度一下就一个
  • 06628网页制作与网站建设/百度百度一下
  • 网站备案证明/淘宝店怎么运营和推广
  • 十大手游平台排行榜/内蒙古seo