Java线程池七大参数详解和配置(面试重点!!!)

一、corePoolSize核心线程数

二、maximunPoolSize最大线程数

三、keepAliveTime空闲线程存活时间

四、unit空闲线程存活时间的单位

五、workQueue线程工作队列

1、ArrayBlockingQueue FIFO有界阻塞队列

2、LinkedBlockingQueue FIFO无限队列

3、PriorityBlockingQueue VIP

4、SynchronousQueue不缓存任务的阻塞队列

六、threadFactory线程工厂

七、handler超出线程数和工作队列时候的任务请求处理策略

策略1:ThreadPoolExecutor.AbortPolicy(默认)拒绝执行

策略2:ThreadPoolExecutor.CallerRunsPolicy调用 execute 方法的线程本身运行任务

策略3:ThreadPoolExecutor.DiscardOldestPolicy执行程序未关闭,则删除工作队列头部的任务

策略4:ThreadPoolExecutor.DiscardPolicy无法执行的任务被简单地删除

八 ThreadPoolExecutor线程池参数设置技巧

1、ThreadPoolExecutor的重要参数

2、ThreadPoolExecutor执行顺序:

3、如何设置参数

九 真实环境实践

十 个人总结


JDK1.8线程池参数源代码:

    public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit,BlockingQueue<Runnable> workQueueRejectedExecutionHandler handler) this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueueExecutors.defaultThreadFactory(), handler);}

一、corePoolSize核心线程数

指的是核心线程大小,线程池中维护一个最小的线程数量,即使这些线程处于空闲状态,也一直存在池中,除非设置了核心线程超时时间

这也是源码中的注释说明。

/** @param corePoolSize the number of threads to keep in the pool, 
* even if they are idle, unless {@code allowCoreThreadTimeOut} is set.
*/

二、maximunPoolSize最大线程数

指的是线程池中允许的最大线程数量。当线程池中核心线程都处理执行状态,有新请求的任务:

1、工作队列未满:新请求的任务加入工作队列

2、工作队列已满:线程池会创建新线程,来执行这个任务。当然,创建新线程不是无限制的,因为会受到maximumPoolSize最大线程数量的限制。


三、keepAliveTime空闲线程存活时间

指的是空闲线程存活时间。具体说,当线程数大于核心线程数时,空闲线程在等待新任务到达的最大时间,如果超过这个时间还没有任务请求,该空闲线程就会被销毁。

可见官方注释:

/** @param keepAliveTime when the number of threads is greater than*        the core, this is the maximum time that excess idle threads*        will wait for new tasks before terminating.
*/

四、unit空闲线程存活时间的单位

是指空闲线程存活时间的单位keepAliveTime的计量单位。枚举类型TimeUnit类。


五、workQueue线程工作队列

1、ArrayBlockingQueue FIFO有界阻塞队列

基于数组的有界阻塞队列,特点FIFO(先进先出)。

当线程池中已经存在最大数量的线程时候,再请求新的任务,这时就会将任务加入工作队列的队尾,一旦有空闲线程,就会取出队头执行任务。因为是基于数组的有界阻塞队列,所以可以避免系统资源的耗尽。

那么如果出现有界队列已满,最大数量的所有线程都处于执行状态,这时又有新的任务请求,怎么办呢?

这时候会采用Handler拒绝策略,对请求的任务进行处理。后面会详细介绍。

2、LinkedBlockingQueue FIFO无限队列

基于链表的无界阻塞队列,默认最大容量Integer.MAX_VALUE( ),可认为是无限队列,特点FIFO。

关于maximumPoolSize参数在工作队列为LinkedBlockingQueue时候,是否起作用这个问题,我们需要视情况而定!

情况①:如果指定了工作队列大小,比如core=2,max=3,workQueue=2,任务数task=5,这种情况的最大线程数量的限制是有效的。

情况②:如果工作队列大小默认,这时maximumPoolSize不起作用,因为新请求的任务一直可以加到队列中。

3、PriorityBlockingQueue VIP

优先级无界阻塞队列,前面两种工作队列特点都是FIFO,而优先级阻塞队列可以通过参数Comparator实现对任务进行排序,不按照FIFO执行。

4、SynchronousQueue不缓存任务的阻塞队列

