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

android 线程池的管理工具类

封装了各种类型的线程池,方便直接使用

看下有哪些类型:

默认线程池,搜索模块专用线程池,网络请求专用线程池,U盘更新,同步SDK读写操作线程池,日志打印使用线程池

DEFALUT,SEARCH,NET_WORK,UDISK_DOWNLOAD,SDK_IO,LOG_PRINT

看下有哪些优先级级别

UI_TOP, UI_NORMAL, UI_LOW, DEFAULT, BG_TOP, BG_NORMAL, BG_LOW;

一:实现默认线程池

接下来先实现一个 默认实现 等待队列, 优先级比较,核心线程数等的线程池

开放 核心线程数,线程创建的工厂类(可以定制线程的优先级)供 外部定制(你也可以开放更多的参数)

public class TaskPriorityExecutor implements Executor {private static final int CORE_POOL_SIZE = 3;private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors();private static final int MAXIMUM_POOL_SIZE = CPU_COUNT * 2 + 1;private static final int KEEP_ALIVE = 30;private static final Comparator<Runnable> RUNNABLE_COMPARATOR = new Comparator<Runnable>() {@Overridepublic int compare(Runnable lhs, Runnable rhs) {if (lhs instanceof TaskPriorityRunnable && rhs instanceof TaskPriorityRunnable) {return ((TaskPriorityRunnable) lhs).priority.ordinal() - ((TaskPriorityRunnable) rhs).priority.ordinal();} else {return 0;}}};private final BlockingQueue<Runnable> mPoolWorkQueue =new PriorityBlockingQueue<Runnable>(MAXIMUM_POOL_SIZE, RUNNABLE_COMPARATOR);private final ThreadPoolExecutor mThreadPoolExecutor;public TaskPriorityExecutor() {this(CORE_POOL_SIZE, new TaskThreadFactory("Defalut"));}public TaskPriorityExecutor(int poolSize, ThreadFactory threadFactory) {mThreadPoolExecutor = new ThreadPoolExecutor(poolSize,MAXIMUM_POOL_SIZE,KEEP_ALIVE,TimeUnit.SECONDS,mPoolWorkQueue,threadFactory);}/*** 该构造器会创建单线程池执行任务*/public TaskPriorityExecutor(ThreadFactory threadFactory) {mThreadPoolExecutor = new ThreadPoolExecutor(1, 1,0L, TimeUnit.MILLISECONDS,new LinkedBlockingQueue<Runnable>(),threadFactory);}public int getPoolSize() {return mThreadPoolExecutor.getCorePoolSize();}public void setPoolSize(int poolSize) {if (poolSize > 0) {mThreadPoolExecutor.setCorePoolSize(poolSize);}
//    Executors.newCachedThreadPool()
//    Executors.newFixedThreadPool()
//    Executors.newScheduledThreadPool()
//    Executors.newSingleThreadExecutor()
//    Executors.newSingleThreadScheduledExecutor()}public ThreadPoolExecutor getThreadPoolExecutor() {return mThreadPoolExecutor;}/*** 线程池忙*/public boolean isBusy() {return mThreadPoolExecutor.getActiveCount() >= mThreadPoolExecutor.getCorePoolSize();}/*** 线程池超载*/public boolean isFull() {return mThreadPoolExecutor.getActiveCount() >= mThreadPoolExecutor.getCorePoolSize() * 2;}public boolean isShutdown(){return mThreadPoolExecutor.isShutdown();}@Overridepublic void execute(final Runnable r) {mThreadPoolExecutor.execute(r);}

二 根据接口定制业务场景的线程池接口

接下来我们就开始根据开放的接口来根据不同的业务需要来配置自己的线程池

final class TaskProxy< extends Task<ResultType> {private final Task<ResultType> task;private Executor executor;/*package*/ static final InternalHandler INTERNAL_HANDLER = new InternalHandler();static TaskPriorityExecutor sDefaultExecutor = new TaskPriorityExecutor();static TaskPriorityExecutor sSearchExecutor = null;static TaskPriorityExecutor sNetExecutor = null;static TaskPriorityExecutor sAE8EngineExecutor = null;static TaskPriorityExecutor sUDiskExecutor = null;static TaskPriorityExecutor sTtsInitializeExecutor = null;static TaskPriorityExecutor sSyncSdkIOHandleExecutor = null;static TaskPriorityExecutor sAdapterExecutor = null;static TaskPriorityExecutor sLoggerExecutor = null;static TaskPriorityExecutor sActivateLogExecutor = null;private ResultType result;private Throwable exception;private CancelledException cancelledException;/*package*/ TaskProxy(Task<ResultType> task) {if (task == null) {throw new IllegalArgumentException("task must not be null");}this.task = task;this.executor = task.getExecutor();if (this.executor == null) {this.executor = sDefaultExecutor;}}public static synchronized TaskPriorityExecutor getExecute(TaskExector type){if (TaskExector.DEFALUT.equals(type)) {if (sDefaultExecutor == null || sDefaultExecutor.isShutdown()){sDefaultExecutor = new TaskPriorityExecutor(4, new TaskThreadFactory("Default"));}return sDefaultExecutor;}else if(TaskExector.SEARCH.equals(type)) {if (sSearchExecutor == null || sSearchExecutor.isShutdown()){sSearchExecutor = new TaskPriorityExecutor(2, new TaskThreadFactory("Search"));}return sSearchExecutor;} else if (TaskExector.NET_WORK.equals(type)){if (sNetExecutor == null || sNetExecutor.isShutdown()){sNetExecutor = new TaskPriorityExecutor(1, new TaskThreadFactory("Net"));}return sNetExecutor;} else if (TaskExector.AE8_ENGINE.equals(type)){if (sAE8EngineExecutor == null || sAE8EngineExecutor.isShutdown()){sAE8EngineExecutor = new TaskPriorityExecutor(1, new TaskThreadFactory("AE8_Engine"));}return sAE8EngineExecutor;} else if (TaskExector.UDISK_DOWNLOAD.equals(type)){if (sUDiskExecutor == null || sUDiskExecutor.isShutdown()){sUDiskExecutor = new TaskPriorityExecutor(1, new TaskThreadFactory("UDISK_DOWNLOAD"));}return sUDiskExecutor;} else if (TaskExector.SYNC_SDK_IO.equals(type)) {if (sSyncSdkIOHandleExecutor == null || sSyncSdkIOHandleExecutor.isShutdown()) {sSyncSdkIOHandleExecutor = new TaskPriorityExecutor(1, new TaskThreadFactory("SYNC_SDK_IO_HANDLE"));}return sSyncSdkIOHandleExecutor;} else if (TaskExector.USER_BL.equals(type)) {if (sSyncSdkIOHandleExecutor == null || sSyncSdkIOHandleExecutor.isShutdown()) {sSyncSdkIOHandleExecutor = new TaskPriorityExecutor(1, new TaskThreadFactory("USER_BL"));}return sSyncSdkIOHandleExecutor;}else if (TaskExector.ADAPTER.equals(type)) {if (sAdapterExecutor == null || sAdapterExecutor.isShutdown()) {sAdapterExecutor = new TaskPriorityExecutor(1, new TaskThreadFactory("ADAPTER"));}return sAdapterExecutor;}
//    else if (TaskExector.LOGGER.equals(type)) {
//       if (sLoggerExecutor == null || sLoggerExecutor.isShutdown()) {
//          //日志问题出于时序考虑只能单线程模型进行执行
//          sLoggerExecutor = new TaskPriorityExecutor(new TaskThreadFactory("LOGGER"));
//       }
//       return sLoggerExecutor;
//    }else if (TaskExector.ACTIVATE_LOG.equals(type)) {if (sActivateLogExecutor == null || sActivateLogExecutor.isShutdown()) {//日志问题出于时序考虑只能单线程模型进行执行sActivateLogExecutor = new TaskPriorityExecutor(new TaskThreadFactory("ACTIVATE_LOG"));}return sActivateLogExecutor;}return sDefaultExecutor;}public synchronized static void shutDown(TaskExector type){Logger.d("byron", "[TaskProxy] shutDown:= "+ type);if (TaskExector.SEARCH.equals(type)) {if (sSearchExecutor != null){sSearchExecutor.getThreadPoolExecutor().shutdown();sSearchExecutor = null;}} else if (TaskExector.NET_WORK.equals(type)){if (sNetExecutor != null){sNetExecutor.getThreadPoolExecutor().shutdown();sNetExecutor = null;}} else if (TaskExector.AE8_ENGINE.equals(type)){if (sAE8EngineExecutor != null){sAE8EngineExecutor.getThreadPoolExecutor().shutdown();sAE8EngineExecutor = null;}} else if (TaskExector.UDISK_DOWNLOAD.equals(type)){if (sUDiskExecutor != null){sUDiskExecutor.getThreadPoolExecutor().shutdown();sUDiskExecutor = null;}} else if (TaskExector.SYNC_SDK_IO.equals(type)) {if (sSyncSdkIOHandleExecutor != null) {sSyncSdkIOHandleExecutor.getThreadPoolExecutor().shutdown();sSyncSdkIOHandleExecutor = null;}} else if (TaskExector.USER_BL.equals(type)) {if (sSyncSdkIOHandleExecutor != null) {sSyncSdkIOHandleExecutor.getThreadPoolExecutor().shutdown();sSyncSdkIOHandleExecutor = null;}}else if (TaskExector.ADAPTER.equals(type)) {if (sAdapterExecutor != null) {sAdapterExecutor.getThreadPoolExecutor().shutdown();sAdapterExecutor = null;}}
//    else if (TaskExector.LOGGER.equals(type)) {
//       if (sLoggerExecutor != null) {
//          sLoggerExecutor.getThreadPoolExecutor().shutdown();
//          sLoggerExecutor = null;
//       }
//    }else if (TaskExector.ACTIVATE_LOG.equals(type)) {if (sActivateLogExecutor != null) {sActivateLogExecutor.getThreadPoolExecutor().shutdown();sActivateLogExecutor = null;}}}public static void onDestory(){Logger.d("byron", "[TaskProxy] onDestory");if(INTERNAL_HANDLER != null){INTERNAL_HANDLER.removeCallbacksAndMessages(null);}}@Overrideprotected ResultType doBackground() throws Exception {this.setState(State.Waiting);TaskPriorityRunnable runnable = new TaskPriorityRunnable(task.getPriority(),null,new Runnable() {@Overridepublic void run() {try {Logger.d("proxy", "taskProxy 1");// trace_start runningTaskProxy.this.setState(State.Running);TaskProxy.this.onStart();result = task.doBackground();if (TaskProxy.this.state.get() == State.Cancelled) { // 没有在doBackground过程中取消成功Logger.d("proxy", "taskProxy 1 cancelled");throw new CancelledException("");}TaskProxy.this.setState(State.Finished);TaskProxy.this.onFinished(result);} catch (CancelledException cex) {Logger.d("proxy", "taskProxy e1 = {?}", cex);TaskProxy.this.setState(State.Cancelled);TaskProxy.this.onCancelled(cex);} catch (Throwable ex) {Logger.d("proxy", "taskProxy e2 = {?}", ex);TaskProxy.this.setState(State.Error);TaskProxy.this.onError(ex, false);}}});this.executor.execute(runnable);return null;}@Overrideprotected void onFinished(ResultType result) {INTERNAL_HANDLER.obtainMessage(MSG_WHAT_ON_FINISH, this).sendToTarget();}@Overrideprotected void onError(Throwable ex, boolean isCallbackError) {exception = ex;INTERNAL_HANDLER.obtainMessage(MSG_WHAT_ON_ERROR, this).sendToTarget();}@Overrideprotected void onStart() {INTERNAL_HANDLER.obtainMessage(MSG_WHAT_ON_START, this).sendToTarget();}@Overrideprotected void onUpdate(int flag, Object... args) {INTERNAL_HANDLER.obtainMessage(MSG_WHAT_ON_UPDATE, flag, 0, new ArgsObj(this, args)).sendToTarget();}@Overrideprotected void onCancelled(CancelledException cex) {cancelledException = cex;INTERNAL_HANDLER.obtainMessage(MSG_WHAT_ON_CANCEL, this).sendToTarget();}private void setState(State state) {this.state.set(state);this.task.state.set(state);}@Overridepublic TaskPriority getPriority() {return task.getPriority();}@Overridepublic Executor getExecutor() {return task.getExecutor();}// ########################### inner type #############################private static class ArgsObj {TaskProxy taskProxy;Object[] args;public ArgsObj(TaskProxy taskProxy, Object[] args) {this.taskProxy = taskProxy;this.args = args;}}private final static int MSG_WHAT_ON_START = 1;private final static int MSG_WHAT_ON_FINISH = 2;private final static int MSG_WHAT_ON_ERROR = 3;private final static int MSG_WHAT_ON_UPDATE = 4;private final static int MSG_WHAT_ON_CANCEL = 5;/*package*/ final static class InternalHandler extends Handler {private InternalHandler() {super(Looper.getMainLooper());}@SuppressWarnings("unchecked")@Overridepublic void handleMessage(Message msg) {if (msg.obj == null) {throw new IllegalArgumentException("msg must not be null");}TaskProxy taskProxy = null;Object[] args = null;if (msg.obj instanceof TaskProxy) {taskProxy = (TaskProxy) msg.obj;} else if (msg.obj instanceof ArgsObj) {ArgsObj argsObj = (ArgsObj) msg.obj;taskProxy = argsObj.taskProxy;args = argsObj.args;}if (taskProxy == null) {throw new RuntimeException("msg.obj not instanceof TaskProxy");}try {switch (msg.what) {case MSG_WHAT_ON_START: {taskProxy.task.onStart();break;}case MSG_WHAT_ON_FINISH: {taskProxy.task.onFinished(taskProxy.result);break;}case MSG_WHAT_ON_ERROR: {try {taskProxy.task.onError(taskProxy.exception, false);} catch (Throwable ignored) {}break;}case MSG_WHAT_ON_UPDATE: {taskProxy.task.onUpdate(msg.arg1, args);break;}case MSG_WHAT_ON_CANCEL: {taskProxy.task.onCancelled(taskProxy.cancelledException);break;}default: {break;}}} catch (Throwable ex) {taskProxy.setState(State.Error);if (msg.what != MSG_WHAT_ON_ERROR) {taskProxy.task.onError(ex, true);} else {ex.printStackTrace();}}}}
}
这里是包含优先级的线程对应的基类,可以通过线程工厂类 创建一个优先级的线程类
/*** 任务线程优先级*/
public class TaskPriorityRunnable implements Runnable {public final TaskPriority priority;private final Runnable runnable;private String name;private String oldThreadName;public TaskPriorityRunnable(TaskPriority priority, String name, Runnable runnable) {this.priority = priority == null ? TaskPriority.DEFAULT : priority;this.runnable = runnable;this.name = name == null ? null : new StringBuilder().append("Executor#").append(name).toString();}@Overridepublic final void run() {// run会进来多次,防止多次设置线程名称引起问题,故添加对name、oldThreadName判空判断if (!TextUtils.isEmpty(name) && TextUtils.isEmpty(oldThreadName)){oldThreadName = Thread.currentThread().getName();Thread.currentThread().setName(name);}this.runnable.run();// oldThreadName不为空时才进入设置线程名称if (!TextUtils.isEmpty(oldThreadName)){Thread.currentThread().setName(oldThreadName);oldThreadName = null;}}
}

三:其他相关类

这里面还有一些业务类的封装,这里就不再一一贴出来了(如有人需要,可以整个贴出来)

public abstract class Task<ResultType> {/*package*/ final AtomicReference<State> state = new AtomicReference<>(State.Null);/*package*/ TaskProxy taskProxy = null;protected abstract ResultType doBackground() throws Exception;protected abstract void onFinished(ResultType result);protected abstract void onError(Throwable ex, boolean isCallbackError);protected void onStart() {}protected void onUpdate(int flag, Object... args) {}protected void onCancelled(CancelledException cex) {}public final void update(int flag, Object... args) {if (taskProxy != null) {taskProxy.onUpdate(flag, args);}}public final void cancel() {this.state.set(State.Cancelled);if (taskProxy != null) {taskProxy.cancel();}}public final State getState() {return state.get();}public final boolean isStopped() {return this.state.get().value() > State.Running.value();}public TaskPriority getPriority() {return null;}public Executor getExecutor() {return null;}public static class CancelledException extends RuntimeException {public CancelledException(String detailMessage) {super(detailMessage);}}public static enum State {Null(0), Waiting(1), Running(2), Finished(3), Cancelled(4), Error(5);private final int value;private State(int value) {this.value = value;}public int value() {return value;}}
}

相关文章:

android 线程池的管理工具类

封装了各种类型的线程池&#xff0c;方便直接使用 看下有哪些类型&#xff1a; 默认线程池&#xff0c;搜索模块专用线程池&#xff0c;网络请求专用线程池&#xff0c;U盘更新&#xff0c;同步SDK读写操作线程池&#xff0c;日志打印使用线程池 DEFALUT&#xff0c;SEARCH&…...

编码风格之(5)GNU软件编码风格(3)

GNU软件编码标准风格(3) Author&#xff1a;Onceday Date: 2024年1月21日 漫漫长路&#xff0c;才刚刚开始… 本文主要翻译自《GNU编码标准》(GNU Coding Standards)一文。 参考文档: Linux kernel coding style — The Linux Kernel documentationGNU Coding Standard…...

8 种网络协议

什么是网络协议&#xff1f; 网络协议就是计算机之间沟通的语言&#xff0c;为了有效地交流&#xff0c;计算机之间需要一种共同的规则或协议&#xff0c;就像我们和老外沟通之前&#xff0c;要先商量好用哪种语言&#xff0c;要么大家都说中文&#xff0c;要么大家都说英语&a…...

Flash读取数据库中的数据

Flash读取数据库中的数据 要读取数据库的记录&#xff0c;首先需要建立一个数据库&#xff0c;并输入一些数据。数据库建立完毕后&#xff0c;由Flash向ASP提交请求&#xff0c;ASP根据请求对数据库进行操作后将结果返回给Flash&#xff0c;Flash以某种方式把结果显示出来。 …...

如何写出规范优雅的代码

编码规范是成为一个优质程序员的重要一课&#xff0c;它是编程的样式的模板。这篇文章将介绍12中编程规范及技巧&#xff0c;相信学习之后你的代码一定会提升一个档次。 首先我们要明确&#xff0c;为什么要遵循编码规范&#xff1f;遵循这样的约定有什么好处&#xff1f; 遵循…...

【数据结构】链表(单链表与双链表实现+原理+源码)

博主介绍&#xff1a;✌全网粉丝喜爱、前后端领域优质创作者、本质互联网精神、坚持优质作品共享、掘金/腾讯云/阿里云等平台优质作者、擅长前后端项目开发和毕业项目实战✌有需要可以联系作者我哦&#xff01; &#x1f345;附上相关C语言版源码讲解&#x1f345; &#x1f44…...

14027.ptp 控制流

文章目录 1 ptp 控制流1.1 控制流分层 1 ptp 控制流 1.1 控制流分层 大体分为4层&#xff1a;1 ptp4l层&#xff1a; 获取配置文件、创建时钟、poll监控文件描述符。2 clock时钟层&#xff1a;提供提供clock_poll、clock_create、clock_sync 等3 port 端口层&#xff1a;port…...

【昕宝爸爸小模块】深入浅出之为什么POI的SXSSFWorkbook占用内存更小

➡️博客首页 https://blog.csdn.net/Java_Yangxiaoyuan 欢迎优秀的你&#x1f44d;点赞、&#x1f5c2;️收藏、加❤️关注哦。 本文章CSDN首发&#xff0c;欢迎转载&#xff0c;要注明出处哦&#xff01; 先感谢优秀的你能认真的看完本文&…...

CentOS安装Flume

CentOS安装Flume 一、简介二、安装1、下载2、解压3、创建配置文件4、启动flume agent5、验证 一、简介 Flume is a distributed, reliable, and available service for efficiently collecting, aggregating, and moving large amounts of log data. It has a simple and flexi…...

Qt 多次绘图

使用Qt 的时候发现&#xff1a; 背景&#xff1a;自己定义一个类&#xff0c;把它和某个ui文件绑定。(类似 Qt creator 默认创建的工程&#xff09;问题&#xff1a;当鼠标在窗口内单击的时候会触发2次绘图。&#xff1f;难道不应该是一次吗&#xff1f; 于是开始了如下的测试…...

设计模式介绍

概念&#xff1a; 设计模式是一套被反复使用的、多数人知晓、经过分类编目的优秀代码设计经验的总结。特定环境下特定问题的处理方法。 1&#xff09;重用设计和代码 重用设计比重用代码更有意义&#xff0c;自动带来代码重用 2&#xff09;提高扩展性 大量使用面向接口编程&…...

linux 之 ln 命令

linux 之 ln 命令 在Linux中&#xff0c;ln 命令用于创建文件或目录的链接。它有两种主要类型的链接。 硬链接&#xff08;Hard Links&#xff09; 硬链接实际上是原始文件的另一个引用&#xff0c;指向同一个inode&#xff08;索引节点&#xff09;&#xff0c;这意味着它们共…...

【设计模式】张一鸣笔记:责任链接模式怎么用?

我将通过一个贴近现实的故事——请假审批流程&#xff0c;带你了解和掌握责任链模式。 什么是责任链模式&#xff1f; 责任链模式是一种行为设计模式&#xff0c;它让你可以避免将请求的发送者与接收者耦合在一起&#xff0c;让多个对象都有处理请求的机会将这个对象连成一条…...

Vulnhub-dc4

靶场下载 https://download.vulnhub.com/dc/DC-4.zip 信息收集 判断目标靶机的存活地址: # nmap -sT --min-rate 10000 -p- 192.168.1.91 -oN port.nmap Starting Nmap 7.94 ( https://nmap.org ) at 2024-01-21 16:36 CST Stats: 0:00:03 elapsed; 0 hosts completed (1 up…...

MySQL45道练习题

作业需要数据表SQL语句已给 1. 查询" 01 "课程比" 02 "课程成绩高的学生的信息及课程分数 select * from Student RIGHT JOIN (select t1.SId, class1, class2 from(select SId, score as class1 from sc where sc.CId 01)as t1, (select SId, score as …...

HTML5和CSS3的新特性

HTML5的新特性主要是针对于以前的不足&#xff0c;增加了一些新的标签、新的表单和新的表单属性等 1&#xff0c;HTML5新增的语义化标签 <header> 头部标签 <nav> 导航标签 <article> …...

【MySQL】表列数和行大小限制详解

目录 限制维度 列数量限制 表的最大行大小 单个列的存储要求 存储引擎的附加限制 功能键部分 行容量限制 MySQL表的内部实现 InnoDB表的最大行大小 超出InnoDB最大行大小的处理 不同存储格式的影响 限制示例 行大小限制示例 InnoDB下 MyISAM下 InnoDB变长情况示…...

算法基础学习|双指针算法

双指针算法 代码模板 for (int i 0, j 0; i < n; i ){while (j < i && check(i, j)) j ;// 具体问题的逻辑 } 常见问题分类&#xff1a;(1) 对于一个序列&#xff0c;用两个指针维护一段区间(2) 对于两个序列&#xff0c;维护某种次序&#xff0c;比如归并…...

4.远程登录服务

目录 1. 简介 1.1. 概念 1.2. 功能: 1.3. 分类 1.3.1. 文字接口: 1.3.2. 图形接口&#xff1a; 1.4. 文字接口连接服务器: 2. 连接加密技术简介 2.1. 密钥解析&#xff1a; 3. SSH工作过程&#xff1a; 3.1. 版本协商阶段 3.2. 密钥和算法协商阶段 3.3. 认证阶段(两…...

代码随想录算法训练营第二十九天| 491.递增子序列、46.全排列、47.全排列 II

491.递增子序列 题目链接&#xff1a;力扣&#xff08;LeetCode&#xff09;官网 - 全球极客挚爱的技术成长平台 解题思路&#xff1a;同层相同元素要跳过 java&#xff1a; class Solution {List<List<Integer>> resultnew ArrayList<>();List<Integ…...

如何在看板中有效管理突发紧急任务

在看板中有效管理突发紧急任务需要&#xff1a;设立专门的紧急任务通道、重新调整任务优先级、保持适度的WIP&#xff08;Work-in-Progress&#xff09;弹性、优化任务处理流程、提高团队应对突发情况的敏捷性。其中&#xff0c;设立专门的紧急任务通道尤为重要&#xff0c;这能…...

srs linux

下载编译运行 git clone https:///ossrs/srs.git ./configure --h265on make 编译完成后即可启动SRS # 启动 ./objs/srs -c conf/srs.conf # 查看日志 tail -n 30 -f ./objs/srs.log 开放端口 默认RTMP接收推流端口是1935&#xff0c;SRS管理页面端口是8080&#xff0c;可…...

Psychopy音频的使用

Psychopy音频的使用 本文主要解决以下问题&#xff1a; 指定音频引擎与设备&#xff1b;播放音频文件 本文所使用的环境&#xff1a; Python3.10 numpy2.2.6 psychopy2025.1.1 psychtoolbox3.0.19.14 一、音频配置 Psychopy文档链接为Sound - for audio playback — Psy…...

【HTML-16】深入理解HTML中的块元素与行内元素

HTML元素根据其显示特性可以分为两大类&#xff1a;块元素(Block-level Elements)和行内元素(Inline Elements)。理解这两者的区别对于构建良好的网页布局至关重要。本文将全面解析这两种元素的特性、区别以及实际应用场景。 1. 块元素(Block-level Elements) 1.1 基本特性 …...

前端开发面试题总结-JavaScript篇(一)

文章目录 JavaScript高频问答一、作用域与闭包1.什么是闭包&#xff08;Closure&#xff09;&#xff1f;闭包有什么应用场景和潜在问题&#xff1f;2.解释 JavaScript 的作用域链&#xff08;Scope Chain&#xff09; 二、原型与继承3.原型链是什么&#xff1f;如何实现继承&a…...

CRMEB 框架中 PHP 上传扩展开发:涵盖本地上传及阿里云 OSS、腾讯云 COS、七牛云

目前已有本地上传、阿里云OSS上传、腾讯云COS上传、七牛云上传扩展 扩展入口文件 文件目录 crmeb\services\upload\Upload.php namespace crmeb\services\upload;use crmeb\basic\BaseManager; use think\facade\Config;/*** Class Upload* package crmeb\services\upload* …...

【从零开始学习JVM | 第四篇】类加载器和双亲委派机制(高频面试题)

前言&#xff1a; 双亲委派机制对于面试这块来说非常重要&#xff0c;在实际开发中也是经常遇见需要打破双亲委派的需求&#xff0c;今天我们一起来探索一下什么是双亲委派机制&#xff0c;在此之前我们先介绍一下类的加载器。 目录 ​编辑 前言&#xff1a; 类加载器 1. …...

ZYNQ学习记录FPGA(一)ZYNQ简介

一、知识准备 1.一些术语,缩写和概念&#xff1a; 1&#xff09;ZYNQ全称&#xff1a;ZYNQ7000 All Pgrammable SoC 2&#xff09;SoC:system on chips(片上系统)&#xff0c;对比集成电路的SoB&#xff08;system on board&#xff09; 3&#xff09;ARM&#xff1a;处理器…...

鸿蒙HarmonyOS 5军旗小游戏实现指南

1. 项目概述 本军旗小游戏基于鸿蒙HarmonyOS 5开发&#xff0c;采用DevEco Studio实现&#xff0c;包含完整的游戏逻辑和UI界面。 2. 项目结构 /src/main/java/com/example/militarychess/├── MainAbilitySlice.java // 主界面├── GameView.java // 游戏核…...

若依项目部署--传统架构--未完待续

若依项目介绍 项目源码获取 #Git工具下载 dnf -y install git #若依项目获取 git clone https://gitee.com/y_project/RuoYi-Vue.git项目背景 随着企业信息化需求的增加&#xff0c;传统开发模式存在效率低&#xff0c;重复劳动多等问题。若依项目通过整合主流技术框架&…...