Android学习总结之线程池篇

news2025/5/14 4:27:34

一、线程池参数调优实战真题

真题 1:直播 APP 弹幕加载线程池设计

题目描述:直播 APP 需要实时加载弹幕数据(网络请求,IO 密集型),同时渲染弹幕视图(UI 操作需切主线程),现有线程池导致弹幕卡顿,如何优化?

解题思路

  1. 参数调整
    • corePoolSize:对于 IO 密集型任务,设为 2 * CPU核心数,例如 8 核设备则 corePoolSize = 16
    • maximumPoolSize:适当增大到 3 * CPU核心数(即 24),以应对高并发场景。
    • workQueue:使用有界队列 ArrayBlockingQueue(100),防止内存溢出。
    • keepAliveTime:设为 60秒,允许非核心线程存活更久。
  2. 任务拆分
    • 网络请求任务提交至线程池。
    • 通过 Handler 将渲染任务切换到主线程。
int cpuCores = Runtime.getRuntime().availableProcessors();
// 创建线程池
ExecutorService executor = new ThreadPoolExecutor(
    2 * cpuCores, // 核心线程数,针对IO密集型任务设置为2 * CPU核心数
    3 * cpuCores, // 最大线程数,增大以应对高并发
    60L, // 非核心线程空闲时的存活时间
    TimeUnit.SECONDS, // 存活时间单位为秒
    new ArrayBlockingQueue<>(100), // 有界队列,容量为100
    new ThreadPoolExecutor.CallerRunsPolicy() // 拒绝策略,任务被调用线程执行
);

executor.submit(() -> {
    // 网络请求获取弹幕数据
    List<DanmuData> data = networkRequest(); 
    // 通过Handler切换到主线程渲染弹幕
    new Handler(Looper.getMainLooper()).post(() -> { 
        renderDanmu(data);
    });
});

回答话术
“针对弹幕加载的 IO 密集型任务,我会从三个层面优化。首先是 线程池参数调整

  1. corePoolSize 设置为 2 * CPU核心数(如 8 核设备设为 16),因为 IO 任务等待时线程不占用 CPU,更多核心线程能提升并发效率;
  2. maximumPoolSize 扩展到 3 * CPU核心数(即 24),应对弹幕突发高流量;
  3. 使用 ArrayBlockingQueue(100) 限制任务队列长度,防止内存溢出;
  4. keepAliveTime 设为 60 秒,允许非核心线程存活,减少频繁创建销毁开销。
    其次, 任务拆分:网络请求提交到线程池异步执行,通过 Handler 切换到主线程渲染弹幕,避免阻塞 UI。
    最后, 拒绝策略 选用 CallerRunsPolicy,将被拒绝的任务回退到调用线程(通常是主线程)。这样在高并发时,若主线程空闲可临时处理任务,同时提示开发者线程池已满载,需进一步优化参数或任务分配。”

面试追问

  • :为什么使用 CallerRunsPolicy 拒绝策略?
  • :该策略将被拒绝的任务交给调用者线程(通常是主线程)执行,避免任务丢弃。在弹幕高并发场景下,主线程空闲时可临时处理部分任务,同时提醒开发者线程池已满载,需优化参数或任务分配。
真题 2:图片编辑 APP 线程池优化

题目描述:图片编辑 APP 在批量处理图片时(解码、裁剪、压缩,均为 CPU 密集型),出现手机发热严重且处理速度慢的问题,如何优化?

优化方案

  1. 参数调整
    • corePoolSize:设为 CPU核心数 + 1(如 9)。
    • maximumPoolSize:与核心线程数保持一致(9),避免过多线程上下文切换。
    • keepAliveTime:设为 0,快速回收空闲线程。
  2. 性能监控
    • 使用 StrictMode 监控线程池使用情况。
    • 分析 CPU 使用率,动态调整任务数量。
