JavaWeb14-线程池
目录
1.传统线程的缺点
2.线程池的定义
3.线程池的优点
4.线程池的创建/使用(2类7种)
4.1.通过Executors(执行器)自动创建(6种)
①Executors.newFixedThreadPool:创建⼀个固定⼤⼩的线程池,可控制并发的线程数,超出的线程会在队列中等待。
--->PS:submit VS execute
--->PS:有返回值的线程池实现
--->PS:线程池中的线程工厂
②Executors.newCachedThreadPool:创建⼀个可缓存的线程池,若线程数超过处理所需,缓存⼀段时间后会回收,若线程数量不够,则新建线程,线程数随任务量而定(前提CPU性能好)。
③Executors.newSingleThreadExecutor:创建单个线程数的线程池,它可以保证先进先出的执⾏顺序。
--->PS:(常见面试题)newSingleThreadExecutor:创建单个线程数的线程池,那为何不直接使用线程?单线程线程池的意义?
④Executors.newScheduledThreadPool:创建⼀个可以执⾏延迟任务的线程池。
--->a.延迟执行一次
--->b.固定频率执行scheduleAtFixedRate
--->c.固定频率执行scheduleWithFixedDelay
--->PS:scheduleAtFixedRate VS scheduleWithFixedDelay
⑤Executors.newSingleThreadScheduledExecutor:创建⼀个单线程的可以执行延迟任务的线程池。
⑥Executors.newWorkStealingPool:根据当前服务器的CPU创建⼀个抢占式执⾏的线程池(任务执⾏顺序不确定)【JDK 1.8 添加】。
4.2.通过ThreadPoolExecutor手动创建(1种)
⑦ThreadPoolExecutor:重点掌握,最原始方式,推荐使用。
--->Executors自动创建线程池返回的线程池对象的弊端如下:
--->a.ThreadPoolExecutor 参数说明(包含 7 个参数可供设置,最少需要设置5个参数)
--->b.线程池执行流程
--->c.线程池拒绝策略(4【JDK提供】+1【自定义】)
5.线程池状态(5种)
①RUNNING:
②SHUTDOWN:
③STOP:
④TIDYING:
⑤TERMINATED:
a.各个状态的转换过程
b.shutdown VS shutdownNow
6.究竟选用哪种线程池?
1.传统线程的缺点
-
有任务时创建线程,没任务时结束线程:创建线程需要开辟本地线程栈、虚拟机栈、程序计数器等私有线程内存,消耗的时候也需要释放这些内存。频繁地创建和销毁需要⼀定的开销。
-
线程没有任务队列的任务管理功能:当任务数远远⼤于线程可以承载的数量之后,不能友好地进⾏任务拒绝。
2.线程池的定义
线程池(ThreadPool)是⼀种基于池化思想管理和使⽤线程的机制。
它是将多个线程预先存储在⼀个“池⼦”内,当有任务出现时可以避免重新创建和销毁线程所带来性能开销,只需要从“池⼦”内取出相应的线程执⾏对应的任务即可。
池化思想在计算机的应⽤也⽐较⼴泛:
内存池(Memory Pooling):预先申请内存,提升申请内存速度,减少内存碎⽚。
连接池(Connection Pooling):预先申请数据库连接,提升申请连接的速度,降低系统的开销。
实例池(Object Pooling):循环使⽤对象,减少资源在初始化和释放时的昂贵损耗。
3.线程池的优点
- 复用线程:避免线程重复创建和销毁的性能开销。
- 提⾼响应速度:任务到达时,⽆需等待线程创建即可⽴即执⾏。
- 控制线程数量:避免因线程创建过多而导致OOM(out of memory内存溢出)情况。
- 提供内存管理功能:可实现任务缓存和任务拒绝。
- 提供更多功能:比如定时任务,允许任务延期执⾏或定期执⾏。
同时阿⾥巴巴在其《Java开发⼿册》中也强制规定:线程资源必须通过线程池提供,不允许在应⽤中⾃⾏显式创建线程。
4.线程池的创建/使用(2类7种)
4.1.通过Executors(执行器)自动创建(6种)
①Executors.newFixedThreadPool:创建⼀个固定⼤⼩的线程池,可控制并发的线程数,超出的线程会在队列中等待。
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;/*** 创建一个固定大小的线程池*/
public class ThreadPoolDemo1 {public static void main(String[] args) {//1.创建了一个包含5个线程的线程池ExecutorService threadPool = Executors.newFixedThreadPool(5);//2.使用submit线程池执行任务一for (int i = 0; i < 5; i++) {//给线程池添加任务threadPool.submit(new Runnable() { //匿名内部类@Overridepublic void run() {System.out.println("线程名称:" + Thread.currentThread().getName());}});}//2.使用execute线程池执行任务二for (int i = 0; i < 10; i++) {//给线程池添加任务threadPool.execute(new Runnable() {@Overridepublic void run() {System.out.println("线程名称:" + Thread.currentThread().getName());}});}}
}
--->PS:submit VS execute
- submit:既支持有返回值,也支持无返回值。(推荐使用)
- execute:只支持无返回值。
--->PS:有返回值的线程池实现
import java.util.Random; import java.util.concurrent.*;/*** 有返回值的线程池*/ public class ThreadPoolDemo2 {public static void main(String[] args) throws ExecutionException, InterruptedException {ExecutorService threadPool = Executors.newFixedThreadPool(5);Future<Integer> result = threadPool.submit(new Callable<Integer>() {@Overridepublic Integer call() throws Exception{int num = new Random().nextInt(10);System.out.println("生成随机数:" + num);return num;}});System.out.println("得到线程池返回结果:" + result.get()); //会有阻塞,会等到拿到返回值之后再去执行后面的代码} }
上面代码是使用默认的线程工厂。
--->PS:线程池中的线程工厂
作用:为线程池提供线程的创建。
提供的功能:
- 设置线程池中的线程的命名规则。
- 设置线程的优先级。
- 设置线程的分组。
- 设置线程的类型(用户线程、守护/后台线程)。
import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.ThreadFactory; import static java.lang.Thread.MAX_PRIORITY;/***线程工厂示例演示*/ public class ThreadPoolDemo3 {public static void main(String[] args) {//创建线程工厂ThreadFactory factory = new ThreadFactory() {@Overridepublic Thread newThread(Runnable r) {//!!!一定要注意要把任务Runnable设置给新创建的线程Thread thread = new Thread(r);//设置线程的命名规则thread.setName("我的线程-" + r.hashCode());//设置线程的优先级thread.setPriority(MAX_PRIORITY);return thread;}};ExecutorService service = Executors.newFixedThreadPool(5,factory);for (int i = 0; i < 5; i++) {service.submit(() -> {//任务Thread thread = Thread.currentThread();System.out.println("线程池开始执行了:" + thread.getName() + ",线程优先级:" + thread.getPriority());});}} }
线程池里的线程永远处于存活状态,不会自动停止,除非调用线程池终止执行方法。
②Executors.newCachedThreadPool:创建⼀个可缓存的线程池,若线程数超过处理所需,缓存⼀段时间后会回收,若线程数量不够,则新建线程,线程数随任务量而定(前提CPU性能好)。
优点:更多任务数量产⽣相应的线程池。 当有突发的大量的任务时,建议使用此方式。
缺点:占⽤资源数量⽐较多。
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;/*** 带缓存的线程池*/
public class ThreadPoolDemo4 {public static void main(String[] args) {//创建线程池ExecutorService service = Executors.newCachedThreadPool();for (int i = 0; i < 1000; i++) {//任务数量总共有1000个,最终执行结果 线程数量大概是300多个//i必须定义一个参数,才能去使用,必须是一个确定的参数int finalI = i;service.submit(() -> {System.out.println("i:" + finalI + "|线程名称" + Thread.currentThread().getName());});}}
}
若不关闭,会一直执行下去。
③Executors.newSingleThreadExecutor:创建单个线程数的线程池,它可以保证先进先出的执⾏顺序。
--->PS:(常见面试题)newSingleThreadExecutor:创建单个线程数的线程池,那为何不直接使用线程?单线程线程池的意义?
- 复用线程。
- 单线程的线程池提供了任务队列和拒绝策略(当任务队列满了Integer.MAX_VALUE之后,新来的任务就会执行拒绝策略)。
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;public class ThreadPoolDemo7 {public static void main(String[] args) {ExecutorService service = Executors.newSingleThreadExecutor();for (int i = 0; i < 10; i++) {int finalI = i;service.submit(new Runnable() {@Overridepublic void run() {System.out.println("任务:" + finalI + "线程名:" + Thread.currentThread().getName());}});}}
}
④Executors.newScheduledThreadPool:创建⼀个可以执⾏延迟任务的线程池。
--->a.延迟执行一次
import java.time.LocalDateTime;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;/*** 创建执行定时任务的线程池*/
public class ThreadPoolDemo5 {public static void main(String[] args) {//创建线程池ScheduledExecutorService service = Executors.newScheduledThreadPool(5);System.out.println("添加任务的时间:" + LocalDateTime.now());//执行一次的定时任务scheduleTest(service);}/*** 执行一次的定时任务* @param service*/private static void scheduleTest(ScheduledExecutorService service) {//执行定时任务(延迟3秒执行)。这个延迟任务只能执行一次,不能继续执行。//延迟执行一次定时任务service.schedule(new Runnable() {@Overridepublic void run() {System.out.println("执行了任务:" + LocalDateTime.now());//参数1:执行的任务}},3, TimeUnit.SECONDS);//参数2:延迟多久进行执行; 参数3:是参数2的时间单位描述}
}
--->b.固定频率执行scheduleAtFixedRate
import java.time.LocalDateTime;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;/*** 创建执行定时任务的线程池*/
public class ThreadPoolDemo5 {public static void main(String[] args) {//创建线程池ScheduledExecutorService service = Executors.newScheduledThreadPool(5);System.out.println("添加任务的时间:" + LocalDateTime.now());//2s之后开始执行定时任务,定时任务每隔4s执行一次service.scheduleAtFixedRate(new Runnable() {@Overridepublic void run() {System.out.println("执行任务:" + LocalDateTime.now());}},2,4, TimeUnit.SECONDS);}
}
--->c.固定频率执行scheduleWithFixedDelay
import java.time.LocalDateTime;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;/*** 创建执行定时任务的线程池*/
public class ThreadPoolDemo5 {public static void main(String[] args) {//创建线程池ScheduledExecutorService service = Executors.newScheduledThreadPool(5);System.out.println("添加任务的时间:" + LocalDateTime.now());//2s之后开始执行定时任务,定时任务每隔4s执行一次service.scheduleWithFixedDelay(new Runnable() {@Overridepublic void run() {System.out.println("执行时间:" + LocalDateTime.now());}},2,4,TimeUnit.SECONDS);}
}
--->PS:scheduleAtFixedRate VS scheduleWithFixedDelay
①scheduleAtFixedRate 是以上⼀次任务的开始时间,作为下次定时任务的参考时间的(参考时间+延迟任务=任务执⾏)。
import java.time.LocalDateTime; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit;/*** 创建执行定时任务的线程池*/ public class ThreadPoolDemo5 {public static void main(String[] args) {//创建线程池ScheduledExecutorService service = Executors.newScheduledThreadPool(5);System.out.println("添加任务的时间:" + LocalDateTime.now());//2s之后开始执行定时任务,定时任务每隔4s执行一次service.scheduleAtFixedRate(new Runnable() {@Overridepublic void run() {System.out.println("执行任务:" + LocalDateTime.now());try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}},2,4, TimeUnit.SECONDS);} }
注意:
如果任务执⾏时间⼤于延迟任务设定的间隔时间,则会以任务执行时间为定时任务间隔周期来执行,即哪个值大就用哪个值作为定时任务间隔周期。
public class ThreadPoolDemo5 {public static void main(String[] args) {//创建线程池ScheduledExecutorService service = Executors.newScheduledThreadPool(5);System.out.println("添加任务的时间:" + LocalDateTime.now());//2s之后开始执行定时任务,定时任务每隔3s执行一次service.scheduleAtFixedRate(new Runnable() {@Overridepublic void run() {System.out.println("执行任务:" + LocalDateTime.now());try {Thread.sleep(4000);} catch (InterruptedException e) {e.printStackTrace();}}},2,3, TimeUnit.SECONDS);} }
②scheduleWithFixedDelay 是以上⼀次任务的结束时间,作为下次定时任务的参考时间的。
public class ThreadPoolDemo5 {public static void main(String[] args) {//创建线程池ScheduledExecutorService service = Executors.newScheduledThreadPool(5);System.out.println("添加任务的时间:" + LocalDateTime.now());//2s之后开始执行定时任务,定时任务每隔4s执行一次service.scheduleWithFixedDelay(new Runnable() {@Overridepublic void run() {System.out.println("执行时间:" + LocalDateTime.now());try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}},2,4,TimeUnit.SECONDS);} }
⑤Executors.newSingleThreadScheduledExecutor:创建⼀个单线程的可以执行延迟任务的线程池。
newSingleThreadScheduledExecutor是newScheduledThreadPool的单线程版本。
import java.time.LocalDateTime;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;public class ThreadPoolDemo6 {public static void main(String[] args) {//创建执行定时任务的单线程线程池ScheduledExecutorService service = Executors.newSingleThreadScheduledExecutor();System.out.println("添加任务的时间:" + LocalDateTime.now());service.schedule(new Runnable() {@Overridepublic void run() {System.out.println("执行任务:" + LocalDateTime.now());}},2, TimeUnit.SECONDS);}
}
⑥Executors.newWorkStealingPool:根据当前服务器的CPU创建⼀个抢占式执⾏的线程池(任务执⾏顺序不确定)【JDK 1.8 添加】。
优点:智能、高效。
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;public class ThreadPoolDemo8 {public static void main(String[] args) {//根据当前设备的配置自动生成线程池ExecutorService service = Executors.newWorkStealingPool();for (int i = 0; i < 100; i++) {service.submit(() -> {System.out.println("线程名:" + Thread.currentThread().getName());});}while(!service.isTerminated()){}}
}
4.2.通过ThreadPoolExecutor手动创建(1种)
⑦ThreadPoolExecutor:重点掌握,最原始方式,推荐使用。
--->Executors自动创建线程池返回的线程池对象的弊端如下:
- FixedThreadPool和SingleThreadPool:允许的请求队列长度为Integer.MAX_VALUE,可能会堆积大量的请求,从而导致OOM。
- CachedThreadPool:允许的创建线程数量为Integer.MAX_VALUE,可能会创建大量的线程,从而导致OOM。
OOM代码演示:
import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors;/*** 演示OOM*/ public class ThreadPoolDemo9 {static class OOMClass{//1M空间(M KB Byte)private byte[] bytes = new byte[1 * 1024 * 1024];}public static void main(String[] args) {ExecutorService service = Executors.newCachedThreadPool();Object[] objects = new Object[15];for (int i = 0; i < 15; i++) {int finalI = i;service.execute(() -> {try {Thread.sleep(finalI * 200);} catch (InterruptedException e) {e.printStackTrace();}OOMClass oomClass = new OOMClass();objects[finalI] = oomClass;System.out.println("执行第" + finalI + "次");});}} }
关于参数设置
- -XX:标准设置,所有 HotSpot 都⽀持的参数。
- -X:⾮标准设置,特定的 HotSpot 才⽀持的参数。
- -D:程序参数设置,-D参数=value,程序中使⽤:System.getProperty("获取")。
- mx 是 memory max 的简称。
《阿里巴巴Java开发手册》中强制规定:线程池不允许使用Executors去创建,而是通过ThreadPoolExecutor的方式,这样让程序员更加明确线程池的运行规则,规避资源耗尽的风险。
import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;/*** 手动方式创建线程池*/
public class ThreadPoolDemo10 {public static void main(String[] args) {ThreadFactory factory = new ThreadFactory() {@Overridepublic Thread newThread(Runnable r) {Thread thread = new Thread(r);return thread;}};//手动方式创建线程池ThreadPoolExecutor executor = new ThreadPoolExecutor(5, 10, 10, TimeUnit.SECONDS, new LinkedBlockingDeque<>(100), factory, new ThreadPoolExecutor.DiscardPolicy());//设置任务for (int i = 0; i < 10; i++) {executor.submit(() -> {System.out.println("线程名称:" + Thread.currentThread().getName());});}//终止线程executor.shutdown();//当任务执行完直接就结束了}
}
--->a.ThreadPoolExecutor 参数说明(包含 7 个参数可供设置,最少需要设置5个参数)
-
corePoolSize:核心线程数(正式员工的数量),可以⼤致理解为⻓期驻留的线程数⽬(除⾮设置了allowCoreThreadTimeOut)。对于不同的线程池,这个值可能会有很⼤区别,⽐如 newFixedThreadPool 会将其设置为 nThreads,⽽对于 newCachedThreadPool 则是为0。
-
maximumPoolSize:最大线程数(正式员工+临时员工的数量),就是线程不够时能够创建的最⼤线程数。同样进⾏对⽐,对于newFixedThreadPool,当然就是 nThreads,因为其要求是固定⼤⼩,⽽ newCachedThreadPool 则是 Integer.MAX_VALUE。
-
keepAliveTime:空闲线程的保活时间(针对临时员工),如果线程的空闲时间超过这个值,那么将会被关闭。注意此值⽣效条件必须满⾜:空闲时间超过这个值,并且线程池中的线程数少于等于核⼼线程数 corePoolSize。当然核⼼线程默认是不会关闭的,除⾮设置了allowCoreThreadTimeOut(true)那么核⼼线程也可以被回收。
-
TimeUnit:对参数3的时间单位描述。
-
BlockingQueue:任务/阻塞队列,⽤于存储线程池的待执⾏任务。必须要设置参数值;若不设置参数值,默认为Integer.MAX_VALUE,也会导致OOM问题。
-
threadFactory:用于生成线程的线程工厂,可设置线程属性,⼀般我们可以⽤默认的就可以了。
-
handler:拒绝策略管理器,处理极端问题。当线程池已经满了,但是又有新的任务提交的时候,该采取什么策略由这个来指定。有⼏种⽅式可供选择,像抛出异常、直接拒绝然后返回等,也可以⾃⼰实现相应的接⼝实现⾃⼰的逻辑。
--->b.线程池执行流程
--->c.线程池拒绝策略(4【JDK提供】+1【自定义】)
JDK提供的4种:
①AbortPolicy(默认的拒绝策略):提示异常,拒绝执行。
②DiscardPolicy:忽略最新的任务。
③DiscardOldestPolicy:忽略旧任务(任务队列中的第一个任务)。
④CallerRunsPolicy:使用调用线程池的线程来执行任务~叫救援。
自定义的1种:
5.线程池状态(5种)
①RUNNING:
线程池创建之后的初始状态,这是最正常的状态:接受新的任务,处理等待队列中的任务。
②SHUTDOWN:
线程池不再接受新的任务提交,但是会继续处理等待队列中的任务,将其执行结束。
③STOP:
线程池不接受新的任务提交,不再处理等待队列中的任务,中断正在执⾏任务的线程。
④TIDYING:
该状态下所有的任务都销毁了,workCount 为 0。会执⾏钩⼦⽅法 terminated()。
⑤TERMINATED:
terminated() ⽅法结束后,线程池的状态就会变成这个。
a.各个状态的转换过程
- RUNNING -> SHUTDOWN:当调⽤了 shutdown() 后,会发⽣这个状态转换,这也是最重要的;
- (RUNNING or SHUTDOWN) -> STOP:当调⽤ shutdownNow() 后,会发⽣这个状态转换;
- SHUTDOWN -> TIDYING:当任务队列和线程池都清空后,会由 SHUTDOWN 转换为 TIDYING;
- STOP -> TIDYING:当任务队列清空后,发⽣这个转换;
TIDYING -> TERMINATED:当 terminated() ⽅法结束后。b.shutdown VS shutdownNow
- shutdown 执⾏时线程池终⽌接收新任务,并且会将任务队列中的任务处理完;
- shutdownNow 执⾏时线程池终⽌接收新任务,并且会终⽌执⾏任务队列中的任务。
6.究竟选用哪种线程池?
阿⾥巴巴《Java开发⼿册》给的答案:推荐使⽤ThreadPoolExecutor 的⽅式进⾏线程池的创建,因为这种创建⽅式更可控,并且更加明确了线程池的运⾏规则,可以规避⼀些未知的⻛险。
相关文章:
JavaWeb14-线程池
目录 1.传统线程的缺点 2.线程池的定义 3.线程池的优点 4.线程池的创建/使用(2类7种) 4.1.通过Executors(执行器)自动创建(6种) ①Executors.newFixedThreadPool:创建⼀个固定⼤⼩的线程池…...
[qiankun+nuxt]子应用请求本地文件报错404
前言 目前公司的前端架构是qiankunnuxt做的微前端项目 问题说明 在子应用中,前端需要模拟一些数据,方便后期演示调整而不需要重新打包 所以将一些数据存储到了本地的json文件中,但是获取时报了404的错误,找不到该文件。 页面报错…...
【Qt网络编程】实现TCP协议通信
文章目录概要:本期主要讲解QT中对于TCP协议通信的实现。一、TCP协议二、Qt中TCP协议处理1.QTcpSocket2.QTcpServer三、Qt实现TCP通信1.客户端2.服务器端结尾概要:本期主要讲解QT中对于TCP协议通信的实现。 一、TCP协议 传输控制协议(TCP&am…...
Webpack打包———处理样式资源
基本使用 本质上,webpack 是一个用于现代 JavaScript 应用程序的 静态模块打包工具。当 webpack 处理应用程序时,它会在内部从一个或多个入口点构建一个 依赖图(dependency graph),然后将你项目中所需的每一个模块组合成一个或多个 bundles&a…...
VP记录:Codeforces Round 857 (Div. 2) A~D
传送门:CF A题 Likes: 这道题的题意很变态,十分的难懂,简直就是一坨shit,这场比赛最后被骂是有原因的 简单来说就是对于一个项目,每一个人都能对此加一或者减一,最后问你这个项目每一时刻最大和最小是多少.题目中只说明了只能点赞后才能取消,并没有解释存在取消操作必存在点…...
Docker常用项目实战演练
docker镜像源的修改 linux环境下编辑 /etc/docker/daemon.json vi /etc/docker/daemon.json #如添加如下网易镜像源 { "registry-mirrors": ["http://hub-mirror.c.163.com"] }docker run命令详细解释 日常工作中用的比较多的是docker run命令ÿ…...
Linux进程间通信-FIFO命名管道
Linux进程间通信-FIFO命名管道 1、概述 管道因为没有名称,所以只用于进程间的亲缘通信。为了克服这一缺点,提出了命名管道(FIFO),又称命名管道、FIFO文件。 FIFO不同于无名管道,它提供与之关联的路径名,该路径名以FIF…...
【Kafka】记录一次基于connect-mirror-maker做的Kafka集群迁移完整过程
文章目录背景环境工具选型实操MM1MM2以MM2集群运行以Standalone模式运行验证附录MM2配置表其他背景 一个测试环境的kafka集群,Topic有360,Partition有2000,部署在虚拟机上,由于多方面原因,要求迁移至k8s容器内&#x…...
实现VOC数据集与COCO数据集格式转换
实现VOC数据集与COCO数据集格式转换2、将voc数据集的xml转化为coco数据集的json格式2、COCO格式的json文件转化为VOC格式的xml文件3、将 txt 文件转换为 Pascal VOC 的 XML 格式<annotation><folder>文件夹目录</folder><filename>图片名.jpg</file…...
常用的密码算法有哪些?
我们将密码算法分为两大类。 对称密码(密钥密码)——算法只有一个密钥。如果多个参与者都知道该密钥,该密钥 也称为共享密钥。非对称密码(公钥密码)——参与者对密钥的可见性是非对称的。例如,一些参与者仅…...
SNS (Simple Notification Service)简介
SNS (Simple Notification Service) 是一种完全托管的发布/订阅消息收发和移动通知服务,用于协调向订阅终端节点和客户端的消息分发。 和SQS (Simple Queue Service)一样,SNS也可以轻松分离和扩展微服务,分布式系统和无服务应用程序…...
JVM初步理解浅析
一、JVM的位置 JVM的位置 JVM在操作系统的上一层,是运行在操作系统上的。JRE是运行环境,而JVM是包含在JRE中 二、JVM体系结构 垃圾回收主要在方法区和堆,所以”JVM调优“大部分也是发生在方法区和堆中 可以说调优就是发生在堆中…...
【巨人的肩膀】MySQL面试总结(一)
💪 目录💪1、什么是ER图2、数据库范式了解吗3、超键、候选键、主键、外键分别是什么?4、为什么不推荐使用外键与级联5、什么是存储过程6、drop、delete与truncate区别7、数据库设计通常分为那几步8、什么是关系型数据库9、什么是SQL10、MySQL…...
【数据结构之树】——什么是树,树的特点,树的相关概念和表示方法以及在实际的应用。
文章目录一、1.树是什么?2.树的特点二、树的相关概念三、树的表示方法1.常规方法表示树2.使用左孩子右兄弟表示法3. 使用顺序表来存储父亲节点的下标三、树在实际的应用总结一、1.树是什么? 树是一种非线性的数据结构,它是由n(n&…...
JavaScript语法
文章目录一、JavaScript是什么?JavaScript引入方式二、基础语法书写语法输出语句变量数据类型运算符流程控制语句数组函数JS变量作用域对象一、JavaScript是什么? JavaScript:是一门跨平台的脚本语言,用来控制网页行为࿰…...
【BIOS/UEFI】HII 基本框架及概述
HII(Human Interface Infrastructure )定义了一套管理用户输入的基础框架。HII数据库主要提供用户安装、卸载以及使用各种字符串、字体和图片等资源的接口。 HID Devices 是用户输入设备,如键盘、串口和网络;Display Devices 是输…...
sprintf(...)溢出边界导致程序崩溃的问题
文章目录小结问题及解决参考小结 使用sprintf(...)进行格式化是一种标准的做法,但是这样做是有一个极大的风险,由于sprintf(...)不进行边界检查,这样会有写操作溢出边界的风险,并导致程序崩溃。本文进行了简单写操作溢出边界的测…...
公式推导+dfs简版
写在前面的话:心可以冷,但手不能停 第一题:C. Flexible String 题目大意:给一个aaa字符串和bbb字符串和数字kkk,首先设置一个计数器cntcntcnt,其中可以对aaa字符串做以下操作:替换aaa中的一个字母xxx&#…...
论文笔记 | 标准误聚类问题
关于标准误的选择,如是否选择稳健性标准误、是否采取聚类标准误。之前一直是困惑的,惯用的做法是类似主题的文献做法。所以这一次,借计量经济学课程之故,较深入学习了标准误的选择问题。 在开始之前推荐一个知乎博主。他阅读了很…...
银行管理系统--课后程序(Python程序开发案例教程-黑马程序员编著-第7章-课后作业)
实例1:银行管理系统 从早期的钱庄到现如今的银行,金融行业在不断地变革;随着科技的发展、计算机的普及,计算机技术在金融行业得到了广泛的应用。银行管理系统是一个集开户、查询、取款、存款、转账、锁定、解锁、退出等一系列的功…...
【18】组合逻辑 - VL18 实现3-8译码器①
VL18 实现3-8译码器① 1 题目 【这题我的思路非常绝境】奈斯 !! 看真值表的思路:Yi所在列【0仅一个其余全1】,故【以0为对象求解】 观察发现:E3 E2_n E1_n = 100 时 是 译码的使能信号 ; 并且E3 E2_n E1_n为其他值时,都不使能译码 然后就很简单,没有仿真就成功了 2 代…...
2020蓝桥杯真题最长递增 C语言/C++
题目描述 在数列a_1 ,a_2,⋯,a_n 中,如果a_i <a_i1 <a_i2<⋯<a_j,则称 a_i至 a_j为一段递增序列,长度为 j−i1。 定一个数列,请问数列中最长的递增序列有多长。 输入描述 输入的第一行包含一个整数 n。 第二行包含…...
华为OD机试题 - 寻找连续区间(JavaScript)| 机考必刷
更多题库,搜索引擎搜 梦想橡皮擦华为OD 👑👑👑 更多华为OD题库,搜 梦想橡皮擦 华为OD 👑👑👑 更多华为机考题库,搜 梦想橡皮擦华为OD 👑👑👑 华为OD机试题 最近更新的博客使用说明本篇题解:寻找连续区间题目输入输出示例一输入输出说明示例二输入输出Cod…...
一次疲惫的调试--累了及时透气
原创 射频清茶 深山小老虎 2023-03-11 14:32发表于广东 收录于合集 #射频调试3个 #网分4个 #Wi-Fi 2个 进来透透气 道不尽红尘舍恋 诉不完人间恩怨 世世代代都是缘 喝着相同的水 留着相同的血 这条路漫漫又长远 红花当然配绿叶 这一辈子谁来陪 渺渺茫茫来又回 往日情景再…...
综合练习7 摄氏度转华氏温度(“\t“的使用,循环语句)
综合练习7 摄氏度转华氏温度 使用do…while循环,在控制台输入摄氏温度与华氏温度的对照表。 对照表从摄氏温度-30℃到50℃,每行间隔10℃,运行如下: 摄氏温度:-30℃ 华氏温度:-22.0℉ 摄氏温度:…...
AWS数据库总结
RDS – 联机事务处理OLTP(Online Transaction Processing),包括: SQL ServerOracleMySQL ServerPostgreSQLAuroraMariaDB非关系数据库DynamoDB数据仓库RedShift – 联机分析处理OLAP(Online Analytics Processing&…...
2个步骤就能批量给视频添加滚动字幕
现在很多小伙伴在剪辑视频的时候都会给自己的视频添加适配的字幕,但是有很多的视频想要添加一样的滚动字幕时,有一个能批量添加剪辑的工具非常重要,今天小编就给大家分享一个可以批量剪辑大量视频的工具,下面一起看看具体的操作步…...
PHP 的运行方式有哪些?
PHP本质上的运行方式可以分为两种: 基于命令行的基于PHP-FPM的 但实际上,PHP能做的事很多,很多场景下,不同的运行方式能让开发更方便,减轻各种工作。 测试开发 PHP内置了一个HTTP 的server。这意味着,很…...
Web学习3_JavaScript
1.1 JS的调用方式与执行顺序 使用方式 HTML页面中的任意位置加上<script type"module"></script>标签即可。 常见使用方式有以下几种: 直接在<script type"module"></script>标签内写JS代码。script type"modu…...
「MySQL基础」不可重复读和幻读的区别
「MySQL基础」不可重复读和幻读的区别 文章参考: 在数据库中不可重复读和幻读到底应该怎么分? 作者:暖猫Suki、普通熊猫 文章目录「MySQL基础」不可重复读和幻读的区别一、概述二、小结一、概述 正好在琢磨这个问题,也被搞得头昏…...
网站设计与制作/刷百度关键词排名
有关数据库 行 锁 的几个问题(rowlock) 行锁的基本说明: SELECT au_lname FROM authors WITH (NOLOCK) 锁定提示 2015-04-03 09:41 0人阅读 评论(0) 收藏 编辑 删除有关数据库 行 锁 的几个问题(rowlock) 行锁的基本说…...
家政保洁公司网站建设方案/房地产销售
springboot 项目开发中,maven配置中,dependencyManagement怎么使用,在多个子模块中,可以使用dependencyManagement中的jar吗?待解决!!! 参考:http://blog.csdn.net/mafan…...
湖南网站建设推广/百度收录软件
这里是对快速排序算法的一个简介,适合初学者。写在这里也是加深自己的印象,同时供学习交流。 1,我下面先对快速排序算法的过程做一个简单图形化介绍这样大家就会对后面的程序有个更清晰的认识。 排序问题如下: 问题描述ÿ…...
怎么给客户推广自己的产品/百度seo排名软
从Mac的App Store 上 自动更新微信之后,发现不能在SpotLight上搜索到了。 想着应该是索引出现了问题。 方法一、 采用如下命令重建索引: sudo mdutil -i off /该命令用来关闭索引sudo mdutil -E /该命令用来删除索引sudo mdutil -i on /该命令用来重建索…...
专业的上海网站建设公司哪家好/互站网
由于微信的限制,应用文件在内置浏览器中下载全部被屏蔽掉,造成很多人用微信扫描二维码下载时点击下载按钮没反应,我想到的是做一个提示用户在浏览器中打开下载。 其实原来很简单,就是判断当前是在微信内置浏览器中,然后…...
wordpress弹窗登录代码/如何做网络推广赚钱
导读——网络游戏成就了陈天桥,但是就算陈天桥当初没有迷上游戏,他一定也能找到其他创业的好点子。 陈天桥的成功来得太快,快得让大家还没有完全看懂:学生时代,他比别人长进快,凭着好成绩和活动组织能力强当…...