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

每日学习Java之一万个为什么(JUC)

文章目录

  • Git复习
  • synchronized
    • 介绍
      • 基本概念
      • 特点
    • 使用模板
      • 1. 同步方法
        • 格式
        • 特点
      • 2. 同步代码块
        • 格式
        • 特点
    • 常见面试题
      • 1. `synchronized`的实现原理?
      • 2. `synchronized`与`ReentrantLock`的区别?
      • 3. `synchronized`的缺点?
      • 4. 死锁的四个必要条件?
      • 5. 如何避免死锁?
      • 6. `synchronized`是重量级锁吗?
      • 7. `synchronized`修饰静态方法时锁对象是什么?
  • ReentrantLock
    • 介绍
      • 基本概念
      • 实现原理
      • 特点
    • 使用模板
      • 1. 基础用法(非公平锁)
      • 2. 公平锁
      • 3. 尝试获取锁(非阻塞)
      • 4. 带超时的尝试获取锁
    • 常用方法
    • 常见面试题
      • 1. `ReentrantLock`与`synchronized`的区别?
      • 2. `ReentrantLock`的可重入性如何实现?
      • 3. `ReentrantLock`的公平锁与非公平锁有何区别?
      • 4. 如何避免`ReentrantLock`的锁泄漏?
      • 5. `Condition`的作用是什么?如何使用?
      • 6. `ReentrantLock`的锁降级是否可行?
      • 7. `ReentrantLock`的`tryLock()`与`synchronized`的区别?
    • 总结
  • Condition实现指定唤醒线程 以及代替wait/notify在Synchronized中的地位
    • Condition介绍
    • 使用模板
    • demo:指定唤醒线程(ABC轮流使用资源类)
    • demo:代替wait/notify在Synchronized中的地位(包括synchronized使用)
  • Condition
    • 常用方法
      • 核心方法
      • 其他方法
    • 常见面试题
      • 1. **Condition 的作用是什么?与 `wait/notify` 有何区别?**
      • 2. **为什么 `await()` 必须在持有锁时调用?**
      • 3. **`signal()` 和 `signalAll()` 的区别?**
      • 4. **`Condition` 如何实现精准唤醒?**
      • 5. **`Condition` 的实现原理?**
      • 6. **使用 `Condition` 时的注意事项?**
      • 7. **`Condition` 的典型应用场景?**
      • 8. **`Condition` 与 `synchronized` 的 `wait/notify` 的兼容性?**
      • 9. **`await()` 可能抛出的异常?**
      • 10. **如何实现带超时的条件等待?**
    • 总结
  • JUC 容器类 CopyOnWriteXXX / ConcurrentHashMap
    • 常见面试题
    • **1. JUC中常见的线程安全容器有哪些?**
    • **2. ConcurrentHashMap与Hashtable的区别?**
    • **3. 为什么JDK1.8后ConcurrentHashMap舍弃分段锁?**
    • **4. CopyOnWriteArrayList的适用场景?**
    • **5. BlockingQueue的实现类有哪些?分别适用于什么场景?**
    • **6. 为什么JUC的ConcurrentHashMap要用synchronized而不是ReentrantLock?**
    • **7. 如何确保一个集合不能被修改?**
    • **8. 什么是fail-fast和fail-safe?JUC容器如何实现?**
    • **9. 说一下ConcurrentHashMap的实现原理(JDK1.8)?**
    • **10. BlockingQueue的take()和poll()有什么区别?**
    • **11. 如何选择线程安全的集合类?**
    • **12. 为什么Vector是遗留类?如何替代?**
    • **总结**
  • JUC 辅助类 CountDownLatch / CyclicBarrier / Semophore
    • CountDownLatchDemo(倒计时)
    • CyclicBarrierDemo(收集器)
    • SemaphoreDemo (信号量)可以代替锁
  • **CountDownLatch**
    • **常用方法**
    • **使用场景**
    • **常见面试题**
  • **CyclicBarrier**
    • **常用方法**
    • **使用场景**
    • **常见面试题**
  • **Semaphore**
    • **常用方法**
    • **使用场景**
    • **常见面试题**
    • **总结**

Git复习

在这里插入图片描述

以下是补充后的笔记内容,结构清晰,涵盖核心知识点和常见面试题:


synchronized

介绍

基本概念

  • 作用:Java中的synchronized关键字用于实现线程同步,确保同一时间只有一个线程访问被其修饰的代码块或方法,避免线程安全问题(如竞态条件、脏读等)。
  • 实现机制:基于Java内存模型(JMM)的监视器锁(Monitor),通过对象头中的Mark Word记录锁状态,支持偏向锁、轻量级锁、重量级锁的升级机制。
  • 适用场景:简单同步需求,代码简洁,但性能可能受限于锁升级后的重量级锁。

特点

  • 原子性:保证代码块或方法的原子操作。
  • 可见性:线程间共享变量的修改对其他线程可见。
  • 阻塞式同步:线程获取锁失败时会阻塞等待。

使用模板

1. 同步方法

格式
// 实例方法(锁对象为this)
public synchronized void method() { ... }// 静态方法(锁对象为类的Class对象)
public static synchronized void staticMethod() { ... }
特点
  • 锁对象
    • 实例方法:当前对象实例(this)。
    • 静态方法:类的Class对象(ClassName.class)。

2. 同步代码块

格式
// 对象锁(锁对象为obj)
synchronized(obj) {// 同步代码块
}// 示例:使用this作为锁
synchronized(this) { ... }// 示例:使用类锁(静态方法等效)
synchronized(ClassName.class) { ... }
特点
  • 灵活性:可自定义锁对象,避免全类或全实例的锁竞争。
  • 推荐实践:锁对象应为私有且不可变,避免被外部误用。

常见面试题

1. synchronized的实现原理?

  • Monitor对象:JVM通过对象头中的Mark Word记录锁状态。
  • 锁状态升级
    1. 偏向锁:默认为线程分配偏向锁,减少同步开销(JDK6引入)。
    2. 轻量级锁:通过CAS尝试获取锁,失败则升级为重量级锁。
    3. 重量级锁:阻塞线程,依赖操作系统互斥量(性能开销大)。

2. synchronizedReentrantLock的区别?