int cpuCores = Runtime.getRuntime().availableProcessors();
// 创建线程池
ExecutorService executor = new ThreadPoolExecutor(
    cpuCores + 1, // 核心线程数,针对CPU密集型任务设置为CPU核心数 + 1
    cpuCores + 1, // 最大线程数,与核心线程数相同
    0L, // 非核心线程空闲时的存活时间设为0
    TimeUnit.MILLISECONDS, // 存活时间单位为毫秒
    new ArrayBlockingQueue<>(50), // 有界队列,容量为50
    new ThreadPoolExecutor.DiscardOldestPolicy() // 拒绝策略,丢弃队列中最老的任务
);

“对于 CPU 密集型的图片处理任务,优化需兼顾效率和资源消耗。
首先调整 线程池参数

  1. corePoolSize 设为 CPU核心数 + 1(如 8 核设备设为 9),充分利用 CPU 资源且减少上下文切换;
  2. maximumPoolSize 与核心线程数保持一致,避免创建多余线程加剧 CPU 负载;
  3. keepAliveTime 设为 0,让非核心线程立即回收,释放资源。
    其次, 性能监控 必不可少:通过 StrictMode 监控线程池使用,例如检测耗时任务或线程泄漏;结合 CPU 使用率动态调整任务数量,比如当 CPU 负载过高时,暂停部分任务或降低并发量。
    最后, 拒绝策略 采用 DiscardOldestPolicy,丢弃队列中等待最久的任务,保证新提交的紧急任务优先执行,避免任务堆积。”

二、任务依赖与同步实战真题

真题 3:多任务顺序执行

题目描述:在文件上传功能中,需要依次完成文件压缩、加密、上传三个步骤,如何确保任务按顺序执行?

解决方案:使用 CountDownLatch 来实现任务间的同步。

// 创建CountDownLatch,初始计数值为1
CountDownLatch latch1 = new CountDownLatch(1); 
// 创建另一个CountDownLatch,初始计数值为1
CountDownLatch latch2 = new CountDownLatch(1); 

// 提交压缩任务到线程池
executor.submit(() -> { 
    compressFile(); // 执行文件压缩操作
    latch1.countDown(); // 压缩任务完成,计数值减1
});