不缓存任务的阻塞队列,它实际上不是真正的队列,因为它没有提供存储任务的空间。生产者一个任务请求到来,会直接执行,也就是说这种队列在消费者充足的情况下更加适合。因为这种队列没有存储能力,所以只有当另一个线程(消费者)准备好工作,put(入队)和take(出队)方法才不会是阻塞状态。

以上四种工作队列,跟线程池结合就是一种生产者-消费者 设计模式。生产者把新任务加入工作队列,消费者从队列取出任务消费,BlockingQueue可以使用任意数量的生产者和消费者,这样实现了解耦,简化了设计。
 

六、threadFactory线程工厂

线程工厂,创建一个新线程时使用的工厂,可以用来设定线程名、是否为daemon线程等。

守护线程(Daemon Thread) 在Java中有两类线程:用户线程 (User Thread)、守护线程 (DaemonThread)。

一般建议自定义线程工厂,构建线程的时候设置线程的名称,这样就在查日志的时候就方便知道是哪个线程执行的代码。

官方使用默认的线程工厂源码如下:

    /*** The default thread factory*/static class DefaultThreadFactory implements ThreadFactory {private static final AtomicInteger poolNumber = new AtomicInteger(1);private final ThreadGroup group;private final AtomicInteger threadNumber = new AtomicInteger(1);private final String namePrefix;DefaultThreadFactory() {SecurityManager s = System.getSecurityManager();group = (s != null) ? s.getThreadGroup() :Thread.currentThread().getThreadGroup();namePrefix = "pool-" +poolNumber.getAndIncrement() +"-thread-";}public Thread newThread(Runnable r) {Thread t = new Thread(group, r,namePrefix + threadNumber.getAndIncrement(),0);if (t.isDaemon())                t.setDaemon(false);if (t.getPriority() != Thread.NORM_PRIORITY)t.setPriority(Thread.NORM_PRIORITY);return t}}

七、handler超出线程数和工作队列时候的任务请求处理策略

Java 并发超出线程数和工作队列时候的任务请求处理策略,使用了策略设计模式

策略1:ThreadPoolExecutor.AbortPolicy(默认)拒绝执行

在默认的处理策略。该处理在拒绝时抛出RejectedExecutionException,拒绝执行。

   public static class AbortPolicy implements RejectedExecutionHandler {/*** Creates an {@code AbortPolicy}.*/public AbortPolicy() { }/**         * Always throws RejectedExecutionException.** @param r the runnable task requested to be executed* @param e the executor attempting to execute this task* @throws RejectedExecutionException always*/public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {throw new RejectedExecutionException("Task " + r.toString() +" rejected from " +e.toString());}}
策略2:ThreadPoolExecutor.CallerRunsPolicy调用 execute 方法的线程本身运行任务

调用 execute 方法的线程本身运行任务。这提供了一个简单的反馈控制机制,可以降低新任务提交的速度。

    public static class CallerRunsPolicy implements RejectedExecutionHandler {/*** Creates a {@code CallerRunsPolicy}.*/public CallerRunsPolicy() { }/*** Executes task r in the caller's thread, unless the executor* has been shut down, in which case the task is discarded.** @param r the runnable task requested to be executed* @param e the executor attempting to execute this task*/public void rejectedExecution(Runnable r, ThreadPoolExecutor e)if (!e.isShutdown()) {r.run();}}}
