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 线程池的管理工具类
封装了各种类型的线程池,方便直接使用 看下有哪些类型: 默认线程池,搜索模块专用线程池,网络请求专用线程池,U盘更新,同步SDK读写操作线程池,日志打印使用线程池 DEFALUT,SEARCH&…...
编码风格之(5)GNU软件编码风格(3)
GNU软件编码标准风格(3) Author:Onceday Date: 2024年1月21日 漫漫长路,才刚刚开始… 本文主要翻译自《GNU编码标准》(GNU Coding Standards)一文。 参考文档: Linux kernel coding style — The Linux Kernel documentationGNU Coding Standard…...

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

Flash读取数据库中的数据
Flash读取数据库中的数据 要读取数据库的记录,首先需要建立一个数据库,并输入一些数据。数据库建立完毕后,由Flash向ASP提交请求,ASP根据请求对数据库进行操作后将结果返回给Flash,Flash以某种方式把结果显示出来。 …...
如何写出规范优雅的代码
编码规范是成为一个优质程序员的重要一课,它是编程的样式的模板。这篇文章将介绍12中编程规范及技巧,相信学习之后你的代码一定会提升一个档次。 首先我们要明确,为什么要遵循编码规范?遵循这样的约定有什么好处? 遵循…...

【数据结构】链表(单链表与双链表实现+原理+源码)
博主介绍:✌全网粉丝喜爱、前后端领域优质创作者、本质互联网精神、坚持优质作品共享、掘金/腾讯云/阿里云等平台优质作者、擅长前后端项目开发和毕业项目实战✌有需要可以联系作者我哦! 🍅附上相关C语言版源码讲解🍅 ὄ…...

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

【昕宝爸爸小模块】深入浅出之为什么POI的SXSSFWorkbook占用内存更小
➡️博客首页 https://blog.csdn.net/Java_Yangxiaoyuan 欢迎优秀的你👍点赞、🗂️收藏、加❤️关注哦。 本文章CSDN首发,欢迎转载,要注明出处哦! 先感谢优秀的你能认真的看完本文&…...

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 的时候发现: 背景:自己定义一个类,把它和某个ui文件绑定。(类似 Qt creator 默认创建的工程)问题:当鼠标在窗口内单击的时候会触发2次绘图。?难道不应该是一次吗? 于是开始了如下的测试…...

设计模式介绍
概念: 设计模式是一套被反复使用的、多数人知晓、经过分类编目的优秀代码设计经验的总结。特定环境下特定问题的处理方法。 1)重用设计和代码 重用设计比重用代码更有意义,自动带来代码重用 2)提高扩展性 大量使用面向接口编程&…...
linux 之 ln 命令
linux 之 ln 命令 在Linux中,ln 命令用于创建文件或目录的链接。它有两种主要类型的链接。 硬链接(Hard Links) 硬链接实际上是原始文件的另一个引用,指向同一个inode(索引节点),这意味着它们共…...

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

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的新特性主要是针对于以前的不足,增加了一些新的标签、新的表单和新的表单属性等 1,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 ;// 具体问题的逻辑 } 常见问题分类:(1) 对于一个序列,用两个指针维护一段区间(2) 对于两个序列,维护某种次序,比如归并…...

4.远程登录服务
目录 1. 简介 1.1. 概念 1.2. 功能: 1.3. 分类 1.3.1. 文字接口: 1.3.2. 图形接口: 1.4. 文字接口连接服务器: 2. 连接加密技术简介 2.1. 密钥解析: 3. SSH工作过程: 3.1. 版本协商阶段 3.2. 密钥和算法协商阶段 3.3. 认证阶段(两…...
代码随想录算法训练营第二十九天| 491.递增子序列、46.全排列、47.全排列 II
491.递增子序列 题目链接:力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台 解题思路:同层相同元素要跳过 java: class Solution {List<List<Integer>> resultnew ArrayList<>();List<Integ…...
设计模式和设计原则回顾
设计模式和设计原则回顾 23种设计模式是设计原则的完美体现,设计原则设计原则是设计模式的理论基石, 设计模式 在经典的设计模式分类中(如《设计模式:可复用面向对象软件的基础》一书中),总共有23种设计模式,分为三大类: 一、创建型模式(5种) 1. 单例模式(Sing…...

CTF show Web 红包题第六弹
提示 1.不是SQL注入 2.需要找关键源码 思路 进入页面发现是一个登录框,很难让人不联想到SQL注入,但提示都说了不是SQL注入,所以就不往这方面想了 先查看一下网页源码,发现一段JavaScript代码,有一个关键类ctfs…...
MVC 数据库
MVC 数据库 引言 在软件开发领域,Model-View-Controller(MVC)是一种流行的软件架构模式,它将应用程序分为三个核心组件:模型(Model)、视图(View)和控制器(Controller)。这种模式有助于提高代码的可维护性和可扩展性。本文将深入探讨MVC架构与数据库之间的关系,以…...
鱼香ros docker配置镜像报错:https://registry-1.docker.io/v2/
使用鱼香ros一件安装docker时的https://registry-1.docker.io/v2/问题 一键安装指令 wget http://fishros.com/install -O fishros && . fishros出现问题:docker pull 失败 网络不同,需要使用镜像源 按照如下步骤操作 sudo vi /etc/docker/dae…...
数据库分批入库
今天在工作中,遇到一个问题,就是分批查询的时候,由于批次过大导致出现了一些问题,一下是问题描述和解决方案: 示例: // 假设已有数据列表 dataList 和 PreparedStatement pstmt int batchSize 1000; // …...
【HTTP三个基础问题】
面试官您好!HTTP是超文本传输协议,是互联网上客户端和服务器之间传输超文本数据(比如文字、图片、音频、视频等)的核心协议,当前互联网应用最广泛的版本是HTTP1.1,它基于经典的C/S模型,也就是客…...

安宝特案例丨Vuzix AR智能眼镜集成专业软件,助力卢森堡医院药房转型,赢得辉瑞创新奖
在Vuzix M400 AR智能眼镜的助力下,卢森堡罗伯特舒曼医院(the Robert Schuman Hospitals, HRS)凭借在无菌制剂生产流程中引入增强现实技术(AR)创新项目,荣获了2024年6月7日由卢森堡医院药剂师协会࿰…...

使用Spring AI和MCP协议构建图片搜索服务
目录 使用Spring AI和MCP协议构建图片搜索服务 引言 技术栈概览 项目架构设计 架构图 服务端开发 1. 创建Spring Boot项目 2. 实现图片搜索工具 3. 配置传输模式 Stdio模式(本地调用) SSE模式(远程调用) 4. 注册工具提…...
纯 Java 项目(非 SpringBoot)集成 Mybatis-Plus 和 Mybatis-Plus-Join
纯 Java 项目(非 SpringBoot)集成 Mybatis-Plus 和 Mybatis-Plus-Join 1、依赖1.1、依赖版本1.2、pom.xml 2、代码2.1、SqlSession 构造器2.2、MybatisPlus代码生成器2.3、获取 config.yml 配置2.3.1、config.yml2.3.2、项目配置类 2.4、ftl 模板2.4.1、…...
虚拟电厂发展三大趋势:市场化、技术主导、车网互联
市场化:从政策驱动到多元盈利 政策全面赋能 2025年4月,国家发改委、能源局发布《关于加快推进虚拟电厂发展的指导意见》,首次明确虚拟电厂为“独立市场主体”,提出硬性目标:2027年全国调节能力≥2000万千瓦࿰…...