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

线程池的使用

  1. 为什么要使用线程池
    复习一下创建线程的几种方式:

继承Thread
实现Runnable
实现Callable

但是如果频繁的创建/销毁线程,就会造成资源浪费。这时候就需要将线程创建好之后存起来,以后要用取出来,用完后再放回去。

注意 :线程池并不是一种新的线程创建方法,它也是靠上面的方式创建线程的,只不过它能保存线程,实现线程资源的重复利用。

为什么要学线程池?效率高?牛逼?错,面试喜欢问。。。

  1. Executor
    创建之前首先要来认识一下它 :Executor。

Executor是线程池的根接口

在这里插入图片描述
3. ThreadPoolExecutor
3.1 七个参数
在创建线程池之前先来看看它的7个参数:

new ThreadPoolExecutor(int corePoolSize, int maximumPoolSize,long keepAliveTime,TimeUnit unit,BlockingQueue<Runnable> workQueue,ThreadFactory threadFactory,RejectedExecutionHandler handler)

在这里插入图片描述

corePoolSize

线程池核心线程数。

默认情况下核心线程会一直存活,即使处于闲置状态也不会受存keepAliveTime限制,除非将allowCoreThreadTimeOut设置为true。

maximumPoolSize

线程池所能容纳的最大线程数。超过maximumPoolSize的线程将被阻塞。

最大线程数maximumPoolSize不能小于corePoolSize

keepAliveTime

临时线程的闲置超时时间。超过这个时间临时线程就会被回收。

即 :核心线程被创建后一直存活,临时线程如果在闲置时间(keepAliveTime)内没有接到新任务会被销毁。

TimeUnit

keepAliveTime的时间单位,如TimeUnit.SECONDS。表示:keepAliveTime的单位是秒

workQueue

线程池中的任务队列。

没有获得线程资源的任务将会被放入workQueue,等待线程资源被释放。

如果核心线程数满了,新来的任务会首先放入任务队列

如果任务队列满了,会额外创建临时线程完成任务

如果线程数到达最大线程数时任务队列还是满的,多余的任务将由RejectedExecutionHandler的拒绝策略进行处理。

常用的有三种队列: SynchronousQueue,LinkedBlockingDeque,ArrayBlockingQueue。

threadFactory

提供创建新线程功能的线程工厂。通过threadFactory程序员可以自定义线程池中线程的创建方法。

ThreadFactory是一个接口,只有一个newThread方法:

Thread newThread(Runnable r);

rejectedExecutionHandler

拒绝策略,无法被线程池处理的任务的处理器。

一般是因为任务数超出了workQueue的容量。
3.2 任务队列
常用的三个队列 :

SynchronousQueue :无界缓冲等待队列。没有容量,是不储存元素的阻塞队列,会直接将任务交给线程,必须等队列中的添加元素表内消费后才能继续添加新的元素。即每次只能装一个任务,被线程拿走后才能继续接收任务。
使用SynchronousQueue阻塞队列一般要求最大线程数为无界,避免线程拒绝执行操作。

LinkedBlockingDeque:无界缓冲等待队列。当前执行的线程数量达到核心线程数时,剩余的元素会在阻塞队列里等待,即一次性拿走所有任务,有多少新来的也能装入,等待线程一个一个执行。(该队列默认大小为Integer.MAX_VALUE)

ArrayBlockingQueue :有界缓存等待队列。有容量,可以指定缓存队列的大小。只能装指定容量的任务,被线程拿走后才能继续装。

3.3 拒绝策略
常用的四个拒绝策略 :(它们都是ThreadPoolExecutor的内部类)

AbortPolicy :丢弃多余任务,抛出异常。默认策略。

DiscardPolicy :丢弃新任务,不抛出异常。假如新来5个任务想进入队列,丢弃他们。

DiscardOldestPolicy :丢弃旧任务,不抛出异常。假如新来5个任务想进入队列,将任务队列中的前五个丢弃,新来的进入队列。
CallerRunsPolicy :不抛弃任务,创建线程池的线程帮忙执行任务(例如main)。

  1. 创建线程池
    现在就用刚才所学的知识创建一个线程池并让它执行一些任务。

首先创建一个任务类,处理响应任务

public class Task implements Runnable{public String name;public Task(String name) {this.name = name;}@Overridepublic void run() {System.out.println("线程: " + name + " 执行任务");}
}