特性synchronizedReentrantLock
中断性不支持支持(tryLock()可中断)
超时不支持支持(tryLock(long time)
公平性非公平可配置公平或非公平
功能简单易用更灵活(如条件变量Condition
性能重量级锁时性能较差通常更高(但需合理使用)

3. synchronized的缺点?

  • 不可中断:线程获取锁时无法中断。
  • 死锁风险:若多个线程互相等待锁,可能引发死锁。
  • 性能问题:重量级锁可能导致线程阻塞开销大。
  • 粒度控制不足:同步方法无法灵活控制锁范围。

4. 死锁的四个必要条件?

  1. 互斥:资源不可共享,同一时间只能被一个线程占用。
  2. 请求与保持:线程持有已分配资源,仍请求新资源。
  3. 不剥夺:资源无法被强制剥夺,只能由持有者释放。
  4. 循环等待:存在线程循环等待链(如A等待B的资源,B等待A的资源)。

5. 如何避免死锁?

  • 按顺序获取锁:所有线程按固定顺序申请锁。
  • 超时机制:使用tryLock()并设置超时时间。
  • 尽早释放锁:减少锁持有时间,避免在锁内执行耗时操作。

6. synchronized是重量级锁吗?

  • 早期JVM:是,依赖操作系统互斥量,开销大。
  • JDK6+:引入锁升级机制,优先使用偏向锁和轻量级锁,性能显著提升。

7. synchronized修饰静态方法时锁对象是什么?

  • 锁对象为类的Class对象(即ClassName.class)。

以下是补充后的 ReentrantLock 笔记,结构清晰且覆盖核心知识点和常见面试题:


ReentrantLock

介绍

基本概念

  • 作用:Java中用于实现线程同步的显式锁,需手动获取和释放,属于 java.util.concurrent.locks 包。
  • 可重入性:支持同一线程多次获取同一锁(递归锁),避免死锁。
  • 公平性:可选择公平模式(线程按排队顺序获取锁)或非公平模式(允许插队,性能更高)。

实现原理

  • 底层机制:基于**AQS(AbstractQueuedSynchronizer)**实现,通过CAS操作竞争锁。
  • 锁状态:通过内部计数器记录锁的持有次数,线程释放锁时需计数归零。

特点

  • 灵活性:支持尝试获取锁(tryLock())、超时获取锁、条件变量(Condition)等高级功能。
  • 需手动管理:必须显式调用 lock()unlock(),否则可能导致死锁或资源泄漏。

使用模板

1. 基础用法(非公平锁)

ReentrantLock lock = new ReentrantLock();// 获取锁
lock.lock();
try {// 同步代码块
} finally {lock.unlock(); // 必须确保释放锁
}

2. 公平锁

ReentrantLock fairLock = new ReentrantLock(true); // true表示公平模式

3. 尝试获取锁(非阻塞)

// 尝试立即获取锁,失败返回false
if (lock.tryLock()) {try {// 同步代码块} finally {lock.unlock();}
}

4. 带超时的尝试获取锁

// 尝试在1秒内获取锁,超时返回false
if (lock.tryLock(1, TimeUnit.SECONDS)) {try {// 同步代码块} finally {lock.unlock();}
}

常用方法

方法说明
lock()阻塞等待获取锁,直到成功或被中断。
unlock()释放锁,需确保在finally块中调用。
tryLock()非阻塞尝试获取锁,成功返回true,失败返回false。
tryLock(long time)在指定时间内尝试获取锁,超时返回false。
isHeldByCurrentThread()判断当前线程是否持有该锁。
getHoldCount()返回当前线程持有的锁次数(可重入计数)。
newCondition()创建与该锁绑定的Condition对象,用于线程间协作。

常见面试题

1. ReentrantLocksynchronized的区别?

特性ReentrantLocksynchronized
中断性支持(lockInterruptibly()不支持
超时支持(tryLock()不支持
公平性可配置(公平/非公平)默认非公平
功能支持Condition,更灵活内置锁,无需手动释放
性能通常更高(无锁升级机制)JDK6+优化后性能接近
语法显式调用lock()/unlock()隐式管理

2. ReentrantLock的可重入性如何实现?

  • 通过内部计数器记录锁的持有次数:
    • 线程首次获取锁时计数器设为1。
    • 再次获取锁时计数器递增。
    • 每次unlock()计数器递减,归零时释放锁。

3. ReentrantLock的公平锁与非公平锁有何区别?

  • 公平锁:线程按排队顺序获取锁,避免“饥饿”但性能稍差。
  • 非公平锁:允许新线程插队尝试获取锁(CAS竞争),性能更高但可能引发饥饿。

4. 如何避免ReentrantLock的锁泄漏?

  • 必须确保unlock()在finally块中调用,即使发生异常也要释放锁:
    lock.lock();
    try {// 业务逻辑
    } finally {lock.unlock();
    }
    

5. Condition的作用是什么?如何使用?

  • 作用:提供线程等待/唤醒机制,替代synchronizedwait()/notify()
  • 使用示例
    Condition condition = lock.newCondition();// 等待条件
    condition.await();// 唤醒一个等待线程
    condition.signal();// 唤醒所有等待线程
    condition.signalAll();
    

6. ReentrantLock的锁降级是否可行?

  • 不可直接实现:需通过二级锁(如ReentrantReadWriteLock)实现读写锁的降级。

7. ReentrantLocktryLock()synchronized的区别?

  • tryLock()是非阻塞的,失败直接返回false,而synchronized会阻塞等待。
  • tryLock()需配合unlock()手动释放锁。

总结

  • 适用场景:需要高级功能(如超时、条件变量)或对性能要求高时。
  • 注意事项:必须确保锁的释放,避免泄漏;合理选择公平性模式。
  • 替代方案synchronized适合简单场景,ReentrantLock适合复杂需求。

Condition实现指定唤醒线程 以及代替wait/notify在Synchronized中的地位

Condition介绍

使用模板

demo:指定唤醒线程(ABC轮流使用资源类)

package com.qxy.practice.concurrent;import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;/*** @author : 戚欣扬* @Description : //      v4   对Condtion的灵活运用,指定唤醒线程   A 5->B 10->C 15 loop 10*/
public class ThreadOrder {private int flag  = 1;private Lock lock = new ReentrantLock();private Condition key1 = lock.newCondition();private Condition key2 = lock.newCondition();private Condition key3 = lock.newCondition();/*** print 1-5*/public void print5(){lock.lock();try {while(flag!=1){key1.await();}for (int i = 0; i < 5; i++) {System.out.println(Thread.currentThread().getName()+":"+(i+1));}flag = 2;key2.signal();} catch (InterruptedException e) {throw new RuntimeException(e);} finally {lock.unlock();}}/*** print 1-10*/public void print10(){lock.lock();try {while(flag!=2){key1.await();}for (int i = 0; i < 10; i++) {System.out.println(Thread.currentThread().getName()+":"+(i+1));}flag = 3;key2.signal();} catch (InterruptedException e) {throw new RuntimeException(e);} finally {lock.unlock();}}/*** print 1-15*/public void print15(){lock.lock();try {while(flag!=3){key1.await();}for (int i = 0; i < 15; i++) {System.out.println(Thread.currentThread().getName()+":"+(i+1));}flag = 1;key2.signal();} catch (InterruptedException e) {throw new RuntimeException(e);} finally {lock.unlock();}}/*** main*/public static void main(String[] args) {ThreadOrder threadOrder = new ThreadOrder();for (int i = 0; i < 10; i++) {new Thread(()->{threadOrder.print5();},"A").start();new Thread(()->{threadOrder.print10();},"B").start();new Thread(()->{threadOrder.print15();},"C").start();}}}

demo:代替wait/notify在Synchronized中的地位(包括synchronized使用)

package com.qxy.practice.concurrent;import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;/*** @author : 戚欣扬* @code :*/
public class ThreadTransmit {private int num = 0 ;private Lock lock = new ReentrantLock();Condition condition1 = lock.newCondition();Condition condition2 = lock.newCondition();Condition condition3 = lock.newCondition();
//    V1 使用公平锁 / 睡眠实现 1+ 1-
/*    private Lock lock = new ReentrantLock();public void increase(){lock.lock();try{num++;System.out.println(Thread.currentThread().getName()+"num ="+num);}finally {lock.unlock();}}public void decrease(){lock.lock();try{num--;System.out.println(Thread.currentThread().getName()+"num ="+num);}finally {lock.unlock();}}public static void main(String[] args) throws InterruptedException {ThreadTransmit threadTransmit = new ThreadTransmit();for (int i = 0; i < 10; i++) {new Thread(()->{threadTransmit.increase();},"A").start();new Thread(()->{threadTransmit.decrease();},"B").start();}}*/
//      V2 使用synchronized+wait+notify 实现 虚假唤醒问题 死锁问题
/*        public synchronized void increase(){//判断while(num!=0){try {this.wait();} catch (InterruptedException e) {throw new RuntimeException(e);}}//执行System.out.println(Thread.currentThread().getName()+":num = " + (++num));//通知this.notifyAll();}public synchronized void decrease(){//判断while(num!=1){try {this.wait();} catch (InterruptedException e) {throw new RuntimeException(e);}}//执行System.out.println(Thread.currentThread().getName()+":num = " + (--num));//通知this.notifyAll();}public static void main(String[] args) {ThreadTransmit threadTransmit = new ThreadTransmit();new Thread(()->{for (int i = 0; i < 10; i++) {threadTransmit.increase();}},"A").start();new Thread(()->{for (int i = 0; i < 10; i++) {threadTransmit.decrease();}},"B").start();new Thread(()->{for (int i = 0; i < 10; i++) {threadTransmit.increase();}},"C").start();new Thread(()->{for (int i = 0; i < 10; i++) {threadTransmit.decrease();}},"D").start();}*/
//      v3      lock.lock() +condition.await() + condition.signalAll()
public  void increase(){lock.lock();try {//判断while(num!=0){try {condition1.await();} catch (InterruptedException e) {throw new RuntimeException(e);}}//执行System.out.println(Thread.currentThread().getName()+":num = " + (++num));//通知condition1.signalAll();} finally {lock.unlock();}
}public  void decrease(){lock.lock();try {//判断while(num!=1){try {condition1.await();} catch (InterruptedException e) {throw new RuntimeException(e);}}//执行System.out.println(Thread.currentThread().getName()+":num = " + (--num));//通知condition1.signalAll();} finally {lock.unlock();}}public static void main(String[] args) {ThreadTransmit threadTransmit = new ThreadTransmit();new Thread(()->{for (int i = 0; i < 10; i++) {threadTransmit.increase();}},"A").start();new Thread(()->{for (int i = 0; i < 10; i++) {threadTransmit.decrease();}},"B").start();new Thread(()->{for (int i = 0; i < 10; i++) {threadTransmit.increase();}},"C").start();new Thread(()->{for (int i = 0; i < 10; i++) {threadTransmit.decrease();}},"D").start();}
//      v4      A 5->B 10->C 15 loop 10// concurrentModifyException
}

以下是对 Condition 的补充笔记,涵盖 常用方法常见面试题,结合知识库内容整理:


Condition

常用方法

核心方法

方法说明注意事项
await()使当前线程进入等待状态,直到被通知或中断。必须在持有锁时调用,否则抛出 IllegalMonitorStateException
signal()唤醒一个等待在该 Condition 上的线程。必须在持有锁时调用,唤醒的线程会进入同步队列竞争锁。
signalAll()唤醒所有等待在该 Condition 上的线程。适用于需要通知所有等待线程的场景(如资源充足时唤醒所有消费者)。
await(long time, TimeUnit unit)在指定时间内等待,超时返回 false超时后线程会自动释放锁并返回。
awaitUninterruptibly()忽略中断,等待直到被通知。即使线程被中断也不会抛出异常。
awaitNanos(long nanosTimeout)基于纳秒时间等待,返回剩余时间(若超时返回负数)。精度高但需注意时间单位转换。

其他方法

方法说明
awaitUntil(Date deadline)在指定截止时间前等待,超时返回 false
isAlive()检查线程是否存活(实际由线程自身判断,Condition不直接提供此方法)。

常见面试题

1. Condition 的作用是什么?与 wait/notify 有何区别?

  • 作用
    Condition 是 Java 并发包中用于线程间协作的接口,提供更灵活的条件等待和通知机制,需与 Lock 配合使用。
  • wait/notify 的区别
    • 多条件支持:一个 Lock 可创建多个 Condition 对象,每个条件对应独立的等待队列(如生产者-消费者中的“队列满”和“队列空”)。
    • 精准唤醒signal() 可精准唤醒特定条件的线程,而 notify() 可能随机唤醒线程;signalAll() 仅唤醒当前 Condition 的队列,比 notifyAll() 更高效。
    • 显式绑定:Condition 需显式绑定到 Lock,而 wait/notify 依赖隐式 Object 的监视器锁。

2. 为什么 await() 必须在持有锁时调用?

  • 原因
    1. 调用 await() 会释放当前持有的锁,允许其他线程获取锁。
    2. 若未持有锁就调用,会抛出 IllegalMonitorStateException
  • 流程
    lock.lock();
    try {while (conditionNotMet) {condition.await(); // 释放锁并等待}// 执行业务逻辑condition.signal(); // 唤醒其他线程
    } finally {lock.unlock(); // 重新获取锁后释放
    }
    

3. signal()signalAll() 的区别?

  • signal()
    随机唤醒等待队列中的一个线程,使其竞争锁。适用于“只需一个线程响应”的场景(如消费者消费一个商品)。
  • signalAll()
    唤醒所有等待线程,它们会竞争锁。适用于“所有线程都需要处理变化”的场景(如资源充足时唤醒所有消费者)。
  • 注意
    唤醒后线程需重新竞争锁,最终只有一个线程能执行临界区代码。

4. Condition 如何实现精准唤醒?

  • 多条件队列
    一个 Lock 可创建多个 Condition,每个 Condition 对应独立的等待队列。例如:
    Condition notFull = lock.newCondition(); // 生产者等待条件
    Condition notEmpty = lock.newCondition(); // 消费者等待条件
    
  • 选择性通知
    生产者在添加元素后调用 notEmpty.signal(),仅唤醒消费者队列中的线程;消费者在移除元素后调用 notFull.signal(),唤醒生产者队列中的线程。

5. Condition 的实现原理?

  • 底层机制
    基于 AQS(AbstractQueuedSynchronizer) 实现,每个 Condition 对象维护一个 等待队列
    • await()
      1. 释放锁,当前线程加入 Condition 的等待队列。
      2. 线程被阻塞,直到被信号唤醒或超时。
    • signal()
      1. 将等待队列中的线程移至 AQS 的同步队列,使其有机会重新竞争锁。
      2. 线程获取锁后继续执行。

6. 使用 Condition 时的注意事项?

  1. 必须在锁保护下调用
    await()signal() 必须在 lock 保护的代码块中调用。
  2. 避免虚假唤醒
    使用 循环检查条件,而非单一判断(如生产者-消费者中需检查队列是否满/空)。
  3. 避免死锁
    确保 unlock()finally 块中调用,避免因异常导致锁未释放。
  4. 谨慎使用 awaitUninterruptibly()
    可能忽略中断信号,需根据业务场景权衡。

7. Condition 的典型应用场景?

  • 生产者-消费者模式
    // 生产者
    lock.lock();
    try {while (queue.isFull()) {notFull.await(); // 队列满时等待}queue.put(item);notEmpty.signal(); // 唤醒消费者
    } finally {lock.unlock();
    }
    
  • 读写锁:通过多个 Condition 实现读写线程的协调。
  • 线程池任务调度:根据任务队列状态通知空闲线程。

8. Conditionsynchronizedwait/notify 的兼容性?

  • 不可混用
    • Condition 必须与 Lock 配合使用,不能与 synchronizedwait/notify 混合。
    • 若混用会导致锁状态混乱,可能抛出 IllegalMonitorStateException

9. await() 可能抛出的异常?

  • InterruptedException
    当线程在等待时被中断,会抛出此异常,需在 catch 块中处理。
  • IllegalMonitorStateException
    未持有锁时调用 await()signal() 会抛出此异常。

10. 如何实现带超时的条件等待?

  • 使用 await(long time, TimeUnit unit)awaitNanos()
    if (condition.await(1, TimeUnit.SECONDS)) {// 在1秒内被唤醒,继续执行
    } else {// 超时处理
    }
    

总结

  • 核心价值:Condition 提供了比 wait/notify 更灵活的线程协作能力,支持多条件管理和精准唤醒。
  • 使用要点:必须与 Lock 配合,确保锁的正确释放和获取,避免死锁和资源泄漏。
  • 替代方案:简单场景可使用 synchronized,复杂场景推荐 ReentrantLock + Condition

JUC 容器类 CopyOnWriteXXX / ConcurrentHashMap

package com.qxy.practice.concurrent;import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.CopyOnWriteArrayList;/*** @author : 戚欣扬* @Description : 线程同步队列的两种使用*/
public class SyncListDemo {/*** 如果我们使用ArrayList造100个线程去读写同一个list,会报ConcurrentModifyException :*         if (to > es.length) {*             throw new ConcurrentModificationException();*         }* 1.使用工具类转换为线程安全集合 Collections. 2.使用 CopyOnWirte 读写分离,写时复制*/public static void main(String[] args) {//   List<String> list =  Collections.synchronizedList(new ArrayList<>());//new ArrayList<>();List<String> list = new CopyOnWriteArrayList<>();// HashSet 同理 HashMap 采用 ConcurrentHashMapfor (int i = 0; i < 100; i++) {new Thread(()->{list.add(UUID.randomUUID().toString().substring(0,6));System.out.println(list);},String.valueOf(i)).start();}}
}

常见面试题


1. JUC中常见的线程安全容器有哪些?

答案:

  • ConcurrentHashMap:线程安全的哈希表,替代Hashtable,支持部分并发操作。
  • CopyOnWriteArrayList:线程安全的动态数组,写时复制(Read-Copy-Update)实现。
  • CopyOnWriteArraySet:基于CopyOnWriteArrayList的线程安全Set实现。
  • ConcurrentSkipListMap/Set:基于跳表(SkipList)的有序线程安全集合。
  • BlockingQueue:阻塞队列(如ArrayBlockingQueue、LinkedBlockingQueue等),支持生产者-消费者模式。
  • ConcurrentLinkedQueue:非阻塞的线程安全队列,基于链表实现。

2. ConcurrentHashMap与Hashtable的区别?

答案:

特性ConcurrentHashMapHashtable
线程安全部分线程安全(分段锁/JDK1.8后CAS实现)全局锁(所有方法同步)
性能高并发下性能更好(分段锁/JDK1.8后无锁化)低效(单线程操作)
null值支持允许null键和值(JDK8+)不允许null键或值
迭代器失败为安全(fail-safe)失败快速(fail-fast)
实现原理分段锁(JDK1.7)或CAS+锁(JDK1.8+)全局synchronized

3. 为什么JDK1.8后ConcurrentHashMap舍弃分段锁?

答案:

  • 分段锁(Segment)的问题
    多个Segment锁仍存在竞争,且扩容时需锁所有Segment,性能受限。
  • JDK1.8的改进
    1. 基于CAS和锁:每个桶(Bucket)使用CAS操作,仅在哈希冲突时加锁单个桶。
    2. 无锁化设计:大部分读操作无需锁,写操作通过CAS和自旋实现。
    3. 数组+链表/红黑树:与HashMap结构一致,支持快速扩容和冲突处理。
  • 优势
    显著提升写操作的并发性能,同时保持读操作的高效性。

4. CopyOnWriteArrayList的适用场景?

答案:

  • 读多写少:写操作会复制整个数组,但读操作无需锁,适合读频繁场景。
  • 批量操作:如日志记录、配置列表等,写操作不频繁。
  • 避免迭代中断:迭代器是快照(fail-safe),不会抛出ConcurrentModificationException

缺点

  • 内存开销大(写操作复制数组)。
  • 写操作性能低,不适合频繁写入。

5. BlockingQueue的实现类有哪些?分别适用于什么场景?

答案:

实现类特点适用场景
ArrayBlockingQueue基于数组的有界队列,FIFO。固定容量的场景,需控制生产者速度。
LinkedBlockingQueue基于链表的可选有界队列,默认无界。无界队列或需要缓存的场景。
SynchronousQueue不存储元素,每个put必须等待一个take线程间直接交换数据(如线程池)。
PriorityBlockingQueue基于优先级堆的无界队列,按优先级排序。需按优先级处理任务的场景。
DelayQueue基于时间的延迟队列,元素只有在延迟时间到达后才能被取出。定时任务或延迟任务队列。
LinkedTransferQueue支持无界队列和扩展操作(如转移、批量操作)。需高效生产和消费的高并发场景。

6. 为什么JUC的ConcurrentHashMap要用synchronized而不是ReentrantLock?

答案:

  • 兼容性和性能
    • synchronized在JVM层面优化更好,JDK1.6后引入偏向锁、轻量级锁等机制,性能接近ReentrantLock
    • ConcurrentHashMap的锁粒度较小(如分段锁或单桶锁),同步块较短,synchronized的语法简洁性更优。
  • 代码简洁性
    synchronized的语法糖(自动释放锁)减少了代码复杂度,避免ReentrantLock需要显式unlock()的风险。

7. 如何确保一个集合不能被修改?

答案:

  • 使用不可变集合
    Collections.unmodifiableCollection()包装集合,返回只读视图。
  • 使用CopyOnWrite容器
    CopyOnWriteArrayList,写操作会抛出UnsupportedOperationException
  • 自定义实现
    继承集合类并重写修改方法,抛出异常或忽略操作。

8. 什么是fail-fast和fail-safe?JUC容器如何实现?

答案:

  • fail-fast
    • 机制:迭代过程中检测到结构修改(如并发修改),抛出ConcurrentModificationException
    • 实现:通过modCount计数器,迭代器维护expectedModCount,若不一致则抛异常。
    • 容器ArrayListHashMap等非线程安全集合。
  • fail-safe
    • 机制:迭代器基于快照(快照时的数据),忽略后续修改,不会抛异常。
    • 实现:基于写时复制(如CopyOnWriteArrayList)或版本控制(如ConcurrentHashMap)。
    • 容器CopyOnWriteArrayListConcurrentHashMap等线程安全集合。

9. 说一下ConcurrentHashMap的实现原理(JDK1.8)?

答案:

  1. 结构
    • 基于数组+链表/红黑树结构,与HashMap一致。
    • 数组元素为Node对象,每个节点包含键值对、哈希值、指针等。
  2. 并发控制
    • CAS操作:大部分操作通过CAS(compareAndSwap)无锁化完成。
    • 锁粒度:仅在哈希冲突时锁单个桶(synchronized)。
  3. 扩容机制
    • 扩容时分段进行,新旧表交替迁移数据,避免全局锁。
  4. 性能优化
    • 链表长度超过8转为红黑树,降低查找时间。
    • 读操作无需锁,写操作通过CAS和局部锁实现。

10. BlockingQueue的take()和poll()有什么区别?

答案:

方法行为
take()阻塞等待,直到有元素可用或被中断。
poll()非阻塞,若队列为空立即返回null(或指定超时时间后返回)。

11. 如何选择线程安全的集合类?

答案:

  • 读多写少CopyOnWriteArrayListConcurrentHashMap
  • 频繁写操作ConcurrentHashMap(哈希表)或ConcurrentSkipListMap(有序)。
  • 队列需求:根据是否阻塞选择BlockingQueueConcurrentLinkedQueue
  • 迭代安全:优先使用fail-safe容器(如CopyOnWriteArrayList)。

12. 为什么Vector是遗留类?如何替代?

答案:

  • Vector的问题
    • 全局synchronized锁,性能低。
    • 扩容为双倍容量,内存浪费。
  • 替代方案
    • 线程安全CopyOnWriteArrayList(读多写少)或ConcurrentLinkedQueue
    • 非线程安全ArrayList(手动加锁)。

总结

  • 核心思想:JUC容器通过减少锁粒度无锁化操作(CAS)、写时复制等技术,在保证线程安全的同时提升性能。
  • 设计模式
    • 分段锁(旧版ConcurrentHashMap)。
    • 快照迭代(CopyOnWrite)。
    • 阻塞队列(生产者-消费者模式)。
  • 高频考点:ConcurrentHashMap的实现、CopyOnWrite的适用场景、BlockingQueue的类型选择。

JUC 辅助类 CountDownLatch / CyclicBarrier / Semophore

CountDownLatchDemo(倒计时)

package com.qxy.practice.concurrent;import java.util.concurrent.CountDownLatch;/*** @author : 戚欣扬* @Description :*/
public class CountDownLatchDemo {public static void main(String[] args) {CountDownLatch clock = new CountDownLatch(3);for (int i = 3; i >0; i--) {int finalI = i;new Thread(()->{System.out.println("世界即将崩坏,倒计时 :" + finalI);//事实上,这个println顺序应该是随机的clock.countDown();},String.valueOf(i)).start();}try {clock.await();} catch (InterruptedException e) {throw new RuntimeException(e);}System.out.println("天国降临!!!");}
}

CyclicBarrierDemo(收集器)

package com.qxy.practice.concurrent;import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;/*** @author : 戚欣扬* @Description :*/
public class CyclicBarrierDemo {public static void main(String[] args) {CyclicBarrier collect = new CyclicBarrier(7,()->{System.out.println("召唤神龙!超级赛亚人之神!!!");});for (int i = 1; i <8; i++) {int finalI = i;new Thread(()->{System.out.println("已经收集龙珠 :" + finalI);try {collect.await();} catch (InterruptedException e) {throw new RuntimeException(e);} catch (BrokenBarrierException e) {throw new RuntimeException(e);}},String.valueOf(i)).start();}}
}

SemaphoreDemo (信号量)可以代替锁

package com.qxy.practice.concurrent;import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;/*** @author : 戚欣扬* @Description :*/
public class SemaphoreDemo {Semaphore semaphore = new Semaphore(1);public void stopCar(){try {semaphore.acquire();} catch (InterruptedException e) {throw new RuntimeException(e);}System.out.println(Thread.currentThread().getName()+" 抢到了车位 " );try {TimeUnit.SECONDS.sleep(2);} catch (InterruptedException e) {throw new RuntimeException(e);}System.out.println(Thread.currentThread().getName()+" 离开了商场" );semaphore.release();}public static void main(String[] args) {SemaphoreDemo semaphoreDemo = new SemaphoreDemo();for (int i = 0; i < 5; i++) {new Thread(()->{semaphoreDemo.stopCar();},String.valueOf(i)).start();}}
}

以下是关于 JUC辅助类 CountDownLatch、CyclicBarrier、Semaphore 的常用方法、使用场景及常见面试题的整理:


CountDownLatch

常用方法

方法说明
countDown()将计数器减 1,当计数器为 0 时,所有等待的线程被唤醒。
await()阻塞当前线程,直到计数器为 0。
await(long timeout, TimeUnit unit)在指定时间内等待计数器为 0,超时返回 false
getCount()返回当前计数器的值。

使用场景

  1. 等待多个线程完成任务

    • 主线程等待所有子线程执行完毕后再继续(如启动服务时等待多个组件加载完成)。
    • 示例:多个线程并行下载文件,主线程等待所有下载完成后合并文件。
  2. 并行任务协调

    • 多个线程需要同时开始执行任务(如赛跑中的“发令枪”)。
    • 示例:初始化一个 CountDownLatch(1),多个线程在 await() 处等待,主线程调用 countDown() 后所有线程同时执行。
  3. 资源加载

    • 主线程依赖多个资源加载完成才能继续执行(如数据库连接、配置加载)。

常见面试题

  1. CountDownLatch 的计数器如何变化?是否可重置?

    • 计数器只能减少(通过 countDown()),初始值由构造函数指定。
    • 不可重置,一旦计数器为 0,后续调用 await() 会立即返回。
  2. CountDownLatch 和 CyclicBarrier 的区别?

    特性CountDownLatchCyclicBarrier
    计数器单次使用,不可重置可循环使用
    等待触发条件计数器为 0线程数达到阈值
    应用场景主线程等待多个线程完成多线程需要多次同步到达同一屏障
  3. CountDownLatch 如何实现并行任务的“同时开始”?

    • 初始化 CountDownLatch(1),所有线程在 await() 处等待。
    • 主线程调用 countDown() 后,所有线程同时解除阻塞,开始执行。
  4. CountDownLatch 的 await() 会被中断吗?

    • 会抛出 InterruptedException,需在 catch 块中处理。

CyclicBarrier

常用方法

方法说明
await()阻塞当前线程,直到到达屏障的线程数等于阈值(parties)。
await(long timeout, TimeUnit unit)在指定时间内等待,超时返回 BrokenBarrierException
getNumberWaiting()返回正在等待的线程数。
isBroken()判断屏障是否处于破损状态(有线程中断或异常)。

使用场景

  1. 多线程协作同步

    • 多个线程需要在某个点汇合后再继续执行(如分布式计算的阶段同步)。
    • 示例:多个线程分别处理数据后,到达屏障汇总结果。
  2. 循环使用场景

    • 需要多次重置的同步点(如模拟比赛的多轮竞赛)。
  3. 分阶段任务处理

    • 任务需要分阶段执行,每个阶段需所有线程完成后再进入下一阶段。

常见面试题

  1. CyclicBarrier 的 await() 如何触发?

    • 当调用 await() 的线程数等于构造时指定的 parties 值时触发,所有线程被释放。
  2. CyclicBarrier 的屏障如何复用?

    • 触发后自动重置,可多次使用。除非屏障被破坏(broken 标志为 true),否则可循环使用。
  3. CyclicBarrier 和 CountDownLatch 的核心区别?

    • CountDownLatch:单向计数,不可重置,主线程等待其他线程完成。
    • CyclicBarrier:双向同步,可循环使用,所有线程需到达屏障后共同继续。
  4. 如何通过 CyclicBarrier 执行屏障到达后的操作?

    • 使用带 Runnable 的构造函数 CyclicBarrier(int parties, Runnable barrierAction),当线程数达到阈值时,会执行 barrierAction

Semaphore

常用方法

方法说明
acquire()获取一个许可证,若无可用许可证则阻塞。
acquire(int permits)获取指定数量的许可证。
release()释放一个许可证。
release(int permits)释放指定数量的许可证。
tryAcquire()尝试获取一个许可证,失败立即返回 false
tryAcquire(long timeout, TimeUnit unit)在指定时间内尝试获取许可证。
availablePermits()返回当前可用的许可证数量。

使用场景

  1. 资源访问控制

    • 限制并发访问共享资源(如数据库连接池、线程池)。
    • 示例:控制同时访问某文件的线程数不超过 5 个。
  2. 流量控制

    • 限流(如 API 请求限流,每秒最多 100 个请求)。
  3. 多线程协作

    • 协调线程的执行顺序(如生产者-消费者模式中控制生产者速率)。

常见面试题

  1. Semaphore 的公平模式与非公平模式的区别?

    • 公平模式:按线程等待顺序分配许可证。
    • 非公平模式:允许插队,性能更高但可能引发饥饿。
  2. Semaphore 如何实现资源池?

    • 初始化 Semaphore(poolSize),每个线程需 acquire() 获取资源,使用后 release() 归还。
  3. Semaphore 和 ReentrantLock 的区别?

    • Semaphore:控制并发线程数量,支持多许可证。
    • ReentrantLock:互斥锁,控制单个资源的访问。
  4. 如何避免 Semaphore 的死锁?

    • 确保线程在获取许可证后最终释放(如在 finally 块中调用 release())。
  5. acquire()tryAcquire() 的区别?

    • acquire():阻塞等待直到获取许可证。
    • tryAcquire():非阻塞,立即返回是否成功。

总结

核心功能典型场景
CountDownLatch等待多个线程完成任务,单向计数。主线程等待所有子线程完成。
CyclicBarrier多线程在屏障处汇合,可循环使用。多阶段任务同步、分布式计算。
Semaphore控制并发线程数量,支持资源访问限流。资源池管理、流量控制、并发限制。

相关文章:

每日学习Java之一万个为什么(JUC)

文章目录 Git复习synchronized介绍基本概念特点 使用模板1. 同步方法格式特点 2. 同步代码块格式特点 常见面试题1. synchronized的实现原理&#xff1f;2. synchronized与ReentrantLock的区别&#xff1f;3. synchronized的缺点&#xff1f;4. 死锁的四个必要条件&#xff1f;…...

代码分享:python实现svg图片转换为png和gif

import cairosvg import imageio from PIL import Image import io import osdef svg_to_png(svg_path, png_path):try:cairosvg.svg2png(urlsvg_path, write_topng_path)print(f"成功将 {svg_path} 转换为 {png_path}")except Exception as e:print(f"转换为 P…...

前端热门面试题day1

内容回答较粗糙&#xff0c;如有疑问请自行搜索资料 什么是vue中的slot&#xff1f;它有什么作用 Vue中的Slot&#xff08;插槽&#xff09;就像给组件预先留的“内容停车位”&#xff0c;让父组件能把自定义内容“塞”到子组件的指定位置。它的主要作用是&#xff1a; 灵活定…...

DCAN,ECAN和MCAN的区别

DCAN、ECAN和MCAN的主要区别在于它们各自的管理范围和功能。‌ ‌DCAN&#xff08;动力CAN系统&#xff09;‌&#xff1a;DCAN主要负责协调电机控制单元&#xff08;MCU&#xff09;、电池管理系统&#xff08;BMS&#xff09;、直流电压变换器&#xff08;DC/DC&#xff09;和…...

基于Python爬虫的豆瓣电影信息爬取(可以根据选择电影编号得到需要的电影信息)

# 豆瓣电影信息爬虫(展示效果如下图所示:) 这是一个功能强大的豆瓣电影信息爬虫程序,可以获取豆瓣电影 Top 250 的详细信息。 ## 功能特点 - 自动爬取豆瓣电影 Top 250 的所有电影信息 - 支持分页获取,每页 25 部电影,共 10 页 - 获取每部电影的详细信息,包括: - 标题…...

Linux系统学习----概述与目录结构

linux 是一个开源、免费的操作系统&#xff0c;其稳定性、安全性、处理多并发已经得到业界的认可&#xff0c;目前很多企业级的项目 (c/c/php/python/java/go)都会部署到 Linux/unix 系统上。 一、虚拟机系统操作 1.网络连接的三种方式&#xff08;桥接模式、nat模式、主机模…...

软考资料分享

分享一些软考资料 16系统分析师-基础知识精讲夸克网盘分享1701系统分析师夸克网盘分享1804系统架构设计师夸克网盘分享19软考系统架构设计师2024年11月夸克网盘分享2006信息系统项目管理师夸克网盘分享21软考高级信息系统项目夸克网盘分享22系统分析师视频教程真题资料夸克网盘…...

什么是 GLTF/GLB? 3D 内容创建的基本数据格式说明,怎么下载GLB/GLTF格式模型

GLTF 概述 GLTF 是一种 3D 模型格式&#xff0c;广泛用于在 Web 上共享和显示 3D 内容。 它经过优化&#xff0c;可在 WebGL 中轻松加载&#xff0c;使用 WebGL 可以快速高效地渲染 3D 模型。 GLTF 是 Khronos Group 开发的开放标准之一&#xff0c;以 JSON 或二进制格式表示…...

湖南大学-操作系统实验四

HUNAN UNIVERSITY 操作系统实验报告 一、实验题目 实验四 中断、异常和陷阱指令是操作系统的基石&#xff0c;现代操作系统就是由中断驱动的。本实验和实验五的目的在于深刻理解中断的原理和机制&#xff0c;掌握CPU访问中断控制器的方法&#xff0c;掌握Arm体系结构的中断机…...

3.第三章:数据治理的战略价值

文章目录 3.1 数据治理与企业战略3.1.1 数据驱动的决策体系3.1.2 数据资产的价值挖掘3.1.3 风险防控与合规管理 3.2 数据治理的业务价值3.2.1 提升客户体验3.2.2 优化运营效率3.2.3 加速产品创新 3.3 数据治理的技术价值3.3.1 提升数据质量3.3.2 优化数据架构3.3.3 增强系统集成…...

[KVM] KVM挂起状态恢复失败与KVM存储池迁移

背景&#xff1a;发现KVM host上的几台虚拟机挂起了(paused)&#xff0c;但是并没有执行virsh suspend <vm_hostname>&#xff0c;且使用virsh resume <vm_hostname> 无法恢复。原因是这个几个虚拟机归属的存储池所在的磁盘满了。所以想把虚拟机迁移到磁盘空间富余…...

图文结合 - 光伏系统产品设计PRD文档 -(慧哥)慧知开源充电桩平台

光伏系统产品设计PRD文档 ‌版本号‌&#xff1a;1.0 ‌修订日期‌&#xff1a;2023年10月 ‌作者‌&#xff1a; 一、文档概述 1.1 背景与目标 ‌行业背景‌&#xff1a;全球光伏装机量年增长20%&#xff0c;数字化运维需求迫切‌用户痛点‌&#xff1a;现有系统存在数据延…...

linux-相关命令

一、Linux 详细介绍 1. 什么是 Linux&#xff1f; Linux 是一个开源的类 Unix 操作系统&#xff0c;其核心是 Linux 内核。它最早由 Linus Torvalds 在 1991 年发布&#xff0c;后来逐渐发展成各种发行版&#xff08;如 Ubuntu、CentOS、Debian、Arch 等&#xff09;。 2. L…...

Hive中Map和Reduce阶段的分工

在Hive查询执行过程中,Map和Reduce阶段有明确的分工,但实际情况要复杂一些。 基本分工原则 ​​Map阶段​​: 主要职责是读取输入数据并进行初步处理输出键值对形式的数据​​Reduce阶段​​: 接收Map阶段输出的键值对对相同键的值进行聚合/计算输出最终结果实际执行中的复…...

前端笔记-Vue router

学习目标 Vue Router路由管理1、路由配置2、嵌套路由3、路由守卫与权限控制 一、路由配置&#xff08;给网站做地图&#xff09; npm i vue-router ​作用​&#xff1a;告诉浏览器什么地址该显示什么页面 ​核心代码​&#xff1a; // 创建路由并暴露出去// 第一步&#x…...

MySQL的日志--Redo Log【学习笔记】

MySQL的日志--Redo Log 知识来源&#xff1a; 《MySQL是怎样运行的》--- 小孩子4919 MySQL的事务四大特性之一就是持久性&#xff08;Durability&#xff09;。但是底层是如何实现的呢&#xff1f;这就需要我们的Redo Log&#xff08;重做日志&#xff09;闪亮登场了。它记录着…...

《系统分析师-第三阶段—总结(五)》

背景 采用三遍读书法进行阅读&#xff0c;此阶段是第三遍。 过程 第9章 总结 在这个过程中&#xff0c;对导图的规范越来越清楚&#xff0c;开始结构化&#xff0c;找关系&#xff0c;找联系。...

【LangChain4j】AI 第二弹:项目中接入 LangChain4j

普通接入方式 参考文档&#xff1a; Get Started https://docs.langchain4j.dev/get-started 1.添加依赖 <!-- 基于open-ai的langchain4j接口&#xff1a;ChatGPT、deepseek都是open-ai标准下的大模型 --> <dependency><groupId>dev.langchain4j</grou…...

测试基础笔记第十天

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 一、查询语句1.基本查询2.条件查询3.模糊查询4.范围查询5.判断空 二、其他复杂查询1.排序2.聚合函数3.分组4.分页查询 一、查询语句 1.基本查询 – 需求1: 准备商…...

代理模式:控制对象访问的中间层设计

代理模式&#xff1a;控制对象访问的中间层设计 一、模式核心&#xff1a;通过代理对象控制对目标对象的访问 在软件开发中&#xff0c;有时需要为对象添加一个 “代理” 来控制对它的访问&#xff0c;例如&#xff1a; 远程代理&#xff1a;访问远程对象时&#xff08;如 R…...

Python类和对象二(十一)

构造函数&#xff1a; 重写&#xff1a; 通过类名访问类里面的方法的做法&#xff0c;称为调用未绑定的父类方法&#xff0c;他有时候会产生钻石继承问题&#xff1a; 发现A重复初始化了两次&#xff0c;类c同事继承类B1和B2&#xff0c;类B1和B2又是继承类A的&#xff0c;当c…...

大模型在代码安全检测中的应用

大模型在代码安全检测领域的应用近年来取得显著进展&#xff0c;尤其在代码审查&#xff08;Code Review, CR&#xff09;场景中展现出高效性与准确性。以下是其核心优势、技术路径、挑战及实践案例的总结&#xff1a; 一、技术优势与核心能力 语义理解与上下文分析 大模型通过…...

Python实现图片浏览器

Python实现图片浏览器 支持浏览多种常见图片格式&#xff1a;JPG, JPEG, PNG, GIF, BMP, TIFF, WEBP 通过"打开文件夹"按钮选择任何包含图片的文件夹 灵活的排序选项&#xff1a; 按时间排序&#xff08;新→旧或旧→新&#xff09; 按文件名排序&#xff08;A→…...

网页设计规范:从布局到交互的全方位指南

网页设计规范看似繁杂&#xff0c;但其实都是为了给用户提供更好的体验。只有遵循这些规范&#xff0c;才能设计出既美观又实用的网页&#xff0c;让用户在浏览网页时感到舒适、愉悦。 一、用户体验至上 用户体验&#xff08;UX&#xff09;是网页设计的核心原则之一。设计师…...

哪些心电图表现无缘事业编体检呢?

根据《公务员录用体检通用标准》心血管系统条款及事业单位体检实施细则&#xff0c;心电图不合格主要涉及以下类型及处置方案&#xff1a; 一、心律失常类 早搏&#xff1a;包括房性早搏、室性早搏和交界性早搏。如果每分钟早搏次数较多&#xff08;如超过5次&#xff09;&…...

Java基础系列-HashMap源码解析1-BST树

文章目录 序二叉搜索树&#xff08;BST&#xff09;引入查找5插入9极端情况删除删除叶节点 10删除节点只有左子树或只有右子树删除节点既有左子树又有右子树为什么这么代替&#xff1f; 序 提到HashMap&#xff0c;就不得不提红黑树&#xff08;HashMap1.8之后&#xff09;&am…...

生物计算安全攻防战:从DNA存储破译到碳基芯片防御体系重构

随着碳基生物芯片突破冯诺依曼架构限制&#xff0c;DNA数据存储密度达到1EB/克量级&#xff0c;合成生物学与信息技术的融合正引发新一轮安全革命。本文深入解析碳基芯片逆向工程路径&#xff0c;揭示酶驱动DNA数据解码的技术突破&#xff0c;预警合成生物回路潜在的数据泄露风…...

【金仓数据库征文】从Oracle到KingbaseES的语法兼容与迁移

随着“信创”战略的深入推进&#xff0c;国产数据库逐渐成为IT系统的重要组成部分。KingbaseES&#xff08;金仓数据库&#xff09;凭借其良好的Oracle兼容性和日益完善的生态&#xff0c;成为金融、政务等核心行业国产化替代的重要选项。本文将从语法兼容性分析出发&#xff0…...

MATLAB 下载安装教程

## 一、下载MATLAB 1. 访问 MathWorks 官方网站&#xff1a;https://www.mathworks.com/ 2. 点击右上角的"登录"按钮 - 如果没有账号&#xff0c;需要先注册一个 MathWorks 账号 - 学生可以使用教育邮箱注册&#xff0c;获得教育版授权 3. 登录后&#xff0c;点击&…...

Android kotlin通知功能完整实现指南:从基础到高级功能

本文将详细介绍如何在Android应用中实现通知功能&#xff0c;包括基础通知、动作按钮和内联回复等高级特性。 一、基础通知实现 1. 基本通知发送方法 fun sendBasicNotification(context: Context, title: String, message: String) {// 1. 创建通知渠道(Android 8.0必需)va…...

Javase 基础入门 —— 04 继承

本系列为笔者学习Javase的课堂笔记&#xff0c;视频资源为B站黑马程序员出品的《黑马程序员JavaAI智能辅助编程全套视频教程&#xff0c;java零基础入门到大牛一套通关》&#xff0c;章节分布参考视频教程&#xff0c;为同样学习Javase系列课程的同学们提供参考。 01 什么是继…...

2.4/Q2,Charls最新文章解读

文章题目&#xff1a;The impact of hearing ability on depression among retired middle-aged and elderly individuals in China: the chain mediating role of self-rated health and life satisfaction DOI&#xff1a;10.1186/s41043-025-00791-9 中文标题&#xff1a;中…...

对流对象的理解

在c里&#xff0c;“流”可以理解为数据传输与操作的“介质”。 从输入输出角度来看&#xff0c;有输入流&#xff08;比如cin&#xff09;和输出流&#xff08;cout&#xff09;。对于输入流&#xff0c;数据通过它从外部设备&#xff08;例如键盘&#xff09;“流入”程序内…...

RBAC权限-笔记

1. RBAC模型简介 1.1. RBAC三要素 RBAC权限模型&#xff08;Role-Based Access Control&#xff1a;基于角色的访问控制&#xff09;有3个基础组成部分&#xff0c;分别是&#xff1a;用户、角色和权限。它们之间的关系如下图所示&#xff1a; 用户(User&#xff09;&#xf…...

stm32之GPIO函数详解和上机实验

目录 1.LED和蜂鸣器1.1 LED1.2 蜂鸣器 2.实验2.1 库函数&#xff1a;RCC和GPIO2.1.1 RCC函数1. RCC_AHBPeriphClockCmd2. RCC_APB2PeriphClockCmd3. RCC_APB1PeriphClockCmd 2.1.2 GPIO函数1. GPIO_DeInit2. GPIO_AFIODeInit3. GPIO_Init4. GPIO_StructInit5. GPIO_ReadInputDa…...

MsQuick编译和使用

MsQuick编译和使用 编译克隆代码使用cmakevs2022编译 使用示例 编译 克隆代码 git clone --recurse-submodules https://github.com/microsoft/msquic.git使用cmakevs2022编译 然后直接configure之后Generate然后打开vs工程编译即可生成动态库 使用示例 #include <s…...

01 ubuntu中wps桌面快捷键无法使用

文章目录 1. 问题描述&#xff1a;2. 解决方法&#xff1a;3. 结果展示4. 参考 1. 问题描述&#xff1a; 2. 解决方法&#xff1a; 添加权限 chmod 755 ./wps-office-prometheus.desktop 右键选择允许运行 3. 结果展示 修改前 修改后 4. 参考 参考1...

云原生后端架构:重塑后端开发的新范式

📝个人主页🌹:慌ZHANG-CSDN博客 🌹🌹期待您的关注 🌹🌹 一、引言:后端开发的新时代正在到来 传统的后端开发常常面临如下挑战:部署流程复杂、环境不一致、系统难以扩展、监控能力薄弱、上线流程缓慢。在企业数字化转型、业务快速迭代的大背景下,这些问题暴露得…...

Linux命令-tcpdump

tcpdump 是一个功能强大的网络数据包捕获和分析工具。以下是 tcpdump 命令的完整参数列表及说明&#xff1a; 参数 -a 将网络地址和广播地址转换为名字 tcpdump -a -i eth0-A 以 ASCII 格式打印所有分组&#xff0c;最小化链路层头部信息 tcpdump -A-b 在数据链路层上选择协议…...

分糖果——牛客

链接&#xff1a;登录—专业IT笔试面试备考平台_牛客网 来源&#xff1a;牛客网 题目描述 幼儿园准备了nnn包糖果&#xff0c;每包糖果里有111、222或333颗美味的糖果。现在需要将这些这些糖果平分给两个表现优异的小朋友以作奖励&#xff0c;为了公平公正&#xff0c;需要…...

L0、L2和L∞范数这三种范数的区别

目录 一、解释 ​​1. L0范数&#xff1a;数一数你有多少件行李​​ ​​2. L2范数&#xff1a;别把行李塞得太满​​ ​​3. L∞范数&#xff1a;别带任何超重的东西​​ ​​一句话总结​​ 二、作用 ​​1. L0范数的作用&#xff1a;做减法&#xff0c;只留最重要的​…...

[实战]zynq7000设备树自动导出GPIO

目录 zynq7000设备树自动导出GPIO添加设备树节点验证实验 结论 zynq7000设备树自动导出GPIO 今天无聊&#xff0c;掏出我82年产的microzed玩一玩。玩啥好呢&#xff0c;要不点个灯吧。于是&#xff0c;三下五除二&#xff0c;通过linux sys接口以及echo&#xff0c;很快就点亮…...

java六人打分

import java.util.Scanner;public class HelloWorld {public static void main(String[] args) {//打分平均分System.out.println("请输入六个评分");Scanner sc new Scanner(System.in);double[] score new double[6];for(int i0;i<score.length;i){System.ou…...

量子计算浪潮下的安全应对之法

量子计算凭借其强大的计算能力&#xff0c;被传言能够在极短时间内秒级破解传统计算机需耗时漫长岁月&#xff08;以万年算&#xff09;才能解开的密码&#xff0c;成为了近年来人们讨论的热点。这看似高深的科技名词在网络安全中又扮演着何种角色&#xff1f;我们应从当前人们…...

Windows Server 2022 常见问题解答

一、安装与部署 1.1 系统要求 硬件配置:最低需要 1.4 GHz 64 位处理器、512 MB 内存、32 GB 硬盘空间。但在实际生产环境中,为确保系统流畅运行,建议使用 2.0 GHz 以上处理器、8 GB 以上内存和 100 GB 以上硬盘。软件兼容性:与大多数基于 Windows 的企业级应用兼容,但在安…...

项目组合管理PPM

项目组合管理(Project Portfolio Management, PPM)详述 一、定义与核心目标 定义 项目组合管理是通过系统化的方法,对组织的所有项目和项目集进行识别、选择、优先级排序、资源配置和动态监控,以确保其与战略目标一致,并最大化投资回报(ROI)的管理过程。 核心目标 战略…...

自建开源远程协助服务RustDesk —— 筑梦之路

开源项目 # 服务端https://github.com/rustdesk/rustdesk-server.git# 客户端https://github.com/rustdesk/rustdesk.git 搭建服务端 需要使用的端口、协议 hbbs - RustDesk ID 注册服务器 hbbr - RustDesk 中继服务器默认情况下&#xff0c;hbbs 监听 21115(tcp) , 21…...

【android bluetooth 协议分析 11】【AVDTP详解 2】【avdtp 初始化阶段主要回调关系梳理】

在车机中 a2dp 通常情况下作为 sink. 本篇来帮助各位 朋友梳理一下&#xff0c;这部分的初始化流程。 我们着重梳理 native 层的逻辑&#xff0c; framework - java 侧一般比较容易看明白&#xff0c; 暂时不做梳理。 如果需要笨叔梳理的可以在博客评论。 出专门的章节来梳理。…...

C++回顾 day3

宏定义的数据是在预处理发生了替换 const类型的数据是在编译阶段发生的替换 命名空间 namespace 空间名{int a;void func_print(){printf("func_print");}struct Stu{int x;char *y;};//或者其他命名空间 } Space::x 20; cout << Space::x;using Space::x;…...

机器学习算法-分类决策树

分类决策树算法-python实现 数据集 具体方法是&#xff1a;从根结点开始&#xff0c;对结点计算所有可能的特征的信息增益&#xff0c;选择信息增益最大的特征作为结点的特征&#xff0c;由该特征的不同取值建立子节点&#xff1b;再对子结点递归地调用以上方法&#xff0c;构…...