Android多线程学习:线程池(一)
一、概念
线程池:创建并维护一定数量的空闲线程,当有需要执行的任务,就交付给线程池中的一个线程,任务执行结束后,该线程也不会死亡,而是回到线程池中重新变为空闲状态。
线程池优点:
1、重用线程池中的线程,避免频繁创建和销毁线程所带来的内存开销。
2、有效控制线程的最大并发数,避免因线程之间抢占资源而导致的阻塞现象。
3、能够对线程进行简单的管理,提供定时执行以及指定时间间隔循环执行等功能。
二、线程池使用
ThreadPoolExecutor是线程池的实现,先来个小demo,核心代码如下:
private void threadPoolTest() {//创建线程池ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(2, 4 , 3, TimeUnit.SECONDS, new LinkedBlockingDeque<>(3), new ThreadPoolExecutor.DiscardOldestPolicy());for (int i = 0; i < 5; i++) {String data = "task@" + i;Log.i(TAG, data);//提交任务threadPoolExecutor.execute(new ThreadPoolRunnable(data));}Log.i(TAG, "start test ---------------");
}class ThreadPoolRunnable implements Runnable {private Object taskData;public ThreadPoolRunnable(Object taskData) {this.taskData = taskData;}@Overridepublic void run() {Log.i(TAG, "run - runnableData: " + taskData + " | " + Thread.currentThread());try {Thread.sleep(500);} catch (InterruptedException e) {e.printStackTrace();}taskData = null;}
}
三、线程池创建参数说明
public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit,BlockingQueue<Runnable> workQueue,ThreadFactory threadFactory,RejectedExecutionHandler handler) {
}
-
corePoolSize (int ):核心线程的个数。线程池中有两类线程,核心线程和非核心线程。核心线程默认情况下会一直存在于线程池中,即使这个核心线程什么都不干(铁饭碗),而非核心线程如果长时间的闲置,就会被销毁(临时工)。如果调用了线程池的
prestartAllCoreThreads()或prestartCoreThread()方法,线程池会提前创建并启动所有核心线程。 -
maximumPoolSize (int ):线程池所能容纳的最大线程数。当活动线程数达到这个数值后,后续的新任务将会被阻塞。该值等于核心线程数量 + 非核心线程数量。如果任务队列使用无界的阻塞队列,该参数没有什么效果。
有界阻塞队列和无界阻塞队列含义和区别:
阻塞队列有一个非常重要的属性:容量的大小,分为有界和无界两种。无界阻塞队列:队列容量很大,近似无上界,例如 LinkedBlockingQueue 的上限是 Integer.MAX_VALUE,约为 2 的 31 次方,是非常大的一个数,可以近似认为是无限容量。
有界阻塞队列:队列容量有上界,例如 ArrayBlockingQueue 如果容量满了,也不会扩容,所以一旦满了就无法再往里放数据了。
-
keepAliveTime (long):非核心线程闲置时的超时时长,超过这个时长,非核心线程就会被回收。如果设置
allowCoreThreadTimeOut(true),则会也作用于核心线程。 -
unit (TimeUnit ):
keepAliveTime的时间单位。 -
workQueue(BlockingQueue):线程池中的任务队列,通过线程池的
execute方法提交的Runnable对象存储在这个参数中,遵循先进先出原则。 -
threadFactory(ThreadFactory ):创建线程的工厂 ,用于批量创建线程,统一在创建线程时设置一些参数,如是否守护线程、线程的优先级等。如果不指定,默认使用
Executors.defaultThreadFactory()来创建线程,线程具有相同的NORM_PRIORITY优先级并且是非守护线程。
private 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(RejectedExecutionHandler ):拒绝处理策略,线程数量大于最大线程数就会采用拒绝处理策略。
四种拒绝处理的策略如下:
- ThreadPoolExecutor.AbortPolicy:默认拒绝处理策略,丢弃任务并抛出RejectedExecutionException异常。
- ThreadPoolExecutor.DiscardPolicy:丢弃新来的任务,但是不抛出异常。
- ThreadPoolExecutor.DiscardOldestPolicy:丢弃队列头部(最旧的)的任务,然后重新尝试执行程序(如果再次失败,重复此过程)。
- ThreadPoolExecutor.CallerRunsPolicy:由调用线程处理该任务。
使用总结:
demo中的构造代码如下,声明了2个核心进程,最大进程数为4,非核心进程空闲超时时长是3s。阻塞队列使用LinkedBlockingDeque,并指定大小为3,防止队列无限膨胀,拒绝处理策略为DiscardOldestPolicy,丢弃队列头部(最旧的)的任务。
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(2, 4 , 3, TimeUnit.SECONDS, new LinkedBlockingDeque<>(3), new ThreadPoolExecutor.DiscardOldestPolicy());
四、线程池常用阻塞队列(BlockingQueue)

