欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 新闻 > 会展 > Java并发编程笔记

Java并发编程笔记

2025/4/2 11:01:50 来源:https://blog.csdn.net/2201_75559074/article/details/146772838  浏览:    关键词: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。

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com