策略3:ThreadPoolExecutor.DiscardOldestPolicy执行程序未关闭,则删除工作队列头部的任务
    public static class DiscardOldestPolicy implements RejectedExecutionHandler {/*** Creates a {@code DiscardOldestPolicy} for the given executor.*/public DiscardOldestPolicy() { }/*** Obtains and ignores the next task that the executor      * * would otherwise execute, if one is immediately available,* and then retries execution of task r, unless the executor* is shut down, in which case task r is instead discarded.     ** @param r the runnable task requested to be executed* @param e the executor attempting to execute this task*/public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {if (!e.isShutdown()) {e.getQueue().poll();e.execute(r);}     }

如果执行程序未关闭,则删除工作队列头部的任务,然后重试执行(可能再次失败,导致重复执行)。

策略4:ThreadPoolExecutor.DiscardPolicy无法执行的任务被简单地删除

无法执行的任务被简单地删除,将会丢弃当前任务,通过源码可以看出,该策略不会执行任务操作。

    public static class DiscardPolicy implements RejectedExecutionHandler {/*** Creates a {@code DiscardPolicy}.*/public DiscardPolicy() { }/*** Does nothing, which has the effect of discarding task r.** @param r the runnable task requested to be executed* @param e the executor attempting to execute this task*/public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {}    }

八 ThreadPoolExecutor线程池参数设置技巧

1、ThreadPoolExecutor的重要参数
  • corePoolSize:核心线程数
  • 核心线程会一直存活,及时没有任务需要执行
  • 当线程数小于核心线程数时,即使有线程空闲,线程池也会优先创建新线程处理
  • 设置allowCoreThreadTimeout=true(默认false)时,核心线程会超时关闭
  • queueCapacity:任务队列容量(阻塞队列)

当核心线程数达到最大时,新任务会放在队列中排队等待执行

  • maxPoolSize:最大线程数

当线程数>=corePoolSize,且任务队列已满时。线程池会创建新线程来处理任务
当线程数=maxPoolSize,且任务队列已满时,线程池会拒绝处理任务而抛出异常

  • keepAliveTime:线程空闲时间

当线程空闲时间达到keepAliveTime时,线程会退出,直到线程数量=corePoolSize
如果allowCoreThreadTimeout=true,则会直到线程数量=0

  • allowCoreThreadTimeout:允许核心线程超时
  • rejectedExecutionHandler:任务拒绝处理器

两种情况会拒绝处理任务:
当线程数已经达到maxPoolSize,切队列已满,会拒绝新任务
当线程池被调用shutdown()后,会等待线程池里的任务执行完毕,再shutdown。如果在调用shutdown()和线程池真正shutdown之间提交任务,会拒绝新任务
线程池会调用rejectedExecutionHandler来处理这个任务。如果没有设置默认是AbortPolicy,会抛出异常

ThreadPoolExecutor类有几个内部实现类来处理这类情况:

        AbortPolicy 丢弃任务,抛运行时异常
        CallerRunsPolicy 执行任务
        DiscardPolicy 忽视,什么都不会发生
        DiscardOldestPolicy 从队列中踢出最先进入队列(最后一个执行)的任务

实现RejectedExecutionHandler接口,可自定义处理器

2、ThreadPoolExecutor执行顺序:

线程池按以下行为执行任务

  1. 当线程数小于核心线程数时,创建线程。
  2. 当线程数大于等于核心线程数,且任务队列未满时,将任务放入任务队列。
  3. 当线程数大于等于核心线程数,且任务队列已满
  4. 若线程数小于最大线程数,创建线程
  5. 若线程数等于最大线程数,抛出异常,拒绝任务

3、如何设置参数

默认值

  • corePoolSize=1
  • queueCapacity=Integer.MAX_VALUE
  • maxPoolSize=Integer.MAX_VALUE
  • keepAliveTime=60s
  • allowCoreThreadTimeout=false
  • rejectedExecutionHandler=AbortPolicy()

如何来设置

  • 需要根据几个值来决定

 tasks :每秒的任务数,假设为500~1000
 taskcost:每个任务花费时间,假设为0.1s
 responsetime:系统允许容忍的最大响应时间,假设为1s

  • 做几个计算
  •         corePoolSize = 每秒需要多少个线程处理?

threadcount = tasks/(1/taskcost) =tasks*taskcout = (500~1000)*0.1 = 50~100 个线程。corePoolSize设置应该大于50

根据8020原则,如果80%的每秒任务数小于800,那么corePoolSize设置为80即可

  •         queueCapacity = (coreSizePool/taskcost)*responsetime 

计算可得 queueCapacity = 80/0.1*1 = 80。意思是队列里的线程可以等待1s,超过了的需要新开线程来执行

切记不能设置为Integer.MAX_VALUE,这样队列会很大,线程数只会保持在corePoolSize大小,当任务陡增时,不能新开线程来执行,响应时间会随之陡增。

  •         maxPoolSize = (max(tasks)- queueCapacity)/(1/taskcost)

计算可得 maxPoolSize = (1000-80)/10 = 92

(最大任务数-队列容量)/每个线程每秒处理能力 = 最大线程数

  •         rejectedExecutionHandler

根据具体情况来决定,任务不重要可丢弃,任务重要则要利用一些缓冲机制来处理

  •         keepAliveTimeallowCoreThreadTimeout

采用默认通常能满足

以上都是理想值,实际情况下要根据机器性能来决定。如果在未达到最大线程数的情况机器cpu load已经满了,则需要通过升级硬件(呵呵)和优化代码,降低taskcost来处理。

九 真实环境实践


import org.apache.commons.lang3.concurrent.BasicThreadFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;import java.util.concurrent.RejectedExecutionHandler;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.ThreadPoolExecutor;/*** 线程池配置** @author oldlu**/
@Configuration
public class ThreadPoolConfig {// 核心线程池大小@Value("${threadPoolConfig.corePoolSize}")private int corePoolSize;// 最大可创建的线程数@Value("${threadPoolConfig.maxPoolSize}")private int maxPoolSize;// 队列最大长度@Value("${threadPoolConfig.queueCapacity}")private int queueCapacity;// 线程池维护线程所允许的空闲时间@Value("${threadPoolConfig.keepAliveSeconds}")private int keepAliveSeconds;// 线程池对拒绝任务(无线程可用)的处理策略@Value("${threadPoolConfig.rejectedExecutionHandler}")private String rejectedExecutionHandler;@Bean(name = "threadPoolTaskExecutor")@ConditionalOnProperty(prefix = "threadPoolTaskExecutor", name = "enabled", havingValue = "true")public ThreadPoolTaskExecutor threadPoolTaskExecutor() {ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();executor.setMaxPoolSize(maxPoolSize);executor.setCorePoolSize(corePoolSize);executor.setQueueCapacity(queueCapacity);executor.setKeepAliveSeconds(keepAliveSeconds);RejectedExecutionHandler handler;if (rejectedExecutionHandler.equals("CallerRunsPolicy")) {handler = new ThreadPoolExecutor.CallerRunsPolicy();} else if (rejectedExecutionHandler.equals("DiscardOldestPolicy")) {handler = new ThreadPoolExecutor.DiscardOldestPolicy();} else if (rejectedExecutionHandler.equals("DiscardPolicy")) {handler = new ThreadPoolExecutor.DiscardPolicy();} else {handler = new ThreadPoolExecutor.AbortPolicy();}executor.setRejectedExecutionHandler(handler);return executor;}/*** 执行周期性或定时任务*/@Bean(name = "scheduledExecutorService")protected ScheduledExecutorService scheduledExecutorService() {return new ScheduledThreadPoolExecutor(corePoolSize,new BasicThreadFactory.Builder().namingPattern("schedule-pool-%d").daemon(true).build()) {@Overrideprotected void afterExecute(Runnable r, Throwable t) {super.afterExecute(r, t);Threads.printException(r, t);}};}
}

十 个人总结

Java-如何合理的设置线程池大小
想要合理配置线程池线程数的大小,需要分析任务的类型,任务类型不同,线程池大小配置也不同。

配置线程池的大小可根据以下几个维度进行分析来配置合理的线程数:

任务性质可分为:CPU密集型任务IO密集型任务混合型任务
任务的执行时长。
任务是否有依赖——依赖其他系统资源,如数据库连接等。


CPU密集型任务(普通计算)
尽量使用较小的线程池,一般为CPU核心数+1
因为CPU密集型任务使得CPU使用率很高,若开过多的线程数,只能增加上下文切换的次数,因此会带来额外的开销。

IO密集型任务(文件,数据库操作)
可以使用稍大的线程池,一般为2*CPU核心数+1
因为IO操作不占用CPU,不要让CPU闲下来,应加大线程数量,因此可以让CPU在等待IO的时候去处理别的任务,充分利用CPU时间。

混合型任务:
可以将任务分成IO密集型和CPU密集型任务,然后分别用不同的线程池去处理。
只要分完之后两个任务的执行时间相差不大,那么就会比串行执行来的高效。
因为如果划分之后两个任务执行时间相差甚远,那么先执行完的任务就要等后执行完的任务,最终的时间仍然取决于后执行完的任务,而且还要加上任务拆分与合并的开销,得不偿失

依赖其他资源
如某个任务依赖数据库的连接返回的结果,这时候等待的时间越长,则CPU空闲的时间越长,那么线程数量应设置得越大,才能更好的利用CPU。

借鉴别人的文章 对线程池大小的估算公式:

   最佳线程数目 = ((线程等待时间+线程CPU时间)/线程CPU时间 )* CPU数目


比如平均每个线程CPU运行时间为0.5s,而线程等待时间(非CPU运行时间,比如IO)为1.5s,CPU核心数为8,那么根据上面这个公式估算得到:((0.5+1.5)/0.5)*8=32。

可以得出一个结论:

线程等待时间所占比例越高,需要越多线程。线程CPU时间所占比例越高,需要越少线程。
 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/244320.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

SQL Server多数据表之间的数据查询和分组查询

文章目录 一、多数据表之间的数据查询1.1内连接查询&#xff08;Inner join&#xff09;1.2 左外连接 (LEFT JOIN):1.3右外连接 (RIGHT JOIN):1.4. 全外连接 (FULL OUTER JOIN):1.5 交叉连接 (CROSS JOIN):1.6 自连接 (SELF JOIN):1.7 子查询: 二、分组查询2.1 分组查询2.2 查询…

通信、机房、IT运维、云计算类可视化大屏,大气直观漂亮。

通信、机房、IT运维和云计算可视化大屏的作用主要体现在以下几个方面&#xff1a; 实时监控&#xff1a;可视化大屏可以实时显示通信、机房、IT运维和云计算系统的运行状态和性能指标。通过图表、仪表盘、地图等可视化元素&#xff0c;可以直观地展示各种数据&#xff0c;如网…

【STM32】STM32F4中USB的CDC虚拟串口(VCP)使用方法

文章目录 一、前言二、STM32CubeMX生成代码2.1 选择芯片2.2 配置相关模式2.3 设置时钟频率2.4 生成代码2.5 编译并下载代码2.6 结果2.7 问题 三、回环测试3.1 打开工程3.2 添加回环代码3.3 编译烧录并测试 四、出现问题和解决方法4.1 烧录总是要自己插拔USB4.2 自己生成的工程没…

初识node.js(使用)

文章目录 项目目录介绍和运行流程1.index.html&#x1f447;2.整个项目的核心入口文件其实是main.js3.App.vue 组件化开发 和 根组件普通组件的注册1.局部注册2.全局注册 综合案例 项目目录介绍和运行流程 1.index.html&#x1f447; <!DOCTYPE html> <html lang&quo…

数据结构:3_栈和队列

栈和队列 一.栈 1. 栈的概念及结构 栈&#xff1a;一种特殊的线性表&#xff0c;其只允许在固定的一端进行插入和删除元素操作。**进行数据插入和删除操作的一端称为栈顶&#xff0c;另一端称为栈底。**栈中的数据元素遵守后进先出LIFO&#xff08;Last In First Out&#x…

RabbitMQ系列之交换机的使用

&#x1f389;&#x1f389;欢迎来到我的CSDN主页&#xff01;&#x1f389;&#x1f389; &#x1f3c5;我是君易--鑨&#xff0c;一个在CSDN分享笔记的博主。&#x1f4da;&#x1f4da; &#x1f31f;推荐给大家我的博客专栏《RabbitMQ系列之交换机的使用》。&#x1f3af;&…

【C++】list容器功能模拟实现

介绍 上一次介绍了list队容器的迭代器模拟&#xff0c;这次模拟实现list的简单功能&#xff0c;尤其要注意构造函数、析构函数、以及赋值运算符重载的实现。 list容器需要接纳所有类型的数据&#xff0c;因此&#xff0c;结构设置与迭代器设置同理&#xff0c;需要引入结点&…

java web mvc-04-Apache Wicket

拓展阅读 Spring Web MVC-00-重学 mvc mvc-01-Model-View-Controller 概览 web mvc-03-JFinal web mvc-04-Apache Wicket web mvc-05-JSF JavaServer Faces web mvc-06-play framework intro web mvc-07-Vaadin web mvc-08-Grails 开源 The jdbc pool for java.(java …

Confluence6+mysql5.7破j安装避坑详细记录

目录 一、前言 二、下载与安装 1、版本和安装环境 2、安装数据库 3、配置数据库 4、安装confluence 三、Pj confluence 1、选择语言和产品安装 2、Pj 3、上传mysql驱动 4、重启Confluence服务继续安装 四、Confluence重启卸载方法 重启方法 方法一 方法二 卸载…

no space left on device

异常 在运行中容器异常中止,重新启动后出现的问题 [rootdxx xxx]# docker start 29258e5b52c9 Error response from daemon: write /var/lib/docker/containers/29258e5b52c9053ffa91afba5a3e4fc8519e7c99c7a184466bcdf236653bf10a/hash3291289824: no space left on device Er…

【Linux】Linux系统编程——pwd命令

文章目录 1.命令概述2.命令格式3.常用选项4.相关描述5.参考示例 1.命令概述 pwd&#xff08;Print Working Directory&#xff09;命令用于显示用户当前工作目录的完整路径。这是一个常用的命令&#xff0c;帮助用户确定他们目前所在的目录位置。 2.命令格式 基本的 pwd 命令…

动静态库的理解、制作、使用。

一.动静态库的理解。 1.什么是库&#xff1f; 代码是无穷无尽的&#xff0c;当程序猿在写一些项目时&#xff0c;未必所有代码亲历亲为&#xff0c;他们可以在网上寻找大佬写过的一些有关需求的代码&#xff0c;这些代码可以让他们拿过来直接使用&#xff0c;而省去了许多精力…

android使用相机 intent.resolveActivity returns null

问题 笔者使用java进行android开发&#xff0c;启动相机时 intent.resolveActivity returns null takePictureIntent.resolveActivity(getPackageManager()) null详细问题 笔者使用如下代码启动相机 // 启动相机SuppressLint("LongLogTag")private void dispatc…

大数据开发之Spark(RDD弹性分布式数据集)

第 1 章&#xff1a;rdd概述 1.1 什么是rdd rdd&#xff08;resilient distributed dataset&#xff09;叫做弹性分布式数据集&#xff0c;是spark中最基本的数据抽象。 代码中是一个抽象类&#xff0c;它代表一个弹性的、不可变、可分区、里面的元素可并行计算的集合。 1.1…

Pycharm运行提示(运行‘Python测试(00.py内)‘(u)

为什么有时候我在pycharm中运行代码会出现图片中的问题&#xff1f; 我们该如何改过来&#xff1f; 很简单 点击文件-设置 点击Python集成工具&#xff0c;在默认测试运行程序里修改为Unittest即可 再次运行代码就会显示正常的运行 你的pycharm可能是英文 如何英文变中文&…

idea——git提交到本地记录如何退回/删除

目录 一、git提交到本地记录如何退回/删除 一、git提交到本地记录如何退回/删除 git提交到本地记录&#xff0c;如下图【更新】记录&#xff0c;表示本次提交到git本地需要退回/删除的操作&#xff1a; 选中项目&#xff0c;右键点击【git】——>【Show History】——>…

书生·浦语大模型实战营-学习笔记4

XTuner 大模型单卡低成本微调实战 Finetune简介 常见的两种微调策略&#xff1a;增量预训练、指令跟随 指令跟随微调 数据是一问一答的形式 对话模板构建 每个开源模型使用的对话模板都不相同 指令微调原理&#xff1a; 由于只有答案部分是我们期望模型来进行回答的内容…

2024.1.24 GNSS 学习笔记

1.伪距观测值公式 2.载波相位观测值公式 3.单点定位技术(Single Point Positionin, SPP) 仅使用伪距观测值&#xff0c;不使用其他的辅助信息获得ECEF框架下绝对定位技术。 使用广播星历的轨钟进行定位&#xff0c;考虑到轨钟的米级精度&#xff0c;所以对于<1米的误差&…

【Android】在WSA安卓子系统中进行新实验性功能试用与抓包(2311.4.5.0)

前言 在根据几篇22和23的WSA抓包文章进行尝试时遇到了问题&#xff0c;同时发现新版Wsa的一些实验性功能能优化抓包配置时的一些步骤&#xff0c;因而写下此篇以作记录。 Wsa版本&#xff1a;2311.40000.5.0 本文出现的项目&#xff1a; MagiskOnWSALocal MagiskTrustUserCer…

【刷题】 leetcode 面试题 01.06 字符串压缩

字符串压缩 字符串压缩思路一&#xff08;双指针顺畅版&#xff09;思路二&#xff08;sprintf函数巧解版&#xff09; Thanks♪(&#xff65;ω&#xff65;)&#xff89;谢谢阅读下一篇文章见&#xff01;&#xff01;&#xff01; 字符串压缩 来看题目&#xff1a; 根据题目…