紧接着就可以创建线程池,这里我们创建一个 :

核心线程数为2,最大线程数为5,存活时间为10s,队列使用ArrayBlockingQueue,拒绝策略使用CallerRunsPolicy(创建线程池的线程帮忙执行多余任务)

让它处理20个任务 :

public class Main {public static void main(String[] args) {ThreadPoolExecutor executor = new ThreadPoolExecutor(2,5,10,TimeUnit.SECONDS, new ArrayBlockingQueue<Runnable>(5),new ThreadPoolExecutor.CallerRunsPolicy());for (int i = 0; i < 20; i++) {try {executor.execute(new Task(i + ""));} catch (Throwable e) {System.out.println("丢弃任务: " + (i));}}}
}

在这里插入图片描述

但是也可以注意到,任务已经执行结束,但是程序还未关闭,这就证明线程池并不会主动关闭,需要我们调用executor.shutdown()关闭并回收线程池。

public class Main {public static void main(String[] args) {ThreadPoolExecutor executor = new ThreadPoolExecutor(2,5,10,TimeUnit.SECONDS, new ArrayBlockingQueue<Runnable>(5),new ThreadPoolExecutor.CallerRunsPolicy());for (int i = 0; i < 20; i++) {try {executor.execute(new Task(i + ""));} catch (Throwable e) {System.out.println("丢弃任务: " + (i));}}executor.shutdown();}
}
  1. Executors
    Java提供了Executors工具类来创建线程池,注意它只是一个工具类,就像Strings是String的工具类、Objects是Object的工具类一样。Executors创建的线程池都是ExecutorService的实现类。

但是Executors这种方式创建的线程池是JDK提供的,有很多细节无法把控,所以阿里规范禁止使用Executors来创建线程池。
【强制】线程池不允许使用Executors去创建,而是通过ThreadPoolExecutor的方式,这样的处理方式让写的同学更加明确线程池的运行规则,规避资源耗尽的风险。
说明:
Executors返回的线程池对象的弊端如下:

1FixedThreadPoolSingleThreadPool:允许的请求队列长度为Integer.MAX_VALUE,可能会堆积大量的请求,从而导致OOM2CachedThreadPoolScheduledThreadPool:允许的创建线程数量为Integer.MAX_VALUE,可能会创建大量的线程,从而导致OOM

但是这里依旧要说一下这几种线程池,毕竟是官方封装的。而且后面自己写demo也可以直接用。

这几种线程池也是通过new ThreadPoolExecutor() 创建的,只不过其中的参数不同,所实现的功能也不同。

5.1 CachedThreadPool
Executors.newCachedThreadPool()

可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。

public static ExecutorService newCachedThreadPool() {return new ThreadPoolExecutor(0, Integer.MAX_VALUE,60L, TimeUnit.SECONDS,new SynchronousQueue<Runnable>());
}

核心线程数为0,任务队列只能装一个任务。也就是 只要来一个任务就创建一个线程处理它,来多少任务就创建多少线程。这些线程有60s的存活时间,如果接不到新任务就会被回收。

比起手动new线程,这个线程池可以实现线程复用、线程超时回收。但是可能创建太多线程造成资源浪费。

5.2 FixedThreadPool
Executors.newFixedThreadPool(int nThread)

定长线程池,可控制最大并发线程数量,超出的线程会在队列中等待。

public static ExecutorService newFixedThreadPool(int nThreads) {return new ThreadPoolExecutor(nThreads, nThreads,0L, TimeUnit.MILLISECONDS,new LinkedBlockingQueue<Runnable>());
}

核心线程数 = 最大线程数,核心线程数满了之后任务在队列中等待,队列满了之后直接执行拒绝策略,而不是创建临时线程,因为没有线程。

5.3 SingleThreadExecutor
Executors.newSingleThreadExecutor()

单例线程池 :只会用唯一的线程工作,保证所有任务按照FIFL、LIFO优先级执行。

public static ExecutorService newSingleThreadExecutor() {return new FinalizableDelegatedExecutorService(new ThreadPoolExecutor(1, 1,0L, TimeUnit.MILLISECONDS,new LinkedBlockingQueue<Runnable>()));
}

