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

Java线程池应用实例

线程池的学习

      • 基本概念
        • 好处
        • 应用场景
        • ThreadPoolExecutor
        • 实例理解:
        • 执行流程
      • 自定义线程池
        • 4大核心参数
        • 测试demo
        • 结论:
      • ExecutorService
        • 常用方法
        • 思考
        • 获取ExecutorService
        • 代码示例
      • ScheduleExecutorService
        • 常用获取方式如下
        • ScheduledExecutorService常用方法如下:
        • 代码示例:
        • 总结:
      • Future
        • Future的常用方法如下:
        • 代码示例
      • 综合案例
        • 秒杀商品
          • 思路提示
          • 代码步骤:
          • 代码示例:
        • ATM机取款
          • 思路提示:
          • 代码示例
      • 线程池的五大使用步骤:

基本概念

线程池是多线程的一种处理方式,处理过程中将任务添加到队列中,线程创建完成后自动启动这些任务,任务就是实现了Runnable或Callable接口的实例对象

好处

可以根据系统需求和硬件环境灵活控制线程的数量,对线程进行统一管理

应用场景

1、网购秒杀
2、云盘上传和下载
3、12306网上购票

ThreadPoolExecutor

public ThreadPoolExecutor(int corePoolSize,//核心线程数:当一个任务提交到线程池中,如果当前运行的线程数量小于核心线程数,会新开一个线程来执行任务int maximumPoolSize,//最大线程数:当大于核心线程数时,可以设置一个最大线程数long keepAliveTime,//最大空闲时间(存活时间):当一个任务没有运行时候,task可以存活的时间TimeUnit unit,//时间单位:枚举类型,可设置天、小时、时分秒等BlockingQueue<Runnable> workQueue,//任务队列(临时缓冲区):当任务达到核心线程数量时,再有task提交到线程池需要在任务队列先排队,当任务队列满了之后会根据最大线程数创建新线程ThreadFactory threadFactory,//线程工厂:创建线程的工厂RejectedExecutionHandler handler) {//饱和处理机制:当核心线程数、最大线程数贺任务队列都满了需要处理的事情						  

实例理解:

假设某银行营业部有两名正式工,一名临时工,一个空闲等待座位,当有a、b、c、d客户依次来办理业务,a、b由两名正式工接待工作,c客户由临时工接待,d客户在座位等待,如果营业部是线程池,核心线程数(两名正式工)就是2,最大线程数(外加临时工)为3,任务队列(座位缓冲区)为1,当此时来了客户e办理业务,银行只能按照饱和处理机制拒绝接待客户e,当营业部临时工空闲时间超过1个小时后,经理就会让临时工(线程销毁)下班,有一个allowCoreThreadTimeOut变量控制是否允许销毁核心线程,默认为false,即时正式工闲着也不得提前下班

执行流程

在这里插入图片描述

自定义线程池

4大核心参数

1、核心线程数
按照8020原则设计,例如:一个任务执行需要0.1秒,系统80%每秒产生100个任务,那么一秒钟处理完需要10个线程,核心线程数就是10
2、任务队列长度
核心线程数/单个任务执行时间*2即可,任务队列长度为200
3、最大线程数
最大线程数还需要参照每秒产生的最大任务数,例如:系统每秒产生的最大任务数为1000,最大线程数=(最大任务数-任务队列长度)*单个任务执行时间
即最大线程数=(1000-200)*0.1=80个
4、最大空闲时间
根据系统参数设定,没有固定的参考值

测试demo

1:编写任务类(MyTask),实现Runnable接口;
2:编写线程类(MyWorker),用于执行任务需要持有所有任务
3:编写线程池类(MyThreadPool),包含提交任务执行任务的能力:
4:编写测试类(MyTest),创建线程池对象提交多个任务测试
MyTask

/*** 包含任务编号,每个任务执行时间为0.2秒*/
public class MyTask implements Runnable {private int id;/*** 由于run方法是重写接口中的方法,id属性初始化必须使用构造方法完成*/public MyTask(int id) {this.id = id;}@Overridepublic void run() {String name = Thread.currentThread().getName();
//        System.out.println("线程:" + name + "线程即将执行任务" + id);try {Thread.sleep(200);} catch (InterruptedException e) {e.printStackTrace();}System.out.println("线程:" + name + "线程完成了任务" + id);}@Overridepublic String toString() {return "MyTask{" +"id=" + id +'}';}
}

MyWork

import java.util.List;/*** 设计一个集合,用于保存所有任务*/
public class MyWork extends Thread {//保存线程的名字private String name;private List<Runnable> tasks;public MyWork(String name, List<Runnable> tasks) {super(name);this.tasks = tasks;}@Overridepublic void run() {//判断集合中是否有任务,只要有就一直执行任务while (tasks.size() > 0) {Runnable runnable = tasks.remove(0);runnable.run();}}
}

MyThreadPool

import java.util.Collections;
import java.util.LinkedList;
import java.util.List;/*** 这是自定义的线程池类;* 成员变量:* 1:任务队列集合需要控制线程安全问题* 2:当前线程数量* 3:核心线程数量* 4:最大线程数量* 5:任务队列的长度* 成员方法* 1: 提交任务;* 将任务添加到集合中,需要判断是否超出了任务总长度2: 执行任务;* 判断当前线程的数量,决定创建核心线程还是非核心线程*/
public class MyThreadPool {/*** 1:任务队列集合需要控制线程安全问题* 2:当前线程数量* 3:核心线程数量* 4:最大线程数量* 5:任务队列的长度*/private List<Runnable> tasks = Collections.synchronizedList(new LinkedList<>());private int num;private int corePoolSize;private int maxSize;private int workSize;public MyThreadPool(int corePoolSize, int maxSize, int workSize) {this.corePoolSize = corePoolSize;this.maxSize = maxSize;this.workSize = workSize;}public void submit(Runnable runnable) {//判断当前集合中任务数量是否超出了最大任务数量if (tasks.size() >= workSize) {System.out.println("任务:" + runnable + "被丢弃了...");} else {tasks.add(runnable);//执行任务execTask(runnable);}}private void execTask(Runnable runnable) {//判断当前线程池中的线程总数量,是否超出了核心数if (num < corePoolSize) {new MyWork("核心线程:" + num, tasks).start();num++;} else if (num < maxSize) {new MyWork("非核心线程:" + num, tasks).start();num++;} else {System.out.println("任务:" + runnable + "被缓存了...");}}}

JavaTest

/*** 1、创建线程池对象* 2、提交多个任务*/
public class JavaTest {public static void main(String[] args) {//1、创建线程池对象MyThreadPool pool = new MyThreadPool(2, 4, 20);//2.提交多个任务:当线程超过24时会出现线程被丢弃现象for (int i = 0; i < 3; i++) {//3.创建任务对象,并提交给线程池MyTask myTask = new MyTask(i);pool.submit(myTask);}}
}

结论:

当for循环中i为2,只执行两个核心线程
当for循环中i为4,执行两个核心线程,两个非核心线程
当for循环中i为5,执行两个核心线程,两个非核心线程,一个线程被缓存
当for循环中i为25,执行两个核心线程,两个非核心线程,20个线程被缓存,1个缓存被丢弃

ExecutorService

ExecutorService接口是java内置的线程池接口,通过学习接口中的方法,可以快速的掌握java内置线程池的基本使用

常用方法

void shutdown:启动一次顺序关闭,执行以前提交的任务,但不接受新任务.
List<Runnable> shutdownNow:停止所有正在执行的任务,暂停处理正在等待的任务,并返回等待执行的任务列表
<T> Future<T> submit(Callable<T> task):执行带返回值的任务,返回一个Future对象
Future<?> submit(Runnable task):执行 Runnable 任务,并返回一个表示该任务的 Future.
<T> Future<T> submitRunnable task,T result):执行 Runnable 任务,并返回一个表示该任务的 Future.

思考

既然ExecutorService是一个接口,接口是无法直接创建对象的,那么我们该如何获取ExecutorService的对象呢?

获取ExecutorService

可以利用JDK中的Executors 类中的静态方法常用获取方式如下:

static ExecutorService newCachedThreadPool():创建一个默认的线程池对象,里面的线程数不固定,且在第一次使用时才创建,适合硬件条件好的情况
static ExecutorService newCachedThreadPool(ThreadFactory threadFactory):线程池中的所有线程都使用ThreadFrctory来创建这样的线程无需手动启动,自动执行
static ExecutorService newFixedThreadPool(int nThreads):创建一个有固定线程数的线程池
static ExecutorService newFixedThreadPool(int nThreads, ThreadFactory threadFactory):创建一个有固定线程数的线程池且线程池中的所有线程都使用ThreadFactory来创建
static ExecutorService newSingleThreadExecutor():创建一个使用单个 worker 线程的 Executor,以无界队列方式来运行该线程
static ExecutorService newSingleThreadExecutor(ThreadFactory threadFactory)创建一个使用单个 worker 线程的 Executor,且线程池中的所有线程都使用ThreadFactory来创建

代码示例

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadFactory;/*** 练习Executors获取ExecutorService,然后调用方法,提交任务*/
public class MyTest01 {public static void main(String[] args) {//1、使用工厂类获取线程池对象ExecutorService service = Executors.newCachedThreadPool();//指定3个线程执行
//        ExecutorService service = Executors.newFixedThreadPool(3);//单一线程执行
//        ExecutorService service = Executors.newSingleThreadExecutor();//2、提交任务
//        test01(service);test02();//关闭线程池:在单一线程才能看到效果
//        service.shutdown();//一旦关闭无法再提交
//        service.submit(new MyRunnable01(888));}private static void test02() {//单一线程执行
//        ExecutorService service = Executors.newSingleThreadExecutor(new ThreadFactory()//指定3个线程执行
//        ExecutorService service = Executors.newFixedThreadPool(3,new ThreadFactory()ExecutorService service = Executors.newCachedThreadPool(new ThreadFactory() {int n = 1;@Overridepublic Thread newThread(Runnable r) {return new Thread(r, "自定义的线程名称" + n++);}});for (int i = 0; i < 10; i++) {//如果线程在忙会重新创建新的线程,当线程空闲到一定时间会自动销毁,默认时间为60sservice.submit(new MyRunnable01(i));}//立刻关闭线程池,线程池中有缓存未执行则取消执行,并返回这些任务
//        List<Runnable> runnableList = service.shutdownNow();
//        System.out.println(runnableList);}private static void test01(ExecutorService service) {for (int i = 0; i < 10; i++) {//如果线程在忙会重新创建新的线程,当线程空闲到一定时间会自动销毁,默认时间为60sservice.submit(new MyRunnable01(i));}}
}/*** 任务类:在任务中打印出哪一个线程正在执行任务*/
class MyRunnable01 implements Runnable {private int id;public MyRunnable01(int id) {this.id = id;}@Overridepublic void run() {String name = Thread.currentThread().getName();System.out.println(name + "执行了任务..." + id);}@Overridepublic String toString() {return "MyRunnable01{" +"id=" + id +'}';}
}

单一线程shutdownNow执行结果:

自定义的线程名称1执行了任务...0
[java.util.concurrent.FutureTask@548c4f57, 
java.util.concurrent.FutureTask@1218025c, 
java.util.concurrent.FutureTask@816f27d, 
java.util.concurrent.FutureTask@87aac27, 
java.util.concurrent.FutureTask@3e3abc88, 
java.util.concurrent.FutureTask@6ce253f1, 
java.util.concurrent.FutureTask@53d8d10a, 
java.util.concurrent.FutureTask@e9e54c2, 
java.util.concurrent.FutureTask@65ab7765]

ScheduleExecutorService

当我们的线程池提交后需要延迟一定时间来执行任务,ExecutorService就不适用了,Java给了内置线程池ScheduleExecutorService
ScheduledExecutorService是ExecutorService的子接口,具备了延迟运行或定期执行任务的能力

常用获取方式如下

static ScheduledExecutorService newScheduledThreadPool(int corePoolSize)创建一个可重用固定线程数的线程池且允许延迟运行或定期执行任务
static ScheduledExecutorService newScheduledThreadPool(int corePoolSize, ThreadFactory threadFactory)创建一个可重用固定线程数的线程池且线程池中的所有线程都使用ThreadFactory来创建,且允许延迟运行或定期执行任务
static ScheduledExecutorService newSingleThreadScheduledExecutor(创建一个单线程执行程序,它允许在给定延迟后运行命令或者定期地执行
static ScheduledExecutorService newSingleThreadScheduledExecutor(ThreadFactory threadFactory)创建一个单线程执行程序,它可安排在给定延迟后运行命令或者定期地执行

ScheduledExecutorService常用方法如下:

<V> ScheduledFuture<V> schedule(Callable<V> callable, long delay, TimeUnit unit)延迟时间单位是unit,数量是delay的时间后执行callable。
ScheduledFuture<?> schedule(Runnable command, long delay, TimeUnit unit)延迟时间单位是unit;数量是delay的时间后执行command。
ScheduledFuture<?> scheduleAtFixedRate(Runnable command, long initialDelay, long period, TimeUnit unit延迟时间单位是unit,数量是initialDelay的时间后,每间隔period时间重复执行一次command。
ScheduledFuture<?> scheduleWithFixedDelay(Runnable command, long initialDelay, long delay, TimeUnit unit)创建并执行一个在给定初始延迟后首次启用的定期操作,随后,在每一次执行终止和下一次执行开始之间都存在给定的延迟。

代码示例:

import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.TimeUnit;/*** 测试ScheduleExecutorService接口中延迟执行任务和重复执行任务的功能*/
public class ScheduleExecutorService01 {public static void main(String[] args) {//1、获取一个具备延迟执行任务的线程池对象ScheduledExecutorService scheduledThreadPool1 = Executors.newScheduledThreadPool(3);//2、创建多个任务对象,提交任务,每个任务延迟2秒执行scheduledThreadPool1.schedule(new MyRunnable(1), 2, TimeUnit.SECONDS);System.out.println("over");ScheduledExecutorService scheduledThreadPool2 = Executors.newScheduledThreadPool(3, new ThreadFactory() {int n = 1;@Overridepublic Thread newThread(Runnable r) {return new Thread(r, "自定义线程名:" + n++);}});//2、创建多个任务对象,提交任务,延迟1秒执行第一个任务,之后延迟2秒执行scheduledThreadPool2.scheduleAtFixedRate(new MyRunnable(1), 1, 2, TimeUnit.SECONDS);System.out.println("over");ScheduledExecutorService scheduledThreadPool3 = Executors.newSingleThreadScheduledExecutor(new ThreadFactory() {int n = 1;@Overridepublic Thread newThread(Runnable r) {return new Thread(r, "自定义线程名:" + n++);}});//2、创建多个任务对象,提交任务,延迟1秒执行第一个任务,之后延迟2秒执行scheduledThreadPool3.scheduleWithFixedDelay(new MyRunnable(1), 1, 2, TimeUnit.SECONDS);System.out.println("over");}
}class MyRunnable implements Runnable {private int id;public MyRunnable(int id) {this.id = id;}@Overridepublic void run() {String name = Thread.currentThread().getName();System.out.println(name + "执行了任务:" + id);}
}

总结:

schedule:延迟多久执行一次
scheduleAtFixedRate:间隔多久重复去执行
scheduleWithFixedDelay:第一个任务执行完成后,间隔多久去执行下一个任务

Future

我们刚刚在学习java内置线程池使用时,没有考虑线程计算的结果,但开发中,我们有时需要利用线程进行一些计算,然后获取这些计算的结果,而java中的Future接口就是专门用于描述异步计算结果的,我们可以通过Future 对象获取线程计算的结果:

Future的常用方法如下:

boolean cancel(boolean maylnterruptlfRunning)
试图叔消对此任务的执行。
V get()
如有必要,等待计算完成,然后获取其结果
V get(long timeout, TimeUnit unit)
如有必要,最多等待为使计算完成所给定的时间之后,获取其结果(如果结果可用)
boolean isCancelled()
如果在任务正常完成前将其取消,则返回 trueboolean isDone()
如果任务已完成,则返回 true

代码示例

import java.util.concurrent.*;/*** 练习异步计算结果*/
public class FutureTest {public static void main(String[] args) throws Exception {//1、获取线程池对象ExecutorService executorService = Executors.newCachedThreadPool();//2、创建Callable类型的任务对象Future<Integer> future = executorService.submit(new MyCall(1, 2));//3、判断任务是否完成
//        test01(future);
//        future.cancel(true);
//        boolean cancelled = future.isCancelled();
//        System.out.println("任务执行的结果是:" + cancelled);//由于等待时间过短,任务来不及执行完成会报异常Integer integer = future.get(1, TimeUnit.SECONDS);System.out.println("任务执行的结果是:" + integer);}private static void test01(Future<Integer> future) throws InterruptedException, ExecutionException {boolean done = future.isDone();System.out.println("第一次判断任务是否完成:" + done);boolean cancelled = future.isCancelled();System.out.println("第一次判断任务是否取消:" + cancelled);Integer result = future.get();//一直等待任务的执行,直到执行完成为止System.out.println("任务执行的结果是:" + result);boolean done2 = future.isDone();System.out.println("第二次判断任务是否完成:" + done2);boolean cancelled2 = future.isCancelled();System.out.println("第二次判断任务是否取消:" + cancelled2);}
}class MyCall implements Callable<Integer> {private int a;private int b;public MyCall(int a, int b) {this.a = a;this.b = b;}@Overridepublic Integer call() throws Exception {String name = Thread.currentThread().getName();System.out.println(name + "准备开始计算...");Thread.sleep(2000);System.out.println(name + "计算完成...");return a + b;}
}

综合案例

秒杀商品

案例介绍:假如某网上商城推出活动,新上架10部新手机免费送客户体验,要求所有参与活动的人员在规定的时间同时参与秒杀挣抢,假如有20人同时参与了该活动,请使用线程池模拟这个场景,保证前10人秒杀成功,后10人秒杀失败;要求

1、使用线程池创建线程
2、解决线程安全问题

思路提示

1:既然商品总数量是10个,那么我们可以在创建线程池的时候初始化线程数是10个及以下,设计线程池最大数量为10个2:当某个线程执行完任务之后,可以让其他秒杀的人继续使用该线程参与秒杀
3:使用synchronized控制线程安全防止出现错误数据

代码步骤:

1:编写任务类,主要是送出手机给秒杀成功的客户
2:编写主程序类创建20个任务(模拟20个客户);
3:创建线程池对象并接收20个任务开始执行任务

代码示例:
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;/*** 测试任务类*/
public class MyTest {public static void main(String[] args) {//1、创建一个线程池对象ThreadPoolExecutor executor = new ThreadPoolExecutor(3, 5, 1, TimeUnit.MINUTES, new LinkedBlockingQueue<>(15));//2、循环创建任务对象for (int i = 0; i <= 10; i++) {MyTask myTask = new MyTask("客户" + i);executor.submit(myTask);}//3、关闭线程池executor.shutdown();}}
class MyTask implements Runnable {//设计一个变量,用于表示商品的数量private static int id = 10;//表示商品名称的变量private String userName;public MyTask(String userName) {this.userName = userName;}@Overridepublic void run() {String name = Thread.currentThread().getName();System.out.println(userName + "正在使用" + name + "参与秒杀任务...");synchronized (MyTask.class) {if (id > 0) {System.out.println(userName + "使用" + name + "秒杀:" + id + "号商品成功啦!");} else {System.out.println(userName + "使用" + name + "秒杀失败啦!");}}}
}

ATM机取款

设计一个程序,使用两个线程模拟在两个地点同时从一个账号中取钱,假如卡中一共有1000元,每个线程取800元要求演示结果一个线程取款成功,剩余200元,另一个线程取款失败,余额不足要求:
1:使用线程池创建线程
2:解决线程安全问题

思路提示:

1:线程池可以利用Executors工厂类的静态方法,创建线程池对象;
2:解决线程安全问题可以使用synchronized方法控制取钱的操作;
3:在取款前,先判断余额是否足够,且保证余额判断和取钱行为的原子性;

代码示例
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadFactory;public class MyTest {public static void main(String[] args) {//1、创建线程池对象ExecutorService pool = Executors.newFixedThreadPool(2, new ThreadFactory() {int id = 1;@Overridepublic Thread newThread(Runnable r) {return new Thread(r, "ATM" + id--);}});//2、创建两个任务并提交for (int i = 0; i < 2; i++) {pool.submit(new MyTask("客户" + i, 800));}//3、关闭线程池pool.shutdown();}
}class MyTask implements Runnable {//用户姓名private String userName;//取款金额private double money;//总金额private static double total = 1000;public MyTask(String userName, double money) {this.userName = userName;this.money = money;}@Overridepublic void run() {String name = Thread.currentThread().getName();System.out.println(userName + "正在使用" + name + "取款" + money + "元");try {Thread.sleep(200);} catch (InterruptedException e) {e.printStackTrace();}synchronized (MyTask.class) {if (total - money > 0) {System.out.println(userName + "正在使用" + name + "取款" + money + "元成功,余额" + (total - money));total -= money;} else {System.out.println(userName + "正在使用" + name + "取款" + money + "元失败,余额" + total);}}}
}

线程池的五大使用步骤:

1:利用Executors工厂类的静态方法创建线程池对象
2:编写Runnable或Callable实现类的实例对象
3:利用ExecutorService的submit方法或ScheduledExecutorService的schedule方法提交并执行线程任务
4:如果有执行结果则处理异步执行结果(Future)
5:调用shutdown0方法关闭线程池

相关文章:

小组练习 :结合本小组项目写下能想到的所有 SWOT

结合本小组项目写下能想到的所有SWOT 答:SWOT分析是一种战略规划工具,用于评估一个项目或企业的优势(Strengths)、劣势(Weaknesses)、机会(Opportunities)和威胁(Threats)。以下是针对本小组校园跑腿项目的SWOT分析: 优势(Strengths):创新性: 校园跑腿项目可能提供…...

5G前传光纤传输的25G光模块晶振SG2016CAN

一款适用于5G前传光纤传输网络中的25G光模块的5G晶振SG2016CAN。随着5G时代的到来&#xff0c;5G晶振的重要性也不言而喻&#xff0c;小体积宽温晶振SG2016CAN可以用于5G前传的25G光模块&#xff0c;具有高稳定性、小体积、宽温等优势。在5G前传光纤传输网络中&#xff0c;25G光…...

【快速入门Linux】10_Linux命令—Vi编辑器

文章目录 一、vi 简介1.1 vi1.2 vim1.3查询软连接命令&#xff08;知道&#xff09; 二、打开和新建文件&#xff08;重点&#xff09;2.1 打开文件并且定位行2.2 异常处理 三、vi三种工作模式&#xff08;重点&#xff09;3.1 末行模式-命令 四、常用命令4.0 命令线路图4.1 移…...

跨界探索:在苹果系统M系列处理器上安装Windows 11系统的实践经历

[ 知识是人生的灯塔&#xff0c;只有不断学习&#xff0c;才能照亮前行的道路。] 大家好&#xff0c;我是【WeiyiGeek/唯一极客】一个正在向全栈工程师(SecDevOps)前进的技术爱好者 作者微信&#xff1a;WeiyiGeeker 公众号/知识星球&#xff1a;全栈工程师修炼指南 主页博…...

P9218 Apollo题解

题目分析 仔细阅读题目,可知题目要求的是对于每个 \(a_i\) 的 \(\sum\limits_{j=1}^ng(a_i,a_j)\) 。再结合 \(g(a,b)\) 的定义,可知,对于 \(a_i\) 来说,我们需要计算 \(a_i\) 与 \(a_1\sim a_n\) 构成的 \(n\) 组数对的 \(g(a_i,a_j)\) 的总和。对于 \(g(a,b)\) 的值,则是…...

三角函数之和差化积公式

知识点1:三角函数奇偶性: \(\sin(-\theta)=-\sin\theta, \quad \cos(-\theta)=\cos\theta\)如上图: 单位半圆的半径为1,\(\triangle AOB\)为等腰三角形。 点\(C\)为线段\(AB\)之中点,连接\(CO\)。 根据等腰三角形的性质,\(OC\) 是 \(△AOB\) 的角平分线和垂直平分线。 \(…...

Java线程池应用实例

线程池的学习基本概念好处应用场景ThreadPoolExecutor实例理解&#xff1a;执行流程自定义线程池4大核心参数测试demo结论&#xff1a;ExecutorService常用方法思考获取ExecutorService代码示例ScheduleExecutorService常用获取方式如下ScheduledExecutorService常用方法如下:代…...

数字签名技术

介绍数字签名 数字签名是一种用于确认数据的完整性、确认发送者身份的技术。 签名主要包含两个过程&#xff1a;做摘要、进行非对称加密。 做摘要&#xff1a;签名者使用消息摘要算法对消息做摘要&#xff1b;进行非对称加密&#xff0c;得到签名值&#xff1a;签名者使用私…...

WPF-3D图形

WPF-3D图形 WPF的3D功能可以在不编写任何c#代码的情况下进行绘制&#xff0c;只需要使用xaml即可完成3D图形的渲染。本文主要讲述了WPF-3D中的关键概念&#xff0c; 以及常用到的命中测试、2d控件如何在3D对象中进行渲染&#xff0c;除此之外&#xff0c;还演示了如何导入外部…...

返回值的理解

前言 我们写的函数是怎么返回的&#xff0c;该如何返回一个临时变量&#xff0c;临时变量不是出栈就销毁了吗&#xff0c;为什么可以传递给调用方&#xff1f;返回对象的大小对使用的方式有影响吗&#xff1f;本文将带你探究这些问题&#xff0c;阅读本文需要对函数栈帧有一定…...

前端布局神器display:flex

Flexbox&#xff0c;一种CSS3的布局模式&#xff0c;也叫做弹性盒子模型&#xff0c;用来为盒装模型提供最大的灵活性。首先举一个栗子&#xff0c;之前我们是这样实现一个div盒子水平垂直居中的。在知道对象高宽的情况下&#xff0c;对居中元素绝对百分比定位&#xff0c;然后…...

【Typescript学习】使用 React 和 TypeScript 构建web应用(三)所有组件

教程来自freecodeCamp&#xff1a;【英字】使用 React 和 TypeScript 构建应用程序 跟做&#xff0c;仅记录用 其他资料&#xff1a;https://www.freecodecamp.org/chinese/news/learn-typescript-beginners-guide/ 第三天 以下是视频(0:40-0:60) 的内容 目录第三天1 创建Todo…...

7.3 矩阵范数

定义 向量有范数&#xff0c;矩阵也有范数&#xff0c;定义和向量范数类似&#xff0c;不过多了一条要求。它的定义如下&#xff1a; 正定性positivity,∥A∥≥0\parallel A\parallel\ge 0∥A∥≥0&#xff0c;只有A0A0A0时才取等号&#xff1b;非负齐次性homogeneity或scalin…...

Jetpack架构组件库:Hilt

Hilt Hilt 是基于 Dagger2 的依赖注入框架&#xff0c;Google团队将其专门为Android开发打造了一种纯注解的使用方式&#xff0c;相比 Dagger2 而言使用起来更加简单。 依赖注入框架的主要作用就是控制反转&#xff08;IOC, Inversion of Control&#xff09;, 那么什么是控制…...

InstanceNorm LayerNorm

InstanceNorm && LayerNorm author: SUFEHeisenberg date: 2023/01/26 先说结论: 将Transformer类比于RNN&#xff1a;一个token就是一层layer&#xff0c;对一整句不如token有意义原生Bert代码或huggingface中用的都是InstanceNorm instead of LayerNorm&#xff…...

数据结构---堆

堆 定义 基本操作 建堆 堆排序 优先队列 一、堆的定义&#xff1a; 堆必须是一个完全二叉树 还得满足堆序性 什么是完全二叉树呢&#xff1f; 完全二叉树只允许最后一行不为满 且最后一行必须从左到右排序 最后一行元素之间不可有间隔&#xff0c;中间不可有空缺 如下几棵树…...

3小时精通opencv(五) 利用TrackBar进行颜色检测

3小时精通opencv(五) 利用TrackBar进行颜色检测 参考视频资源:3h精通Opencv-Python 本章内容介绍如何利用TrackBar调节色域, 手动提取到我们需要的颜色 文章目录3小时精通opencv(五) 利用TrackBar进行颜色检测创建Trackbar色彩检测创建Trackbar 在opencv中使用createTrackbar函…...

学习记录673@项目管理之进度管理案例

本文主要是进度管理之关键链路法的案例。 案例 Perfect 项目的建设方要求必须按合同规定的期限交付系统&#xff0c;承建方项目经理李某决定严格执行项目进度管理&#xff0c;以保证项目按期完成。他决定使用关键路径法来编制项目进度网络图。在对工作分解结构进行认真分析后&…...

【设计模式】结构型模式·组合模式

学习汇总入口【23种设计模式】学习汇总(数万字讲解体系思维导图) 写作不易&#xff0c;如果您觉得写的不错&#xff0c;欢迎给博主来一波点赞、收藏~让博主更有动力吧&#xff01; 一.概述 又称为部分整体模式&#xff0c;用于把一组相似的对象当作一个单一的对象。组合模式依…...

Vue-Router详解

1、前端路由的发展历程 1.1、认识前端路由 路由其实是网络工程中的一个术语&#xff1a; 在架构一个网络时&#xff0c;非常重要的两个设备就是路由器和交换机。当然&#xff0c;目前在我们生活中路由器也是越来越被大家所熟知&#xff0c;因为我们生活中都会用到路由器&…...

Eclipse中的Build Path

Eclipse中的Build Path简介如果修改了Build Path中的中的JRE版本&#xff0c;记得还需要同步修改Java编译器的版本&#xff0c;如下图红框所示简介 Build Path是Java工程包含的资源属性合集&#xff0c;用来管理和配置此Java工程中【除当前工程自身代码以外的其他资源】的引用…...

Python与Matlab混合编程案例

前言因为项目需要&#xff0c;需要批处理很多Matlab的.m文件&#xff0c;从每个文件中提取结果合并到一个文件中。 很明显&#xff0c;如果手工统计&#xff0c;几百个文件会累死的。 因此立即想到了Python在批处理方面的优势&#xff0c;因此就在网上找了相关资料&#xff0c;…...

stack、queue、priority_queue

容器适配器 适配器是一种设计模式(设计模式是一套被反复使用的、多数人知晓的、经过分类编目的、代码设计经验的总结)&#xff0c;该种模式是将一个类的接口转换成客户希望的另外一个接口。 其中stack和queue都是容器适配器&#xff0c;其中stack可以封装vector、list以及我们…...

高通平台开发系列讲解(GPS篇)gpsONE 系统架构

文章目录 一、系统架构图二、gpsONE系统组成三、gpsONE交互流程沉淀、分享、成长,让自己和他人都能有所收获!😄 📢高通的定位系统模块,名称叫gpsONE。 一、系统架构图 二、gpsONE系统组成 GPS系统架构可以分为六个部分: APP层Framework Client端(LocationManager API…...

zkMove——针对Move合约生态的zkVM

1. 引言 Move为不同于Solidity的&#xff0c;开源的安全的智能合约开发语言&#xff0c;最早由Facebook为Diem链创造开发。不过&#xff0c;Move本身设计为与平台无关的语言&#xff0c;具有通用的库、工具&#xff0c;并使得采用完全不同数据模型和执行模型的链的开发者社区都…...

贪心算法的题目

每一步都做出一个局部最优的选择&#xff0c;最终的结果就是全局最优 只有一部分问题才能用贪心算法&#xff08;严格来讲&#xff0c;一个问题能不能用贪心算法需要证明的&#xff09; 2022.8.30 蔚来笔试题&#xff1a; 有a个y,b个o,c个u,用这些字母拼成一个字符串&#xf…...

线程控制--Linux

文章目录线程理解线程的优点与缺点进程的多个线程共享线程控制线程创建线程终止线程等待线程分离总结线程理解 谈及线程&#xff0c;就不得不谈起进程与线程的关系了。学习完前面有关进程的知识&#xff0c;之前我们对进程的定义是&#xff1a;内核数据结构代码和数据。但是今…...

17 | 如何做好面试复盘?将经验提升为能力

前言 前言&#xff1a;面试是最好的查漏补缺机会&#xff0c;做好面试复盘又是十分的重要。 文章目录前言一. 关于复盘1. 什么是复盘&#xff08;What&#xff09;2. 复盘的目的&#xff08;Why&#xff09;3. 什么时候需要复盘&#xff08;When&#xff09;4. 怎么进行复盘&am…...

数据结构-树

1. 二叉树遍历 #include <stdbool.h> #include "stdio.h" #include "stdlib.h"typedef struct TNode *Position; typedef Position BinTree; // 二叉树类型 typedef char ElementType;// 树结点定义 struct TNode {ElementType Data; // 结点数据Bin…...

Python3 循环语句

本章节将为大家介绍 Python 循环语句的使用。 Python 中的循环语句有 for 和 while。 Python 循环语句的控制结构图如下所示&#xff1a; while 循环 Python 中 while 语句的一般形式&#xff1a; while 判断条件(condition)&#xff1a;执行语句(statements)…… 执行流程…...

时序数据处理中的拟合问题

对于深度学习或机器学习模型而言,我们不仅要求它对训练数据集有很好的拟合(训练误差),同时也希望它可以对未知数据集(测试集)有很好的拟合结果(泛化能力),所产生的测试误差被称为泛化误差。度量泛化能力的好坏,最直观的表现就是模型的过拟合(overfitting)和欠拟合(…...

[数据结构基础]排序算法第一弹 -- 直接插入排序和希尔排序

目录 一. 排序的概念及分类 1.1 排序的概念 1.2 常见的排序算法 二. 直接插入排序 2.1 直接插入排序的实现逻辑 2.2 直接插入排序的实现代码 2.3 直接插入排序的时间复杂度分析 三. 希尔排序 3.1 希尔排序的实现逻辑 3.2 希尔排序实现代码 3.3 希尔排序的效率测试 …...

厚积薄发打卡Day115:Debug设计模式<简单工厂、工厂方法、抽象工厂>

厚积薄发打卡Day115&#xff1a;Debug设计模式<简单工厂、工厂方法、抽象工厂> 简单工厂 定义 由一个工厂对象决定创建出哪一种产品类的实例&#xff08;严格意义并不是设计模式&#xff0c;更是一种风格&#xff09; 类型&#xff1a;创建型&#xff0c;但不属于GOF…...

python元组

python元组 文章目录python元组一、实验目的二、实验原理三、实验环境四、实验内容五、实验步骤1.创建元组2.访问元组3.修改元组4.删除元组5.索引及截取6.元组运算符7.内置函数总结一、实验目的 掌握元组的用法 二、实验原理 Python 的元组与列表类似&#xff0c;不同之处在…...

gcc中预定义的宏__GNUC__ __GNUC_MINOR__ __GNUC_PATCHLEVEL__

今天在看Linux系统编程这本书的代码的时候看到了__GNUC__&#xff0c;不太清楚这个宏所以去查了一下&#xff0c;以此记录。GNU C预定义了一系列的宏&#xff0c;这些宏都是以双下划线开始的&#xff0c;这里只讲一下__GNUC__ __GNUC_MINOR__ __GNUC_PATCHLEVEL__&#xff0c;完…...

AxMath使用教程(持续更新中)

前言 这两天学了学Latex&#xff0c;主要是为了以后写毕业论文做铺垫&#xff0c;而且Latex在数学公式这一方面&#xff0c;要比Word方便许多&#xff0c;于是我就下载了一款国产的公式编辑器——AxMath。永久会员不贵&#xff0c;只要36元&#xff0c;而且软件很好用&#xf…...

day11 栈和队列 | 20、有效的括号 1047、删除字符串中的所有相邻重复项 150、逆波兰表达式求值

题目 20、有效的括号 给定一个只包括 ‘(’&#xff0c;‘)’&#xff0c;‘{’&#xff0c;‘}’&#xff0c;‘[’&#xff0c;‘]’ 的字符串&#xff0c;判断字符串是否有效。 有效字符串需满足&#xff1a; 左括号必须用相同类型的右括号闭合。 左括号必须以正确的顺序…...

【前端面试】http面试整理

"一问一答"模型的协议 客户端通过http请求&#xff1b;服务器端根据请求返回客户想要的资源&#xff1b;客户端接收到资源&#xff1b;http是什么 HTTP是超文本传输协议&#xff0c;是一个在计算机世界里专门在两点之间传输文字、图片、音频、视频等超文本数据的约…...

倒霉倒霉倒霉(传送门 bfs 三维数组 递归 综合运用

题目描述“啊&#xff01;倒霉倒霉倒霉~”龙叔被困在一座大厦里了&#xff0c;可恶的瓦龙把这座大厦点燃了&#xff0c;他借机消灭龙叔。这座大厦有L层&#xff0c;每一层都有R*C个房间。熊熊火焰蔓延十分快&#xff0c;有的房间已经着火了&#xff0c;龙叔没办法通过。这时老爹…...

C++函数定义和调用介绍

C函数定义和调用介绍 函数的意义&#xff1a;利用率高&#xff0c;可读性强&#xff0c;利于移植。 一个C程序中主函数有且只有一个&#xff0c;是程序的入口&#xff0c;而函数&#xff08;或称子函数&#xff09;可以有很多。 每个 C 程序都至少有一个函数&#xff0c;即主…...

手把手带初学者快速入门 JAVA Web SSM 框架

博主也是刚开始学习SSM&#xff0c;为了帮大家节省时间&#xff0c;写下SSM快速入门博客 有什么不对的地方还请 私信 或者 评论区 指出 ​只是一个简单的整合项目&#xff0c;让初学者了解一下SSM的大致结构 项目先把框架写好&#xff0c;之后在填写内容 项目压缩包 完整的蓝奏…...

RocketMQ源码本地搭建调试

1 GitHub源码 git clone https://github.com/apache/rocketmq.git导入IDEA&#xff0c;可在命令行执行mvn compile一下&#xff0c;保证源码能够正确编译。本次我使用的master分支的版本-4.8.0。下面我们开始准备启动Namesrv。 2 启动Namesrv 到namesrv模块找到NamesrvStart…...

Axios 二次封装并使用

index.js import axios from "axios";let token localStorage.getItem("token"); // let token "123213"; class Request {// 自定义变量instance;constructor(config) {// console.log(config)// 创建axios 实例&#xff0c;变量接收this.in…...

【SpringCloud】Nacos集群搭建

集群结构图官方给出的Nacos集群图如下&#xff1a;其中包含3个nacos节点&#xff0c;然后一个负载均衡器代理3个Nacos。这里负载均衡器可以使用nginx。我们接下来要尝试 Nacos集群搭建&#xff0c;效果图如下所示&#xff1a;三个nacos节点的地址&#xff1a;节点ipportnacos1l…...

【CSDN的2022与2023】普普通通的三年,从懵懂、焦虑到坚定、奋进,破除焦虑努力成为更好的自己

大家好&#xff0c;我是黄小黄&#xff01;一名普通的软件工程在读学生。最近终于闲下来了一丢丢&#xff01;借着休息之余&#xff0c;来写一篇年度总结散散心~与其说是年度总结&#xff0c;不如说是给大学生活与莽莽撞撞的自己一个交代叭&#xff01; 这些都是小标题~碎碎念1…...

k8s单机版使用本地存储local-path-provisioner

在k8s单机环境中&#xff0c;我们经常使用本机路径作为持久化存储。在k8s官方文档中有两种方式使用本机存储&#xff0c;一种是hostPath&#xff0c;另一种是local volume&#xff0c;这两种都不支持动态扩容&#xff0c;并且程序移植改动比较大&#xff0c;而local-path-provi…...

MySQL优化(1)执行计划explain中type属性详解

系列文章目录1.初始化测试数据1.初始化表格&#xff08;user表&#xff09;2.初始化表格&#xff08;product表&#xff09;3.初始化表格&#xff08;user表数据初始化&#xff09;4.初始化表格&#xff08;product表函数&#xff09;5.初始化表格&#xff08;product表数据初始…...

servlet过滤器Filter简要回顾-过滤请求字符编码,/和/*和/**的区别

servlet过滤器Filter简要回顾-过滤请求字符编码,/和/*和/**的区别servlet过滤器1.filter过滤器的含义2.filter过滤器的使用3.测试-过滤字符编码正确响应中文编码3.1 创建servlet用于显示中文字符3.2 自定义过滤器3.3 配置web.xml中的servlet映射以及过滤器请求拦截3.4 运行输出…...

Java链表OJ题

目录1. 删除链表中等于给定值val的所有结点2. 逆置单链表3. 链表的中间结点4. 链表中倒数第k个结点5. 将两个有序链表合并为一个新的有序链表6. 以给定值x为基准将链表分割成两部分7. 判断是否为回文链表8. 两个链表的第一个公共结点9. 判断链表中是否有环10. 链表开始入环的第…...

0、Spring工程构建Spring快速入门Spring配置文件详解注入Sprint相关API

1、Spring工程构建 创建工程项目目录文件夹 IDEA选择项目new一个module 配置案例 aop创建 创建并下载完毕后&#xff0c;点击file选择projert 选择按照的jdk版本 output选择当前目录&#xff0c; 点击右下方apply 选择facets&#xff0c;点击""号选择web 选择当前…...

网络原理之HTTP/HTTPS、TCP、IP四层协议栈

文章目录一、应用层&#xff08;一&#xff09;xml协议&#xff08;二&#xff09;json协议&#xff08;三&#xff09;protobuffer协议&#xff08;四&#xff09;HTTP协议1. 抓包工具&#xff0c;fiddler2. HTTP报文格式3. HTTP请求(Request)&#xff08;1&#xff09;URL基本…...

CS61B 2021spring HW0

HW 0: A Java Crash Course 文章目录HW 0: A Java Crash CourseA Basic ProgramCreative Exercise 1a: Drawing a TriangleCreative Exercise 1b: DrawTriangleExercise 2、3Optional: Exercise 4Java可视化orz表达积累参考资料这个hw是optional&#xff0c;然后主要是给至少学…...

自动驾驶环境感知——视觉传感器技术

文章目录1. 摄像头的成像原理1.1 单目视觉传感器的硬件结构1.2 单目视觉的成像原理 –小孔成像模型1.3 单目视觉的成像原理 – 像素坐标系1.4 单目视觉三维坐标系转换 – 外参1.5 单目视觉的坐标系转换 – 从世界坐标点到像素坐标1.6 单目视觉的特性2. 视觉传感器的标定2.1 视觉…...

分享148个ASP源码,总有一款适合您

ASP源码 分享148个ASP源码&#xff0c;总有一款适合您 下面是文件的名字&#xff0c;我放了一些图片&#xff0c;文章里不是所有的图主要是放不下...&#xff0c; 148个ASP源码下载链接&#xff1a;https://pan.baidu.com/s/1e2PvBmXxZA8C3IelkP8ZtQ?pwdj7lp 提取码&#x…...

Java线程的生命周期的五种状态

前面在《有关Java多线程的几个概念》&#xff08;https://blog.csdn.net/helloworldchina/article/details/128753898&#xff09;讲述了Java线程的生命周期的五种状态。在这里再详述一下线程的5种状态。 在java中&#xff0c;任何对象都要有生命周期&#xff0c;线程也一样&a…...

springboot自定义拦截器的简单使用和一个小例子

springboot自定义拦截器的使用1. 自定义拦截器2. 拦截器登录验证的小demo2.1 配置pom.xml2.2 创建User的bean组件2.3 创建需要的表单页面以及登录成功的页面2.4 编写controller映射关系2.5 自定义拦截器类&#xff0c;实现intercepetor接口2.6注册添加拦截器&#xff0c;自定义…...

C语言中的精确宽度类型

概述 在 C 语言标准库 <stdint.h> 中定义了一系列精确宽度的整数类型&#xff0c;这些类型保证了它们的位数宽度&#xff0c;从而允许编写跨平台的可移植代码。以下是一些常用的精确宽度整数类型&#xff1a; int8_t: 8位有符号整数uint8_t: 8位无符号整数int16_t: 16位…...

[C++]智能指针的实现:auto_ptr, shared_ptr, weak_ptr

auto_ptr 简介 交换资源的管理权&#xff0c;将被拷贝资源置空&#xff0c;很危险&#xff0c;一般被禁用 代码实现 namespace memory {template<typename T>class auto_ptr{public:auto_ptr(T* ptr):_ptr(ptr){}auto_ptr(auto_ptr<T>& ap){_ptr ap._ptr;…...

K8S join 证书过期 节点报错:certificate has expired or is not yet valid

问题场景&#xff1a; 我是因为虚拟机&#xff0c;挂起了几天&#xff0c;再打开join节点的时候报错&#xff1a; 证书过期报错 ...其他输出 I0427 15:33:56.626776 93338 token.go:215] [discovery] Failed to request cluster-info, will try again: Get "https://…...

人体姿态估计学习

人体姿态估计 1.绪论 人体姿态估计是计算机视觉中一个很基础的问题。从名字的角度来看&#xff0c;可以理解为对“人体”的姿态&#xff08;关键点&#xff0c;比如头&#xff0c;左手&#xff0c;右脚等&#xff09;的位置估计。 一般我们可以这个问题再具体细分成4个任务&…...

VMware与CentOS的安装

VMware与CentOS的安装 第一章 VMware安装第二章 CentOS上网虚拟机网络IP修改地址配置修改主机名和hosts文件修改主机名称配置Linux克隆机主机名称映射hosts文件&#xff0c;打开/etc/hosts 安装Xshell7和Xftp7 第一章 VMware安装 VMware Workstation Pro 安装包 …...

【强训笔记】day13

NO.1 代码实现&#xff1a; #include <iostream>#include<string>using namespace std;int n,k,t; string s;int func() {int ret0;for(int i0;i<n;i){char chs[i];if(chL) ret-1;else{if(i-1>0&&i-2>0&&s[i-1]W&&s[i-2]W) retk…...

Python机器翻译包Translate:多语种翻译利器

Python机器翻译包Translate&#xff1a;多语种翻译&#xff0c;效果卓越&#xff01; 随着全球化的不断深化&#xff0c;跨语言沟通成为人们越来越重要的需求。而如今&#xff0c;Python作为一种功能强大的编程语言&#xff0c;正以其独特的优势和实用性&#xff0c;在机器翻译…...

C++使用单链表实现一元多项式的加,乘操作

相邀再次喝酒 待 葡萄成熟透 但是命运入面 每个邂逅 一起走到了 某个路口 是敌与是友 各自也没有自由 位置变了 各有队友 首先&#xff0c;按照惯例&#xff0c;十分欢迎大家边听歌边观看本博客&#xff01;&#xff01; 最佳损友 - 陈奕迅 - 单曲 - 网易云音乐 (163.com) 一…...

LLM分布式训练---混合并行(2D 3D)

近年来&#xff0c;随着Transformer、MOE架构的提出&#xff0c;使得深度学习模型轻松突破上万亿规模参数&#xff0c;传统的单机单卡模式已经无法满足超大模型进行训练的要求。因此&#xff0c;我们需要基于单机多卡、甚至是多机多卡进行分布式大模型的训练。 而利用AI集群&a…...

前端如何设置div视图可滚动

前端如何设置div视图可滚动&#xff1f; 要使一个 div 元素可滚动&#xff0c;你可以通过设置其 overflow CSS 属性来实现。以下是如何设置的简单步骤&#xff1a; HTML 结构&#xff1a; html复制代码 <div class"scrollable-div"> <!-- 这里放入大量的…...

open-vm-tools使用虚机的拷贝/粘切

open-vm-tools 是一组用于 VMware 虚拟机中的开源工具,它们提供了一些与虚拟机操作和管理相关的功能。这些工具与 VMware 虚拟化平台集成,可以在虚拟机中提供更好的性能和功能。以下是一些 open-vm-tools 提供的功能: 1. 虚拟机增强功能: open-vm-tools 提供了与 VMware 虚…...

PCB板上的Mark点

PCB生产中Mark点设计 1.pcb必须在板长边对角线上有一对应整板定位的Mark点,板上集成电路引脚中心距小于0.65mm的芯片需在集成电路长边对角线上有一对对应芯片定位的Mark点;pcb双面都有贴片件时,则pcb的两面都按此条加Mark点。 2.pcb边需留5mm工艺边(机器夹持PCB最小间距要求…...