1、ArrayBlockingQueue(常用)

- 基于数组的阻塞队列。
ArrayBlockingQueue内部,维护了一个定长数组,以便缓存队列中的数据对象,这是一个常用的阻塞队列。 ArrayBlockingQueue在生产者放入数据和消费者获取数据,都是共用同一个锁对象,由此也意味着两者无法真正并行运行,没有实现读写分离。- 在创建
ArrayBlockingQueue时,我们还可以控制对象的内部锁是否采用公平锁,默认采用非公平锁。
ArrayBlockingQueue 使用 ReentrantLock 的公平锁和非公平锁来实现该功能。简单理解就是,ReentrantLock 内部会维护一个有先后顺序的等待队列,假如有五个任务一起过来,都被阻塞了。如果是公平的,则等待队列中等待最久的任务就会先进入阻塞队列。如果是非公平的,那么这五个线程就需要抢锁,谁先抢到,谁就先进入阻塞队列。
2、LinkedBlockingQueue(常用)

- 由链表结构组成的有界阻塞队列。
LinkedBlockingQueue不指定队列的大小时,默认值是Integer.MAX_VALUE。但是,建议指定一个固定大小。因为,如果生产者的速度比消费者的速度大的多的情况下,这会导致阻塞队列一直膨胀,直到系统内存被耗尽。 LinkedBlockingQueue实现了读写分离,可以实现数据的读和写互不影响,这在高并发的场景下,对于效率的提高无疑是非常巨大的。
3、SynchronousQueue

- 这是一个没有缓冲的无界队列,
size为0。当执行插入元素的操作时,必须等待一个取出操作。也就是说,put元素的时候,必须等待take操作。 - 适用于并发任务不大,而且生产者和消费者的速度相差不多的场景下,直接把生产者和消费者对接,不用经过队列的入队出队这一系列操作,效率上会高一些。
Excutors.newCachedThreadPool方法用的就是这种队列,我们还可以控制对象的内部锁是否采用公平锁,默认采用非公平锁。
4、PriorityBlockingQueue

- 这是一个支持优先级排序的无界队列。
- 可以指定初始容量大小(注意初始容量并不代表最大容量),或者不指定,默认大小为
11。也可以传入一个比较器,把元素按一定的规则排序,不指定比较器的话,默认是自然顺序。 PriorityBlockingQueue是基于二叉树最小堆实现的,每当取元素的时候,就会把优先级最高的元素取出来。
5、DelayQueue
- 一个带有延迟时间的无界阻塞队列,队列中的元素,只有等延时时间到了,才能取出来。此队列一般用于过期数据的删除,或任务调度。
五、线程池常用方法
- execute(Runnable run):提交任务,交由线程池调度;
- shutdown():关闭线程池,等待任务执行完成;
- shutdownNow():关闭线程池,不等待任务执行完成;
- getTaskCount():返回线程池找中所有任务的数量 (已完成的任务+阻塞队列中的任务);
- getCompletedTaskCount():返回线程池中已执行完成的任务数量 (已完成的任务);
- getPoolSize():返回线程池中已创建线程数量;
- getActiveCount():返回当前正在运行的线程数量;
- terminated():线程池终止时执行的策略。
六、线程池状态
ThreadPoolExecutor类中使用了一些final int常量变量来表示线程池的状态 :
private static final int RUNNING = -1 << COUNT_BITS;
private static final int SHUTDOWN = 0 << COUNT_BITS;
private static final int STOP = 1 << COUNT_BITS;
private static final int TIDYING = 2 << COUNT_BITS;
private static final int TERMINATED = 3 << COUNT_BITS;
1、RUNNING
- 线程池创建后处于RUNNING状态。
- 线程池能够接收新任务,也能够对已经添加的任务进行处理。
2、SHUTDOWN
- 线程池已经被关闭了,不再接收新任务;但是,其还是会处理队列中的剩余的任务。
- 调用线程池的shutdown()方法后,线程池的状态就会由RUNNING转为SHUTDOWN。
3、STOP:
- 线程池处于STOP状态,此时线程池不再接收新任务,不处理已经添加进来的任务,并且会中断正在处理的任务。
- 调用线程池的
shutdownNow()方法后,线程池的状态就会由RUNNING或SHUTDOWN转为STOP;
4、TIDYING:
workCount(有效线程数)为0。- 线程池被下达关闭命令后,如果当前所有的任务都已经终止了(这个终止可以表示执行结束,也可以表示强制中断,也可以表示被丢弃) ,那么线程就会进入TIDYING状态;当线程池变为TIDYING状态时,会执行钩子函数terminated()。terminated()在ThreadPoolExecutor类中是空的,若用户想在线程池变为TIDYING时进行相应的处理,可以通过重载terminated()函数来实现。
- 如果线程状态已经是SHUTDOWN了,并且线程中以及队列中都没有任务时,线程池就会由SHUTDOWN转为TIDYING;如果线程池状态为STOP,那么当线程池把所有的任务都给清理干净时,线程池就会由STOP转为TIDYING。
5、TERMINATED:
- 线程池就结束了;线程池就不能重新启动了。
- 如果线程池处于TIDYING状态,那么当线程池执行完terminated()方法后,线程池状态就会由TIDYING转为TERMINTED。