核心线程数 = 最大线程数 = 1,只有一个线程,所有任务都由它处理,任务队列LinkedBlockingQueue可以一次性装很多任务,这些任务排着队等待唯一的线程执行。

5.4 ScheduledThreadPoolExecutor
调度线程池,定长,支持定时及周期性任务执行,延迟任务执行。

public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {return new ScheduledThreadPoolExecutor(corePoolSize);
}
------
public ScheduledThreadPoolExecutor(int corePoolSize) {super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,new DelayedWorkQueue());
}

可以指定核心线程数,最大线程数是Integer.MAX_VALUE,可以实现延时执行、周期执行。

延时执行 :

delay 延时时间。

// 参数 : 任务 + 时间 + 时间单位
public <V> ScheduledFuture<V> schedule(Callable<V> callable,long delay, TimeUnit unit);

周期执行 :

initialDelay 第一次执行的延时时间
period 每一次执行的间隔时间。

// 参数 : 任务 + 时间 + 时间单位
public ScheduledFuture<?> scheduleAtFixedRate(Runnable command,long initialDelay,long period,TimeUnit unit);
  1. ExecutorService
    刚刚说了,Executors创建的都是ExecutorService的子类,那么现在来使用一下ExecutorService完成任务。

先来看看它拥有的方法:

在这里插入图片描述
shutdown :任务执行完毕后销毁线程池。
shutdownNow :立即销毁线程池。
invokeAll :执行所有任务。
submit :提交并执行任务。

public class TestExecutorService {public static void main(String[] args) {ExecutorService executorService = Executors.newCachedThreadPool();for (int i = 0; i < 10; i++) {executorService.submit(() -> {System.out.println(Thread.currentThread().getName() + " 执行");});}System.out.println(executorService.isShutdown());executorService.shutdown();System.out.println(executorService.isShutdown());}
}

结果:

pool-1-thread-2 执行
pool-1-thread-5 执行
pool-1-thread-6 执行
pool-1-thread-4 执行
pool-1-thread-1 执行
pool-1-thread-3 执行
false
pool-1-thread-8 执行
pool-1-thread-7 执行
pool-1-thread-9 执行
pool-1-thread-4 执行
true
——————

相关文章:

线程池的使用

为什么要使用线程池 复习一下创建线程的几种方式&#xff1a; 继承Thread 实现Runnable 实现Callable 但是如果频繁的创建/销毁线程&#xff0c;就会造成资源浪费。这时候就需要将线程创建好之后存起来&#xff0c;以后要用取出来&#xff0c;用完后再放回去。 注意 &#xff…...

字节码指令

目录 2.1 入门 2.2 javap 工具 2.3 图解方法执行流程 1&#xff09;原始 java 代码 2&#xff09;编译后的字节码文件 3&#xff09;常量池载入运行时常量池 4&#xff09;方法字节码载入方法区 5&#xff09;main 线程开始运行&#xff0c;分配栈帧内存 6&#xff09;…...

TLS/SSL证书彻底扫盲

证书格式 pem Privacy Enhanced Mail文本格式&#xff0c;以 -----BEGIN CERTIFICATE----- 开头&#xff0c;以-----END CERTIFICATE-----结尾 der 二进制格式&#xff0c;只保存证书&#xff0c;不保存私钥java和window服务器常见 pfx/p12 Predecessor of PKCS#12二进制格式&…...

WGCNA | 值得你深入学习的生信分析方法!~(网状分析-第五步-高级可视化)

1写在前面 前面我们用WGCNA分析完成了一系列的分析&#xff0c;聚类分割模块。&#x1f970; 随后进一步筛选&#xff0c;找到与我们感兴趣的表型或者临床特征相关的模块&#xff0c;而且进行了模块内部分析。&#x1f618; 再然后是对感兴趣模块进行功能注释&#xff0c;了解模…...

try catch finally执行顺序

try catch finally&#xff0c;try里有return&#xff0c;finally还执行么&#xff1f;答案&#xff1a; 执行&#xff0c;并且返回return时&#xff0c;finally的执行早于try。try-catch-finally的执行顺序无return当try中的t()没有抛出异常public static void main(String[] …...

2023年数学建模美赛D题(Prioritizing the UN Sustainability Goals)分析与编程