// 提交加密任务到线程池
executor.submit(() -> { 
    try {
        latch1.await(); // 等待压缩任务完成(计数值变为0)
        encryptFile(); // 执行文件加密操作
        latch2.countDown(); // 加密任务完成,计数值减1
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
});

// 提交上传任务到线程池
executor.submit(() -> { 
    try {
        latch2.await(); // 等待加密任务完成(计数值变为0)
        uploadFile(); // 执行文件上传操作
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
});

回答话术
“我会使用 CountDownLatch 实现任务同步。首先创建两个 CountDownLatch,初始计数值都为 1,分别控制压缩→加密、加密→上传的依赖关系。
提交任务时,压缩任务完成后调用 latch1.countDown() 释放信号;加密任务通过 latch1.await() 等待压缩完成,完成后再释放 latch2;最后上传任务等待 latch2 信号。这样通过计数器的增减,强制任务按顺序执行。
若任务失败,可在每个任务中捕获异常并记录,后续通过 CyclicBarrier 或自定义状态机实现重试逻辑。例如,若加密失败,回滚压缩结果并重新执行压缩和加密,确保流程可靠性。”

面试追问

  • :如果中间某个任务失败怎么办?
  • :可以在每个任务中捕获异常,记录失败信息。使用 CyclicBarrier 或自定义状态机来管理任务重试逻辑,确保整体流程的可靠性。
真题 4:任务优先级调度

题目描述:APP 中有高优先级的用户登录任务和低优先级的日志上报任务,如何确保高优先级任务优先执行?

解决方案:使用 PriorityBlockingQueue 来实现任务优先级调度。

// 定义一个实现Runnable和Comparable接口的任务类
class PrioritizedTask implements Runnable, Comparable<PrioritizedTask> { 
    private final int priority; // 任务优先级
    private final Runnable task; // 具体任务

    public PrioritizedTask(int priority, Runnable task) {
        this.priority = priority;
        this.task = task;
    }

    @Override
    public void run() {
        task.run(); // 执行具体任务
    }

    @Override
    public int compareTo(PrioritizedTask other) {
        return Integer.compare(other.priority, this.priority); // 比较任务优先级,倒序排列,高优先级在前
    }
}

// 创建线程池
ExecutorService executor = new ThreadPoolExecutor(
    5, // 核心线程数
    10, // 最大线程数
    30L, // 非核心线程空闲时的存活时间
    TimeUnit.SECONDS, // 存活时间单位为秒
    new PriorityBlockingQueue<>() // 优先级队列
);

// 提交高优先级的用户登录任务
executor.submit(new PrioritizedTask(1, () -> login())); 
// 提交低优先级的日志上报任务
executor.submit(new PrioritizedTask(2, () -> uploadLog())); 

回答话术
“使用 PriorityBlockingQueue 作为线程池的任务队列即可实现。自定义 PrioritizedTask 类,实现 Comparable 接口并重写 compareTo 方法,按优先级倒序排列(高优先级在前)。线程池从队列中获取任务时,始终优先执行优先级高的任务。
相比其他方案,PriorityBlockingQueue 更灵活:它基于堆结构实现,插入和获取任务的时间复杂度为 O (log n),效率较高;同时支持动态调整任务优先级。例如,若有新的高优先级登录任务加入,能立即插队执行,而低优先级的日志上报任务会暂停等待,确保核心业务的响应速度。” 

三、线程池与 Android 生命周期管理

真题 5:Activity 中的线程池内存泄漏

题目描述:在 Activity 中使用线程池执行网络请求,旋转屏幕后内存占用持续上升,如何解决?

解决方案

  1. 正确关闭线程池:在 Activity 的 onDestroy 方法中调用 executor.shutdown() 优雅关闭线程池,如需立即关闭可调用 executor.shutdownNow()
  2. 使用弱引用:避免 Activity 被任务强引用导致无法回收。
public class MainActivity extends AppCompatActivity {
    private ExecutorService executor;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // 创建固定大小的线程池
        executor = Executors.newFixedThreadPool(5); 
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        executor.shutdown(); // 优雅关闭线程池
        // 如需立即关闭线程池,可使用executor.shutdownNow();
    }
}

class MyTask implements Runnable {
    private WeakReference<Activity> activityRef; // 使用弱引用持有Activity

    public MyTask(Activity activity) {
        activityRef = new WeakReference<>(activity);
    }

    @Override
    public void run() {
        Activity activity = activityRef.get();
        if (activity != null) {
            // 任务逻辑
        }
    }
}

回答话术
“内存泄漏主要因线程池任务持有 Activity 强引用,或线程池未正确关闭。
首先,在 Activity 的 onDestroy 方法中调用 executor.shutdown() 优雅关闭线程池,它会等待已提交任务执行完毕后释放资源;若需立即中断任务,可使用 executor.shutdownNow()
其次,避免任务强引用 Activity:将任务类中的 Activity 引用改为 WeakReference,确保 Activity 被销毁时,任务不再阻止其回收。
最后,建议将线程池与 ViewModel 或 Service 绑定,而非直接关联 Activity。例如,使用 ViewModel 管理长期运行的任务,其生命周期与 Activity 分离,能有效防止因配置变更(如旋转屏幕)导致的内存泄漏问题。” 

四、WorkManager 替代方案场景

真题 6:后台任务调度

题目描述:APP 需要在设备充电且 Wi-Fi 连接时,自动备份数据到云端,如何实现?

解决方案:使用 WorkManager 结合 Constraints 来实现后台任务调度。

// 构建任务约束条件
Constraints constraints = new Constraints.Builder() 
   .setRequiresCharging(true) // 设置任务需要设备充电
   .setRequiredNetworkType(NetworkType.UNMETERED) // 设置任务需要连接非计量网络(如Wi-Fi)
   .build();

// 创建一次性工作请求,指定工作类和约束条件
OneTimeWorkRequest backupWorkRequest = new OneTimeWorkRequest.Builder(BackupWorker.class) 
   .setConstraints(constraints)
   .build();

// 将工作请求加入WorkManager队列
WorkManager.getInstance(context).enqueue(backupWorkRequest); 

回答话术
“使用 WorkManager 结合 Constraints 能轻松实现。通过 Constraints.Builder 设置条件:setRequiresCharging(true) 确保设备充电,setRequiredNetworkType(NetworkType.UNMETERED) 限制为 Wi-Fi 网络。然后创建 OneTimeWorkRequest,将备份任务类和约束条件传入,最后加入 WorkManager 队列。
WorkManager 相比 ThreadPoolExecutor 有显著优势:它支持任务重试、延迟执行、系统级调度,且与 Android 生命周期深度集成(如设备重启后任务自动恢复)。而 ThreadPoolExecutor 更专注于任务并发执行,需开发者手动处理调度逻辑和资源管理。因此,对于这种有条件触发、需长期可靠运行的后台任务,WorkManager 是更优选择。”

面试追问

  • :WorkManager 与 ThreadPoolExecutor 的区别?
  • :WorkManager 是 Android 提供的高级任务调度框架,支持任务重试、延迟执行、约束条件等,与系统生命周期紧密集成;而 ThreadPoolExecutor 更专注于任务的并发执行,需要开发者手动处理任务调度和资源管理。

额外具体场景设计:

一、如何设计线程池让 100 个任务最快完成?

1. 核心考点:线程池参数调优与 Android 场景适配

Android 面试中,线程池设计需结合设备 CPU 核心数、任务类型(CPU 密集型 / IO 密集型)以及内存管理要求,避免 OOM 和资源浪费。

关键参数设计:
  • 核心线程数(corePoolSize):
    • CPU 密集型任务:设为 CPU 核心数 + 1(充分利用 CPU,避免线程上下文切换损耗),可通过 Runtime.getRuntime().availableProcessors() 获取核心数。
    • IO 密集型任务:设为 2 * CPU 核心数(因 IO 等待时线程不占用 CPU,更多线程可提高并发效率)。
  • 最大线程数(maximumPoolSize):
    • 对于 CPU 密集型,通常与核心线程数一致(避免无意义的线程创建);
    • 对于 IO 密集型,可适当增大,但需结合任务队列容量避免内存溢出(Android 中建议使用有界队列 ArrayBlockingQueue,而非无界队列 LinkedBlockingQueue,防止内存暴涨)。
  • 任务队列(workQueue):
    • 有界队列(如 ArrayBlockingQueue:更安全,可控制并发量,避免 OOM(Android 内存受限,无界队列可能导致后台任务堆积)。
    • 优先级队列(PriorityBlockingQueue:若任务有优先级差异,可优先执行高优先级任务。
  • 线程存活时间(keepAliveTime):
    • 非核心线程空闲时的存活时间,IO 密集型任务可设稍长(如 30s),CPU 密集型可设 0(快速回收空闲线程)。
Android 禁用默认线程池(高频考点):

避免使用 Executors.newFixedThreadPool()(无界队列导致 OOM)或 newCachedThreadPool()(最大线程数无限),必须手动创建 ThreadPoolExecutor,示例:

int cpuCores = Runtime.getRuntime().availableProcessors();
ExecutorService executor = new ThreadPoolExecutor(
    cpuCores + 1,          // corePoolSize(CPU 密集型)
    2 * cpuCores,         // maximumPoolSize(IO 密集型可增大)
    30L, TimeUnit.SECONDS,// keepAliveTime
    new ArrayBlockingQueue<>(100), // 有界队列,容量根据任务量调整
    new ThreadPoolExecutor.CallerRunsPolicy() // 拒绝策略:任务被调用线程执行,避免丢弃
);
性能优化点:
  • 任务轻量化: 避免在任务中执行耗时 UI 操作(需通过 Handler/runOnUiThread 切换主线程)。
  • 复用线程: 线程池复用线程避免频繁创建销毁开销,比 new Thread() 更高效。

二、如何确保前 99 个任务完成后再执行第 100 个任务?

1. 核心考点:同步机制选择(CountDownLatch 或 Future)

Android 面试中,需区分 任务依赖关系 和 线程间同步,常用方案:

方案一:CountDownLatch(最简洁方案)
  • 原理:通过计数器(初始值 99)阻塞第 100 个任务,前 99 个任务完成时调用 countDown(),计数器归零后第 100 个任务继续执行。
  • Android 注意点
    • 第 100 个任务需在后台线程执行 latch.await(),避免阻塞主线程(否则触发 ANR)。
    • 任务中避免持有 Activity 强引用,防止内存泄漏(可使用弱引用或静态内部类)。
  • 代码示例:
// 初始化 CountDownLatch(计数器 99)
private final CountDownLatch latch = new CountDownLatch(99);

// 提交前 99 个任务
for (int i = 0; i < 99; i++) {
    executor.submit(() -> {
        // 执行任务...
        latch.countDown(); // 任务完成,计数器减一
    });
}

// 提交第 100 个任务(依赖前 99 个)
executor.submit(() -> {
    try {
        latch.await(); // 阻塞直到计数器归零
        // 执行第 100 个任务...
    } catch (InterruptedException e) {
        Thread.currentThread().interrupt(); // 恢复中断状态
    }
});
方案二:Future 批量获取结果(适合任务有返回值场景)
  • 原理:将前 99 个任务的 Future 存入列表,通过 Future.allOf() 等待所有任务完成,再执行第 100 个任务。
  • 优势:可处理任务返回值,支持异常处理(如 Future.get() 抛 ExecutionException)。
  • 代码示例:
List<Future<?>> futures = new ArrayList<>(99);
for (int i = 0; i < 99; i++) {
    futures.add(executor.submit(() -> { /* 任务逻辑 */ }));
}

// 提交第 100 个任务,等待前 99 个完成
executor.submit(() -> {
    try {
        Future.allOf(futures.toArray(new Future[0])).get(); // 阻塞直到所有完成
        // 执行第 100 个任务...
    } catch (InterruptedException | ExecutionException e) {
        // 处理异常
    }
});
方案对比(面试官可能追问):
方案优点缺点适用场景
CountDownLatch轻量、无返回值需求仅支持单向等待纯任务依赖场景
Future.allOf支持返回值、异常处理代码稍复杂任务有结果校验场景

三、Android 面试加分项(必答点)

  1. 线程池生命周期管理:

    • 在 Activity/Fragment 的 onDestroy() 中调用 executor.shutdown(),避免后台线程持有上下文导致内存泄漏。
    • 若需立即中断任务,调用 shutdownNow(),并处理 InterruptedException
  2. 避免 ANR:

    • 所有耗时任务(包括 latch.await()/Future.get())必须在后台线程执行,UI 操作通过 Handler 切换回主线程。
  3. 替代方案(高级考点):

    • 若任务需与 Android 生命周期绑定,可使用 WorkManager(适合后台任务调度,支持延迟、重试、约束条件)。
    • 对于轻量任务,可使用 ExecutorService + HandlerThread(自定义线程消息循环)。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2375102.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

OpenCV 中用于背景分割的一个类cv::bgsegm::BackgroundSubtractorLSBP

操作系统&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 编程语言&#xff1a;C11 算法描述 cv::bgsegm::BackgroundSubtractorLSBP 是 OpenCV 中用于背景分割的一个类&#xff0c;它基于局部样本二进制模式&#xff08;Local Sample Bina…

MacOS 上构建 gem5

MacOS 中只存在 python3&#xff0c;但是scons 只认 python&#xff0c;不在 系统中创建 软连接&#xff0c;一个是因为比较难操作&#xff1b;另一个是尽量不要更改系统。所以独立构件python 和scons&#xff1a; 1&#xff0c;安装python 下载源代码&#xff1a; Python S…

认识中间件-以及两个简单的示例

认识中间件-以及两个简单的示例 什么是中间件一个响应处理中间件老朋友 nest g如何使用为某个module引入全局引入编写逻辑一个日志中间件nest g mi 生成引入思考代码进度什么是中间件 官方文档 中间件是在路由处理程序之前调用的函数。中间件函数可以访问请求和响应对象,以及…

(五)毛子整洁架构(分布式日志/Redis缓存/OutBox Pattern)

文章目录 项目地址一、结构化日志1.1 使用Serilog1. 安装所需要的包2. 注册服务和配置3. 安装Seq服务 1.2 添加分布式id中间件1. 添加中间件2. 注册服务3. 修改Application的LoggingBehavior 二、Redis缓存2.1 添加缓存1. 创建接口ICaching接口2. 实现ICaching接口3. 注册Cachi…

大模型微调终极方案:LoRA、QLoRA原理详解与LLaMA-Factory、Xtuner实战对比

文章目录 一、微调概述1.1 微调步骤1.2 微调场景 二、微调方法2.1 三种方法2.2 方法对比2.3 关键结论 三、微调技术3.1 微调依据3.2 LoRA3.2.1 原理3.2.2 示例 3.3 QLoRA3.4 适用场景 四、微调框架4.1 LLaMA-Factory4.2 Xtuner4.3 对比 一、微调概述 微调&#xff08;Fine-tun…

云效 MCP Server:AI 驱动的研发协作新范式

作者&#xff1a;黄博文、李晔彬 云效 MCP Server 是什么&#xff1f; 云效 MCP&#xff08;Model Context Protocol&#xff09;是阿里云云效平台推出的模型上下文协议标准化接口系统&#xff0c;作为连接 AI 助手与 DevOps 平台的核心桥梁&#xff0c;通过模型上下文协议将…

Linux常见指令解析(三)

通配符 * *可以匹配任意名称的文件&#xff0c;如&#xff1a; ls * 列出当前目录下的所有非隐藏文件和目录&#xff0c;并展开目录内容 ls *.c 列出当前目录下以.c为结尾的文件 rm -rf * 删除所有非隐藏文件 alias指令 alias指令用于给命令取别名。如&#xff1a; 给ls …

HTTP学习

HTTP知识 01. 经典五层模型 应用层 为应用软件提供了很多服务&#xff0c;构建于协议之上。 传输层 数据的传输都是在这层定义的&#xff0c;数据过大分包&#xff0c;分片。 网络层 为数据在节点之间传输创建逻辑链路 数据链路层 通讯实体间建立数据链路连接 物理层 主要作用…

go语言实现IP归属地查询

效果: 实现代码main.go package mainimport ("encoding/json""fmt""io/ioutil""net/http""os" )type AreaData struct {Continent string json:"continent"Country string json:"country"ZipCode …

Android RxJava框架分析:它的执行流程是如何的?它的线程是如何切换的?如何自定义RxJava操作符?

目录 RxJava是什么&#xff1f;为什么使用。RxJava是如何使用的呢&#xff1f;RxJava如何和Retrofit一起使用。RxJava源码分析。 &#xff08;1&#xff09;他执行流程是如何的。&#xff08;2&#xff09;map&#xff08;3&#xff09;线程的切换。 如何自定义RxJava操作符…

MySQL及线程关于锁的面试题

目录 1.了解过 MySQL 死锁问题吗&#xff1f; 2.什么是线程死锁&#xff1f;死锁相关面试题 2.1 什么是死锁&#xff1a; 2.2 形成死锁的四个必要条件是什么&#xff1f; 2.3 如何避免线程死锁&#xff1f; 3. MySQL 怎么排查死锁问题&#xff1f; 4.Java线上死锁问题如…

【工作记录】crmeb后端项目打开、运行

1、下载代码 1&#xff09;安装git 不再详述 2&#xff09;git拉代码 项目地址如下&#xff0c;在vscode-分支中拉代码 # 克隆项目 git clone https://gitee.com/ZhongBangKeJi/crmeb_java/ 截图如下是已经成功拉下来 注意安装对应版本 2、maven配置 安装配置见&#x…

智能手表测试计划文档(软/硬件)

&#x1f4c4; 智能手表测试计划文档&#xff08;软/硬件&#xff09; 项目名称&#xff1a;Aurora Watch S1 文档编号&#xff1a;AW-S1-QA-TP-001 编制日期&#xff1a;2025-xx-xx 版本&#xff1a;V1.0 编写人&#xff1a;xxx&#xff08;测试主管&#xff09; 一、测试目标…

k8s监控方案实践(三):部署与配置Grafana可视化平台

k8s监控方案实践&#xff08;三&#xff09;&#xff1a;部署与配置Grafana可视化平台 文章目录 k8s监控方案实践&#xff08;三&#xff09;&#xff1a;部署与配置Grafana可视化平台一、Grafana简介1. 什么是Grafana&#xff1f;2. Grafana与Prometheus的关系3. Grafana应用场…

嵌入式系统架构验证工具:AADL Inspector v1.10 全新升级

软件架构建模与早期验证是嵌入式应用的关键环节。架构分析与设计语言&#xff08;AADL&#xff09;是专为应用软件及执行平台架构模型设计的语言&#xff0c;兼具文本与图形化的双重特性。AADL Inspector是一款轻量级的独立工具&#xff1a; 核心处理能力包括 √ 支持处理AA…

STM32-模电

目录 一、MOS管 二、二极管 三、IGBT 四、运算放大器 五、推挽、开漏、上拉电阻 一、MOS管 1. MOS简介 这里以nmos管为例&#xff0c;注意箭头方向。G门极/栅极&#xff0c;D漏极&#xff0c;S源极。 当给G通高电平时&#xff0c;灯泡点亮&#xff0c;给G通低电平时&a…

华为云Flexus+DeepSeek征文|从开通到应用:华为云DeepSeek-V3/R1商用服务深度体验

前言 本文章主要讲述在华为云ModelArts Studio上 开通DeepSeek-V3/R1商用服务的流程&#xff0c;以及开通过程中的经验分享和使用感受帮我更多开发者&#xff0c;在华为云平台快速完成 DeepSeek-V3/R1商用服务的开通以及使用入门注意&#xff1a;避免测试过程中出现部署失败等问…

鸿蒙NEXT开发动画案例5

1.创建空白项目 2.Page文件夹下面新建Spin.ets文件&#xff0c;代码如下&#xff1a; /*** TODO SpinKit动画组件 - Pulse 脉冲动画* author: CSDN—鸿蒙布道师* since: 2024/05/09*/ ComponentV2 export struct SpinFive {// 参数定义Require Param spinSize: number 48;Re…

ctfshow——web入门351~356

SSRF没有出网的部分 web入门351 $ch curl_init($url); 作用&#xff1a;初始化一个 cURL 会话&#xff0c;并设置目标 URL。解释&#xff1a; curl_init($url) 创建一个新的 cURL 资源&#xff0c;并将其与 $url 关联。这里的 $url 是用户提供的&#xff0c;因此目标地址完全…

【PostgreSQL数据分析实战:从数据清洗到可视化全流程】金融风控分析案例-10.1 风险数据清洗与特征工程

&#x1f449; 点击关注不迷路 &#x1f449; 点击关注不迷路 &#x1f449; 点击关注不迷路 文章大纲 PostgreSQL金融风控分析案例&#xff1a;风险数据清洗与特征工程实战一、案例背景&#xff1a;金融风控数据处理需求二、风险数据清洗实战&#xff08;一&#xff09;缺失值…