七、线程池分类
1、newFixedThreadPool()
public static ExecutorService newFixedThreadPool(int nThreads) {return new ThreadPoolExecutor(nThreads, nThreads,0L, TimeUnit.MILLISECONDS,new LinkedBlockingQueue<Runnable>());
}
- 线程数量固定且都是核心线程:核心线程数量和最大线程数量都是
nThreads。 keepAliveTime = 0L,即使线程池中的线程空闲,也不会被回收。除非调用shutDown()或shutDownNow()去关闭线程池。- 可以更快响应外界的请求,且任务阻塞队列为无边界队列(
LinkedBlockingQueue()链表结构的阻塞队列),意味着任务可以无限加入线程池。 - 可控制线程最大并发数。
2、newScheduledThreadPool()
public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {return new ScheduledThreadPoolExecutor(corePoolSize);
}
//默认闲置超时回收时常
private static final long DEFAULT_KEEPALIVE_MILLIS = 10L;
public ScheduledThreadPoolExecutor(int corePoolSize) {super(corePoolSize, Integer.MAX_VALUE,DEFAULT_KEEPALIVE_MILLIS, MILLISECONDS,new DelayedWorkQueue());
}
- 核心线程数量固定,非核心线程数量无限制。
- 非核心线程闲置超过
10s会被回收。 - 主要用于执行定时任务和具有固定周期的重复任务。
3、newSingleThreadExecutor()
public static ExecutorService newSingleThreadExecutor() {return new FinalizableDelegatedExecutorService(new ThreadPoolExecutor(1, 1,0L, TimeUnit.MILLISECONDS,new LinkedBlockingQueue<Runnable>()));
}
- 核心线程数为1的线程池。确保所有任务在同一线程执行,因此不用考虑线程同步问题,从命名也可以看出来,其他为
ThreadPool线程池,当前类型为ThreadExecutor,执行线程。(相当于newFixedThreadPool传入线程个数是1)。 - 阻塞队列是无界的,可以一直接收任务 。
- 常用于不适合并发但可能引起IO阻塞性及影响UI线程响应的操作,如数据库操作、文件操作等。
4、newCachedThreadPool()
public static ExecutorService newCachedThreadPool() {return new ThreadPoolExecutor(0, Integer.MAX_VALUE,60L, TimeUnit.SECONDS,new SynchronousQueue<Runnable>());
}
- 没有核心线程,非核心线程无限,但执行完任务后,空闲超过60s则回收空闲线程。
- 使用
SynchronousQueue()队列,有新任务时使用空闲线程执行,没有空闲线程则创建新的线程来处理。 - 适合执行大量的耗时较少的任务,当所有线程闲置超过60s都会被停止,所以这时几乎不占用系统资源。
八、各类线程池使用
基础知识差不多了,可以撸代码了,以下为核心代码:
public void fixedThreadPoolTest() {Log.i(TAG, "----fixedThreadPoolTest----");ExecutorService fixedThreadPool = Executors.newFixedThreadPool(2);for (int i = 0; i < 5; i++) {String data = "task@" + i;Log.i(TAG, data);fixedThreadPool.execute(new ThreadPoolRunnable(data));}
}public void cachedThreadPoolTest() {Log.i(TAG, "----cachedThreadPoolTest----");ExecutorService cachedThreadPool = Executors.newCachedThreadPool();for (int i = 0; i < 5; i++) {String data = "task@" + i;Log.i(TAG, data);cachedThreadPool.execute(new ThreadPoolRunnable(data));}
}public void singleThreadExecutorTest() {Log.i(TAG, "----singleThreadExecutorTest----");ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor();for (int i = 0; i < 5; i++) {String data = "task@" + i;Log.i(TAG, data);singleThreadExecutor .execute(new ThreadPoolRunnable(data));}
}public void scheduledThreadPoolTest() {Log.i(TAG, "----scheduledThreadPoolTest----");//这里创建的是ScheduledExecutorService对象,ScheduledExecutorService是ExecutorService的子类mScheduledThreadPool = Executors.newScheduledThreadPool(2);for (int i = 0; i < 5; i++) {String data = "task@" + i;Log.i(TAG, data);// 1000ms后执行runnablemScheduledThreadPool.schedule(new ThreadPoolRunnable(data), 1000, TimeUnit.MILLISECONDS);}
}public void scheduledAtFixedRateTest() {Log.i(TAG, "----scheduledAtFixedRateTest----");//这里创建的是ScheduledExecutorService对象,ScheduledExecutorService是ExecutorService的子类mScheduledThreadPool = Executors.newScheduledThreadPool(2);// 1s后,每2s执行一次runnablemScheduledThreadPool.scheduleAtFixedRate(new ThreadPoolRunnable(666), 1000, 2000, TimeUnit.MILLISECONDS);
}public void scheduledCancelTest() {Log.i(TAG, "----scheduledCancelTest----");if (mScheduledThreadPool != null) {mScheduledThreadPool.shutdown();}
}class ThreadPoolRunnable implements Runnable {private Object taskData;public ThreadPoolRunnable(Object taskData) {this.taskData = taskData;}@Overridepublic void run() {Log.i(TAG, "run - runnableData: " + taskData + " | " + Thread.currentThread());try {Thread.sleep(500);} catch (InterruptedException e) {e.printStackTrace();}taskData = null;}
}
运行结果:

cachedThreadPoolTest函数,看下图结果可知,一共新建了5个线程来执行这5个任务,所以newCachedThreadPoo()只适合耗时较短的任务,否则会一直创建新线程。




参考文章:
线程池10:线程池的5种状态;
常用阻塞队列 BlockingQueue 有哪些?
Android多线程:理解和简单使用总结
Android 线程池
全方位解析-Android中的线程池
相关文章:
Android多线程学习:线程池(一)
一、概念 线程池:创建并维护一定数量的空闲线程,当有需要执行的任务,就交付给线程池中的一个线程,任务执行结束后,该线程也不会死亡,而是回到线程池中重新变为空闲状态。 线程池优点: 1、重用…...
网络安全(黑客技术)—小白自学笔记
1.网络安全是什么 网络安全可以基于攻击和防御视角来分类,我们经常听到的 “红队”、“渗透测试” 等就是研究攻击技术,而“蓝队”、“安全运营”、“安全运维”则研究防御技术。 2.网络安全市场 一、是市场需求量高; 二、则是发展相对成熟入…...
掌握核心技巧就能创建完美的目录!如何在Word中自动创建目录
目录是Word布局的一个重要因素,尤其是在编写较长的文档时。那么,你如何在你的作品中添加目录呢?在这篇文章中,我将分享一些基于Word2016自动创建目录的经验。希望它能或多或少地帮到你。 自动创建目录 1、输入目录文本的名称&am…...
正则表达式中re.match、re.search、re.findall的用法和区别
这位作者的例子写的非常好,记录一下,目前用到的比较多的是findall 正则表达式中re.match、re.search、re.findall的用法和区别_<re.match object; span(0, 270), match<a href"/-CSDN博客...
算法题:买卖股票的最佳时机含手续费(动态规划解法贪心解法-详解)
这道题有两种解法:动态规划 or 贪心算法。 贪心算法的提交结果要比动态规划好一些,总体上动态规划的解法更容易想到。(完整题目附在了最后) 1、动态规划解法 设置两个数,dp[0]表示遍历到股票prices[i]时手里没有股…...
【gcc】RtpTransportControllerSend学习笔记 4:码率分配
本文是woder大神 的文章的学习笔记。 大神的webrtc源码分析(8)-拥塞控制(上)-码率预估 详尽而具体,堪称神作。 gcc保障带宽公平性,预估码率后要分配码率,实现qos效果: webrtc源码分析(9)-拥塞控制(下)-码率分配 是 woder 大神进一步给出的另一篇神作。 本文是对(https://w…...
「专题速递」AR协作、智能NPC、数字人的应用与未来
元宇宙是一个融合了虚拟现实、增强现实、人工智能和云计算等技术的综合概念。它旨在创造一个高度沉浸式的虚拟环境,允许用户在其中交互、创造和共享内容。在元宇宙中,人们可以建立虚拟身份、参与虚拟社交,并享受无限的虚拟体验。 作为互联网大…...
什么是基于意图的网络(IBN)
基于意图的网络是一种网络技术,它根据业务意图(来自网络管理员的服务请求)配置 IT 基础架构,无需任何人工干预,它不断提供关键的网络见解,并不断调整硬件配置以确保满足意图,它将网络从以设备为…...
知识增强语言模型提示 零样本知识图谱问答10.8
知识增强语言模型提示 零样本知识图谱问答 摘要介绍相关工作方法零样本QA的LM提示知识增强的LM提示与知识问题相关的知识检索 摘要 大型语言模型(LLM)能够执行 零样本closed-book问答任务 ,依靠其在预训练期间存储在参数中的内部知识。然而&…...
虚拟现实项目笔记:SDK、Assimp、DirectX Sample Browser、X86和X64
文章目录 SDK是什么Assimp是什么DirectX Sample Browser是什么X86和X64生成解决方案和重新生成解决方案 SDK是什么 SDK是Software Development Kit的英文缩写,意思是软件开发包。 软件开发包中往往包含有多种辅助进行软件开发的内容,包括一些软件开发工…...
openwrt rm500u ncm方式拨号步骤记录
1.进入设备页面 用户名:root 2.创建接口 3.配置接口 国内APN 信息 中国移动APN:CMNET 中国联通APN:3GNET 中国电信APN:CTNET 4.防火墙配置 5.点击Save&Apply 6.配置完成后重启设备。重新进入设备页面,可以看…...
使用js代码将一个值为“1=增量,2=全量“的字符串转化为一个数组,数据格式为[{value:““,label:“‘‘}]
const str "1增量,2全量"; const arr str.split(",").map(item > {const [value, label] item.split("");return { value, label}; });...
图片调色盘
图片预览 配置安装 Color-Thief 安装包使用文档 yarn add colorthief -S // npm install colorthief --save代码 <template><div class"img-thief"><div class"container"><div class"thief-item" v-for"(item, in…...
一文读懂Base64
这几天在和第三方交互的时候,对方返回的数据是base64格式的数据,所以这两天又彻底捋了下Base64的来龙去脉。之前看过一篇文章说的非常好(再找到给加上链接),我在这不详细说明了,只说转换过程。 还是使用中…...
CCF CSP认证 历年题目自练 Day20
题目一 试题编号: 201903-1 试题名称: 小中大 时间限制: 1.0s 内存限制: 512.0MB 问题描述: 题目分析(个人理解) 常规题目,先看输入,第一行输入n表示有多少数字&am…...
【Overload游戏引擎分析】从视图投影矩阵提取视锥体及overload对视锥体的封装
overoad代码中包含一段有意思的代码,可以从视图投影矩阵逆推出摄像机的视锥体,本文来分析一下原理 一、平面的方程 视锥体是用平面来表示的,所以先看看平面的数学表达。 平面方程可以由其法线N(A, B, C)和一个点Q(x0,…...
vue全局事件总线是什么?有什么用?解决了什么问题,与pinia有什么区别?
全局事件总线快速入门 概念基本概念(是什么?)核心概念 核心特性和优势(有什么用?)解决了什么问题?主要优势是什么? 案例演示?传递数据-案例演示传递事件-案例演示 与pinia有什么区别?…...
【debian 12】:debian系统切换中文界面
目录 目录 项目场景 基础参数 原因分析 解决方案 1.ctrlaltT 打开终端 2.查询当前语言环境(我的已经设置成了中文 zh_CN.UTF-8) 3.打开语言配置界面 4.最后一步:重启 不要放弃任何一个机会! 项目场景: 这两…...
es官方为我们提供的堆内存保护机制-熔断器( breaker )
总熔断器(相当于似乎总闸) 参数: indices.breaker.total.use_real_memory 默认值:true 在 elasticsearch.yml中配置。 参数: indices.breaker.total.limit 如果 indices.breaker.total.use_real_memory : true, in…...
靶场通关记录
OSCP系列靶场-Esay-CyberSploit1 总结 getwebshell → 源码注释发现用户名 → robots.txt发现base64密码 → SSH登录 提 权 思 路 → 内网信息收集 → 发现发行版本有点老 → 内核overlayfs提权 准备工作 启动VPN 获取攻击机IP > 192.168.45.220 启动靶机 获取目标机器I…...
浏览器访问 AWS ECS 上部署的 Docker 容器(监听 80 端口)
✅ 一、ECS 服务配置 Dockerfile 确保监听 80 端口 EXPOSE 80 CMD ["nginx", "-g", "daemon off;"]或 EXPOSE 80 CMD ["python3", "-m", "http.server", "80"]任务定义(Task Definition&…...
脑机新手指南(八):OpenBCI_GUI:从环境搭建到数据可视化(下)
一、数据处理与分析实战 (一)实时滤波与参数调整 基础滤波操作 60Hz 工频滤波:勾选界面右侧 “60Hz” 复选框,可有效抑制电网干扰(适用于北美地区,欧洲用户可调整为 50Hz)。 平滑处理&…...
rknn优化教程(二)
文章目录 1. 前述2. 三方库的封装2.1 xrepo中的库2.2 xrepo之外的库2.2.1 opencv2.2.2 rknnrt2.2.3 spdlog 3. rknn_engine库 1. 前述 OK,开始写第二篇的内容了。这篇博客主要能写一下: 如何给一些三方库按照xmake方式进行封装,供调用如何按…...
转转集团旗下首家二手多品类循环仓店“超级转转”开业
6月9日,国内领先的循环经济企业转转集团旗下首家二手多品类循环仓店“超级转转”正式开业。 转转集团创始人兼CEO黄炜、转转循环时尚发起人朱珠、转转集团COO兼红布林CEO胡伟琨、王府井集团副总裁祝捷等出席了开业剪彩仪式。 据「TMT星球」了解,“超级…...
【android bluetooth 框架分析 04】【bt-framework 层详解 1】【BluetoothProperties介绍】
1. BluetoothProperties介绍 libsysprop/srcs/android/sysprop/BluetoothProperties.sysprop BluetoothProperties.sysprop 是 Android AOSP 中的一种 系统属性定义文件(System Property Definition File),用于声明和管理 Bluetooth 模块相…...
Python爬虫(一):爬虫伪装
一、网站防爬机制概述 在当今互联网环境中,具有一定规模或盈利性质的网站几乎都实施了各种防爬措施。这些措施主要分为两大类: 身份验证机制:直接将未经授权的爬虫阻挡在外反爬技术体系:通过各种技术手段增加爬虫获取数据的难度…...
【Java_EE】Spring MVC
目录 Spring Web MVC 编辑注解 RestController RequestMapping RequestParam RequestParam RequestBody PathVariable RequestPart 参数传递 注意事项 编辑参数重命名 RequestParam 编辑编辑传递集合 RequestParam 传递JSON数据 编辑RequestBody …...
【论文阅读28】-CNN-BiLSTM-Attention-(2024)
本文把滑坡位移序列拆开、筛优质因子,再用 CNN-BiLSTM-Attention 来动态预测每个子序列,最后重构出总位移,预测效果超越传统模型。 文章目录 1 引言2 方法2.1 位移时间序列加性模型2.2 变分模态分解 (VMD) 具体步骤2.3.1 样本熵(S…...
优选算法第十二讲:队列 + 宽搜 优先级队列
优选算法第十二讲:队列 宽搜 && 优先级队列 1.N叉树的层序遍历2.二叉树的锯齿型层序遍历3.二叉树最大宽度4.在每个树行中找最大值5.优先级队列 -- 最后一块石头的重量6.数据流中的第K大元素7.前K个高频单词8.数据流的中位数 1.N叉树的层序遍历 2.二叉树的锯…...
Java多线程实现之Thread类深度解析
Java多线程实现之Thread类深度解析 一、多线程基础概念1.1 什么是线程1.2 多线程的优势1.3 Java多线程模型 二、Thread类的基本结构与构造函数2.1 Thread类的继承关系2.2 构造函数 三、创建和启动线程3.1 继承Thread类创建线程3.2 实现Runnable接口创建线程 四、Thread类的核心…...