2023年数学建模美赛D题分析建模与编程 重要说明&#xff1a; 本文介绍2023年美赛题目&#xff0c;并进行简单分析&#xff1b;本文首先对 D题进行深入分析&#xff0c;其它题目分析详见专题讨论&#xff1b;本文及专题分析将在 2月17日每3小时更新一次&#xff0c;完全免费&am…...

35岁测试工程师被辞退,给你们一个忠告

一&#xff1a;前言&#xff1a;人生的十字路口静坐反思 入软件测试这一行至今已经10年多&#xff0c;承蒙领导们的照顾与重用&#xff0c;同事的支持与信任&#xff0c;我的职业发展算是相对较好&#xff0c;从入行到各类测试技术岗位&#xff0c;再到测试总监&#xff0c;再转…...

华为OD机试题 - 租车骑绿岛(JavaScript)

最近更新的博客 2023新华为OD机试题 - 斗地主(JavaScript)2023新华为OD机试题 - 箱子之形摆放(JavaScript)2023新华为OD机试题 - 考古学家(JavaScript)2023新华为OD机试题 - 相同数字的积木游戏 1(JavaScript)2023新华为OD机试题 - 最多等和不相交连续子序列(JavaScri…...

Linux下Python脚本的编写解析fio(minimal格式)(三)

在服务器测试(storage)过程中&#xff0c;会看到很多人写跑fio的脚本用minimal格式来解析&#xff0c;因为这种格式返回的结果对与脚本(shell,python)解析log非常方便.下面介绍一下这种方式下,用Python来解析log 1 一般客户会要求结果中出现一下参数的值&#xff1a; bandwidth…...

【实战场景二】如何设计一个分布式锁?

如何优雅的设计一个分布式锁&#xff1f;如何设计一个分布式锁&#xff1f;1、什么是分布式锁2、那么分布式锁&#xff0c;具备什么条件呢&#xff1f;3、设计分布式锁有哪些方式&#xff1f;3.1 利用redis实现分布式锁原理3.2 基于数据库做分布式锁3.3 基于zookeeper实现分布式…...

Java中ThreadLocal类详解

ThreadLocal从名字上我们看出&#xff0c;它叫做本地线程变量&#xff0c;每个线程都有各自的的变量&#xff0c;而不再是我们之前的两个线程共用同一个变量&#xff1b;以这个类创建的变量&#xff0c;在多个线程都用到这个变量时&#xff0c;可以为每一个线程创建一个变量副本…...

从一致性角度考虑推荐冷启动长尾推荐问题(一)

前言&#xff1a;目前中长尾推荐的方法有很多&#xff0c;主流的方法有几类比如:1)在没有项目ID嵌入的情况下提高推荐模型的鲁棒性&#xff0c;2)利用有限的交互数据提高学习效率&#xff0c;如使用元学习方法;3)利用物品侧面信息&#xff0c;便于物品ID嵌入的初始化&#xff0…...

电脑(Windows)常用快捷键

简述&#xff1a;实用的键盘快捷键是一个程序员的必备技能&#xff0c;下面给大家整理了一下常用的键盘快捷键&#xff1b; ⭐CtrlP 打开“打印机”对话框&#xff1b; ⭐CtrlW 关闭当前网页&#xff1b; ⭐CtrlF 查找&#xff08;网页内查找&#xff09;&#xff1b; ⭐…...

Java类加载器

1 类加载器 1.1 类加载 当程序要使用某个类时&#xff0c;如果该类还未被加载到内存中&#xff0c;则系统会通过类的加载&#xff0c;类的连接,类的初始化这三个步骤来对类进行初始化。如果不出现意外情况&#xff0c;JVM将会连续完成这三个步骤,所以有时也把这三个步骤统称为…...

信号完整性设计规则之单根信号失真最小化

本文内容从《信号完整性与电源完整性分析》整理而来&#xff0c;加入了自己的理解&#xff0c;如有错误&#xff0c;欢迎批评指正。 1. 通常采用所能容许的最长上升边。 上升边越短&#xff0c;带宽越大&#xff0c;信号完整性问题越严重。 2. 使用可控阻抗走线。 可控阻抗…...

Python3 数据结构

列表 Python中列表是可变的&#xff0c;这是它区别于字符串和元组的最重要的特点&#xff0c;一句话概括即&#xff1a;列表可以修改&#xff0c;而字符串和元组不能。 以下是 Python 中列表的方法&#xff1a; 方法 描述 list.append(x) 把一个元素添加到列表的结尾&#xf…...

Compose-Navigation带参传递

带参传递 目前 compose 还不支持传入对象作为参数&#xff01; 简单双参数 根目录下新建文件夹 entity&#xff0c;新建单例类 ContentType 作为数据类存储位置 新增数据类 DemoContent&#xff0c;这表示我们需要传入的两个参数&#xff0c;后面带问号判空 object ContentT…...

【函数栈帧的创建和销毁】 -- 神仙级别底层原理,你学会了吗?

文章目录1.函数的调用方式 2.函数在栈区上的动作 1.函数的调用方式 相信你对调用函数一点都不陌生&#xff0c;但是在调用函数的过程中&#xff0c;却存在着很多你无法见到的东西&#xff0c;这是底层信息&#xff0c;想要理解透彻&#xff0c;就得深入底层去观察。 本文以…...

Promise的使用及原理

此文章主要讲解核心思想和基本用法&#xff0c;想要了解更多细节全面的使用方式&#xff0c;请阅读官方API 这篇文章假定你具备最基本的异步编程知识&#xff0c;例如知道什么是回调&#xff0c;知道什么是链式调用&#xff0c;同时具备最基本的单词量&#xff0c;例如page、us…...

怎么拥有一个帅气的 CMD 命令窗口 ❓ - Windows

自从拥有这样一个炫酷的命令窗口&#xff0c;我都舍不得关掉它了 关于我为什么我要闲的去 “打扮” 一个命令窗口&#xff0c;这要从星期五下午的一场 摸鱼 &#x1f420; 开始&#xff0c;当时我要创建一个 vue ts vite 的项目练练手&#xff0c;为新项目开始做准备&#x…...

时隔多年再学习Vuex,什么?原来如此简单!

时隔多年再学习Vuex&#xff0c;什么&#xff1f;原来如此简单! start 写 Vue 写了好多年了&#xff0c;少不了和 Vuex 打交道。虽然使用它的次数非常频繁&#xff0c;但是潜意识里总觉得这东西很难&#xff0c;导致遇到与之相关的问题就容易慌张。时至今日&#xff0c;升级版…...

Linux笔记_gcc

Linux_gcc程序的翻译链接库make与makefile关于gcc的一些笔记。 程序的翻译 gcc/g是一个编译器。 预处理&#xff1a;头文件展开、条件编译、宏替换、去注释 编译&#xff1a;C语言汇编语言 汇编&#xff1a;汇编->可重定位目标二进制文件&#xff0c;不可以被执行&#xff0…...

2023美赛MCM A题 详细思路

2023美赛(MCM/ICM)如期开赛&#xff0c;为了尽早的帮大家确定选题。这里我们加急为大家编辑出A赛题详细思路&#xff0c;方便大家快速对A题目的难度有个大致的了解。同时&#xff0c;我们也给出了A题目简要的解题思路&#xff0c;以及该问题在实际解决中可能会遇到的难点。A题的…...

c#: NetTopologySuite凹凸多边形计算

环境&#xff1a; .net 6.0NetTopologySuite 2.5.0vs2022平面二维 一、夹角计算 1.1 计算向量与x轴正方向的夹角 方法: AngleUtility.Angle(Coordinate p) 下图上的t2即为p&#xff0c;之所以这么写是为了和AngleUtility.AngleBetweenOriented做比较 注意&#xff1a; 结果…...

NFT Insider #86:A16z 领投,YGG 获得 1380 万美元融资,The Sandbox与《北斗神拳》合作

引言&#xff1a;NFT Insider由NFT收藏组织WHALE Members、BeepCrypto联合出品&#xff0c;浓缩每周NFT新闻&#xff0c;为大家带来关于NFT最全面、最新鲜、最有价值的讯息。每期周报将从NFT市场数据&#xff0c;艺术新闻类&#xff0c;游戏新闻类&#xff0c;虚拟世界类&#…...

Sort_Algorithm

排序算法前言插入排序折半插入排序希尔排序冒泡排序快速排序选择排序堆排序归并排序前言 排序算法&#xff1a;将一堆数据元素按关键字递增或者递减的顺序&#xff0c;进行排序。 排序算法的评价指标&#xff1a;时间复杂度&#xff0c;空间复杂度&#xff0c;算法稳定性。 算…...

【初探人工智能】2、雏形开始长成

【初探人工智能】2、雏形开始长成【初探人工智能】2、雏形开始长成安装Flask封装Web接口雏形设置接收参数功能验证聊天写代码代码补全生成图片写在后面笔者初次接触人工智能领域&#xff0c;文章中错误的地方还望各位大佬指正&#xff01; 【初探人工智能】2、雏形开始长成 在…...

【LeetCode】剑指 Offer(2)

目录 写在前面&#xff1a; 题目&#xff1a; 题目的接口&#xff1a; 解题思路&#xff1a; 代码&#xff1a; 过啦&#xff01;&#xff01;&#xff01; 写在最后&#xff1a; 写在前面&#xff1a; 今天的每日一题好难&#xff0c;我不会dp啊啊啊啊啊啊。 所以&am…...

【JavaSE】Lambda、Stream(659~686)

659.每天一考 1.写出获取Class实例的三种常见方式 Class clazz1 String.class; Class clazz2 person.getClass(); //sout(person); //xxx.yyy.zzz.Person... Class clazz3 Class.forName(String classPath);//体现反射的动态性2.谈谈你对Class类的理解 Class实例对应着加载…...

有限差法(Finite Difference)求梯度和Hessian Matrix(海森矩阵)的python实现

数学参考 有限差方法求导&#xff0c;Finite Difference Approximations of Derivatives&#xff0c;是数值计算中常用的求导方法。数学上也比较简单易用。本文主要针对的是向量值函数&#xff0c;也就是f(x):Rn→Rf(x):\mathbb{R^n}\rightarrow \mathbb{R}f(x):Rn→R当然&…...

网站建设如果登录失败/网站广告收费标准

本文含 4818 字&#xff0c;6 图表截屏建议阅读 26 分钟本文是 Python 系列的特别篇的第十二篇特别篇 1 - PyEcharts TreeMap特别篇 2 - 面向对象编程特别篇 3 - 两大利「器」特别篇 4 - 装饰器特别篇 5 - Sklearn 0.22特别篇 6 - Jupyter Notebook特别篇 7 - 格式化字符串特别…...

如何在网站后台做超链接到文档/女教师遭网课入侵直播录屏曝光se

《三体》的第三体一个宇宙的时代&#xff08;不以年计&#xff09;&#xff0c;书中的故事主角永存&#xff0c;其他所有被时间洗涮着。结局&#xff1a;所有文明生存的空间被自己玩完&#xff0c;有文明向宇宙中所有 100 多万个文明发出了信息。但一切已成定局。故事小结&…...

凉山建设机械网站/百度服务中心人工客服电话

转自&#xff1a;https://zhuanlan.zhihu.com/p/24638007 &#xff08;详细&#xff0c;666耳东陈老师&#xff09; 字典 SVM&#xff08;Support Vector Machine&#xff09;&#xff0c;支持向量机 constraint&#xff0c;约束 阅读说明 希腊字母表见附录1&#xff08;数…...

做网站诈骗/目前小说网站排名

Purge死锁场景说明Purge死锁说明表中存在记录(unique key) 10&#xff0c;20&#xff0c;30&#xff0c;40 (且有 自增主键 )&#xff0c;现在删除记录 20 &#xff0c;并且已经 提交 了该事物。 purge 线程此时还 没有回收 该记录&#xff0c;且此时又 插入 新的记录 20 。---…...

广州网站建设o2o/新东方英语培训机构官网

说到文件大小&#xff0c;刚好常有人问我说MySQL是否有单个表的大小限制&#xff1f;限制多大呢&#xff1f;这里做一个简单的介绍吧。 在老版本的MySQL 3.22中&#xff0c;MySQL的单表限大小为4GB&#xff0c;当时的MySQL的存储引擎还是ISAM存储引擎。但是&#xff0c;当出现…...

靠谱的代运营公司有哪些/seo广告优化

原标题&#xff1a;【表扬信】一封来自福州大学至诚学院的表扬信自2020年初国科科技与福州大学至诚学院计算机工程系开展产学研合作以来&#xff0c;国科科技为该系2020年的教学工作提供了专业的教学服务&#xff0c;主要承担了入侵检测与安全扫描技术、网络安全架构、网络空间…...