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

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)

常用阻塞队列类图.jpg

1、ArrayBlockingQueue(常用)

ArrayBlockingQueue.jpg

  • 基于数组的阻塞队列。ArrayBlockingQueue 内部,维护了一个定长数组,以便缓存队列中的数据对象,这是一个常用的阻塞队列。
  • ArrayBlockingQueue 在生产者放入数据和消费者获取数据,都是共用同一个锁对象,由此也意味着两者无法真正并行运行,没有实现读写分离。
  • 在创建 ArrayBlockingQueue 时,我们还可以控制对象的内部锁是否采用公平锁,默认采用非公平锁。

ArrayBlockingQueue 使用 ReentrantLock 的公平锁和非公平锁来实现该功能。简单理解就是,ReentrantLock 内部会维护一个有先后顺序的等待队列,假如有五个任务一起过来,都被阻塞了。如果是公平的,则等待队列中等待最久的任务就会先进入阻塞队列。如果是非公平的,那么这五个线程就需要抢锁,谁先抢到,谁就先进入阻塞队列。

2、LinkedBlockingQueue(常用)
LinkedBlockingQueue.jpg

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

3、SynchronousQueue
SynchronousQueue.jpg

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

4、PriorityBlockingQueue
PriorityBlockingQueue.jpg

  • 这是一个支持优先级排序的无界队列。
  • 可以指定初始容量大小(注意初始容量并不代表最大容量),或者不指定,默认大小为 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()方法后,线程池的状态就会由RUNNINGSHUTDOWN转为STOP

4、TIDYING

  • workCount(有效线程数)为0
  • 线程池被下达关闭命令后,如果当前所有的任务都已经终止了(这个终止可以表示执行结束,也可以表示强制中断,也可以表示被丢弃) ,那么线程就会进入TIDYING状态;当线程池变为TIDYING状态时,会执行钩子函数terminated()。terminated()在ThreadPoolExecutor类中是空的,若用户想在线程池变为TIDYING时进行相应的处理,可以通过重载terminated()函数来实现。
  • 如果线程状态已经是SHUTDOWN了,并且线程中以及队列中都没有任务时,线程池就会由SHUTDOWN转为TIDYING;如果线程池状态为STOP,那么当线程池把所有的任务都给清理干净时,线程池就会由STOP转为TIDYING

5、TERMINATED

  • 线程池就结束了;线程池就不能重新启动了。
  • 如果线程池处于TIDYING状态,那么当线程池执行完terminated()方法后,线程池状态就会由TIDYING转为TERMINTED

线程池状态转换图.png

七、线程池分类

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;}
}

运行结果:

fixedThreadPoolTest.png

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

singleThreadExecutorTest.png

scheduledThreadPoolTest.png

scheduleAtFixedRateTest.png

参考文章:
线程池10:线程池的5种状态;
常用阻塞队列 BlockingQueue 有哪些?
Android多线程:理解和简单使用总结
Android 线程池
全方位解析-Android中的线程池

相关文章:

Android多线程学习:线程池(一)

一、概念 线程池&#xff1a;创建并维护一定数量的空闲线程&#xff0c;当有需要执行的任务&#xff0c;就交付给线程池中的一个线程&#xff0c;任务执行结束后&#xff0c;该线程也不会死亡&#xff0c;而是回到线程池中重新变为空闲状态。 线程池优点&#xff1a; 1、重用…...

网络安全(黑客技术)—小白自学笔记

1.网络安全是什么 网络安全可以基于攻击和防御视角来分类&#xff0c;我们经常听到的 “红队”、“渗透测试” 等就是研究攻击技术&#xff0c;而“蓝队”、“安全运营”、“安全运维”则研究防御技术。 2.网络安全市场 一、是市场需求量高&#xff1b; 二、则是发展相对成熟入…...

掌握核心技巧就能创建完美的目录!如何在Word中自动创建目录

目录是Word布局的一个重要因素&#xff0c;尤其是在编写较长的文档时。那么&#xff0c;你如何在你的作品中添加目录呢&#xff1f;在这篇文章中&#xff0c;我将分享一些基于Word2016自动创建目录的经验。希望它能或多或少地帮到你。 自动创建目录 1、输入目录文本的名称&am…...

正则表达式中re.match、re.search、re.findall的用法和区别

这位作者的例子写的非常好&#xff0c;记录一下&#xff0c;目前用到的比较多的是findall 正则表达式中re.match、re.search、re.findall的用法和区别_<re.match object; span(0, 270), match<a href"/-CSDN博客...

算法题:买卖股票的最佳时机含手续费(动态规划解法贪心解法-详解)

这道题有两种解法&#xff1a;动态规划 or 贪心算法。 贪心算法的提交结果要比动态规划好一些&#xff0c;总体上动态规划的解法更容易想到。&#xff08;完整题目附在了最后&#xff09; 1、动态规划解法 设置两个数&#xff0c;dp[0]表示遍历到股票prices[i]时手里没有股…...

【gcc】RtpTransportControllerSend学习笔记 4:码率分配

本文是woder大神 的文章的学习笔记。 大神的webrtc源码分析(8)-拥塞控制(上)-码率预估 详尽而具体,堪称神作。 gcc保障带宽公平性,预估码率后要分配码率,实现qos效果: webrtc源码分析(9)-拥塞控制(下)-码率分配 是 woder 大神进一步给出的另一篇神作。 本文是对(https://w…...

「专题速递」AR协作、智能NPC、数字人的应用与未来

元宇宙是一个融合了虚拟现实、增强现实、人工智能和云计算等技术的综合概念。它旨在创造一个高度沉浸式的虚拟环境&#xff0c;允许用户在其中交互、创造和共享内容。在元宇宙中&#xff0c;人们可以建立虚拟身份、参与虚拟社交&#xff0c;并享受无限的虚拟体验。 作为互联网大…...

什么是基于意图的网络(IBN)

基于意图的网络是一种网络技术&#xff0c;它根据业务意图&#xff08;来自网络管理员的服务请求&#xff09;配置 IT 基础架构&#xff0c;无需任何人工干预&#xff0c;它不断提供关键的网络见解&#xff0c;并不断调整硬件配置以确保满足意图&#xff0c;它将网络从以设备为…...

知识增强语言模型提示 零样本知识图谱问答10.8

知识增强语言模型提示 零样本知识图谱问答 摘要介绍相关工作方法零样本QA的LM提示知识增强的LM提示与知识问题相关的知识检索 摘要 大型语言模型&#xff08;LLM&#xff09;能够执行 零样本closed-book问答任务 &#xff0c;依靠其在预训练期间存储在参数中的内部知识。然而&…...

虚拟现实项目笔记:SDK、Assimp、DirectX Sample Browser、X86和X64

文章目录 SDK是什么Assimp是什么DirectX Sample Browser是什么X86和X64生成解决方案和重新生成解决方案 SDK是什么 SDK是Software Development Kit的英文缩写&#xff0c;意思是软件开发包。 软件开发包中往往包含有多种辅助进行软件开发的内容&#xff0c;包括一些软件开发工…...

openwrt rm500u ncm方式拨号步骤记录

1.进入设备页面 用户名&#xff1a;root 2.创建接口 3.配置接口 国内APN 信息 中国移动APN&#xff1a;CMNET 中国联通APN&#xff1a;3GNET 中国电信APN&#xff1a;CTNET 4.防火墙配置 5.点击Save&Apply 6.配置完成后重启设备。重新进入设备页面&#xff0c;可以看…...

使用js代码将一个值为“1=增量,2=全量“的字符串转化为一个数组,数据格式为[{value:““,label:“‘‘}]

const str "1增量&#xff0c;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

这几天在和第三方交互的时候&#xff0c;对方返回的数据是base64格式的数据&#xff0c;所以这两天又彻底捋了下Base64的来龙去脉。之前看过一篇文章说的非常好&#xff08;再找到给加上链接&#xff09;&#xff0c;我在这不详细说明了&#xff0c;只说转换过程。 还是使用中…...

CCF CSP认证 历年题目自练 Day20

题目一 试题编号&#xff1a; 201903-1 试题名称&#xff1a; 小中大 时间限制&#xff1a; 1.0s 内存限制&#xff1a; 512.0MB 问题描述&#xff1a; 题目分析&#xff08;个人理解&#xff09; 常规题目&#xff0c;先看输入&#xff0c;第一行输入n表示有多少数字&am…...

【Overload游戏引擎分析】从视图投影矩阵提取视锥体及overload对视锥体的封装

overoad代码中包含一段有意思的代码&#xff0c;可以从视图投影矩阵逆推出摄像机的视锥体&#xff0c;本文来分析一下原理 一、平面的方程 视锥体是用平面来表示的&#xff0c;所以先看看平面的数学表达。 平面方程可以由其法线N&#xff08;A, B, C&#xff09;和一个点Q(x0,…...

vue全局事件总线是什么?有什么用?解决了什么问题,与pinia有什么区别?

全局事件总线快速入门 概念基本概念&#xff08;是什么&#xff1f;&#xff09;核心概念 核心特性和优势(有什么用&#xff1f;)解决了什么问题&#xff1f;主要优势是什么&#xff1f; 案例演示&#xff1f;传递数据-案例演示传递事件-案例演示 与pinia有什么区别&#xff1f…...

【debian 12】:debian系统切换中文界面

目录 目录 项目场景 基础参数 原因分析 解决方案 1.ctrlaltT 打开终端 2.查询当前语言环境&#xff08;我的已经设置成了中文 zh_CN.UTF-8&#xff09; 3.打开语言配置界面 4.最后一步&#xff1a;重启 不要放弃任何一个机会&#xff01; 项目场景&#xff1a; 这两…...

es官方为我们提供的堆内存保护机制-熔断器( breaker )

总熔断器&#xff08;相当于似乎总闸&#xff09; 参数&#xff1a; indices.breaker.total.use_real_memory 默认值&#xff1a;true 在 elasticsearch.yml中配置。 参数&#xff1a; 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…...

全网最新最全的软件测试面试题

一、前言 与开发工程师相比&#xff0c;软件测试工程师前期可能不会太深&#xff0c;但涉及面还是很广的。 在一年左右的实习生或岗位的早期面试中&#xff0c;主要是问一些基本的问题。 涉及到的知识主要包括MySQL数据库的使用、Linux操作系统的使用、软件测试框架问题、测试…...

如何列出 Ubuntu 和 Debian 上已安装的软件包

当你安装了 Ubuntu 并想好好用一用。但在将来某个时候&#xff0c;你肯定会遇到忘记曾经安装了那些软件包。 这个是完全正常。没有人要求你把系统里所有已安装的软件包都记住。但是问题是&#xff0c;如何才能知道已经安装了哪些软件包&#xff1f;如何查看安装过的软件包呢&a…...

图论---最小生成树问题

在连通网的所有生成树中&#xff0c;所有边的代价和最小的生成树&#xff0c;称为最小生成树。解决最小生成树问题一般有两种算法&#xff1a;Kruskal算法和Prim算法。 Kruskal算法 原理&#xff1a;基本思想是从小到大加入边&#xff0c;是个贪心算法。我们将图中的每个边按…...

elementplus 时间范围选择器限制选择时间范围

<el-date-pickerv-model"form.time" type"daterange"range-separator"-"start-placeholder"开始时间"end-placeholder"结束":disabled-date"disabledDate"calendar-Change"calendarChange" />co…...

【网络】抓包工具Wireshark下载安装和基本使用教程

&#x1f341; 博主 "开着拖拉机回家"带您 Go to New World.✨&#x1f341; &#x1f984; 个人主页——&#x1f390;开着拖拉机回家_Linux,大数据运维-CSDN博客 &#x1f390;✨&#x1f341; &#x1fa81;&#x1f341; 希望本文能够给您带来一定的帮助&#x1…...

Metasequoia 4 水杉3D建模工具 附序列号

Metasequoia 4是一款非常强大的3D水杉建模工具&#xff0c;它基于多边形建模技术&#xff0c;可以用于创建各种对象并支持多种第三方3DCG软件的文件格式&#xff0c;是一款非常适合从爱好到业务&#xff0c;支持3D电脑绘图&#xff0c;3D印刷&#xff0c;游戏开发等的3D建模软件…...

股票杠杆交易平台排名:淘配网推荐的十大平台

在投资世界中&#xff0c;股票杠杆交易一直以其提供更高回报机会的吸引力而备受欢迎。随着市场的不断发展&#xff0c;出现了越来越多的股票杠杆交易平台。本文将为您介绍淘配网推荐的十大股票杠杆交易平台&#xff0c;并分析它们的特点。 富灯网 - 富灯网以其全面的杠杆产品和…...

CoreData + CloudKit 在初始化 Schema 时报错 A Core Data error occurred 的解决

问题现象 如果希望为 CoreData 支持的 App 增加云数据备份和同步功能,那么 CloudKit 是绝佳的选择。CloudKit 会帮我们默默处理好一切,我们基本不用为升级而操心。 不过,有时在用本地 CoreData NSManagedObjectModel 初始化 iCloud 中的 Schema 时会发生如下错误: Error …...

修炼k8s+flink+hdfs+dlink(三:安装dlink)

一&#xff1a;mysql初始化。 mysql -uroot -p123456 create database dinky; grant all privileges on dinky.* to dinky% identified by dinky with grant option; flush privileges;二&#xff1a;上传dinky。 上传至目录/opt/app/dlink tar -zxvf dlink-release-0.7.4.t…...

Linux 系统性能瓶颈分析(超详细)

Author&#xff1a;rab 目录 前言一、性能指标1.1 进程1.1.1 进程定义1.1.2 进程状态1.1.3 进程优先级1.1.4 进程与程序间的关系1.1.5 进程与进程间的关系1.1.6 进程与线程的关系 1.2 内存1.2.1 物理内存与虚拟内存1.2.2 页高速缓存与页写回机制1.2.3 Swap Space 1.3 文件系统1…...

怎样做同性恋女视频网站/今日头条新闻消息

一&#xff1a;cookie在浏览器中什么地方查找写入成功 二&#xff1a;如何用js写 function addCookie(name,value,expireHours){var cookieStringname""escape(value)"; path/";//判断是否设置过期时间if(expireHours>0){var datenew Date();date.setTi…...

创建游戏网站/泰安网站建设优化

启动失败IDLE使用套接字在IDLE GUI进程和用户代码执行过程之间进行通信。无论何时Shellstart或重新启动&#xff0c;都必须建立连接。(后者用分隔线表示’RESTART’)。如果用户进程无法连接到GUI进程&#xff0c;则会显示一个失败的常见原因是用户编写的文件与标准库模块同名&a…...

wordpress aliay/拼多多女装关键词排名

static cell 与 dynamic cell 混合使用 关于静态cell与动态cell的混合使用&#xff0c;google一下便会有很多相关文章&#xff0c;这里也是看过一些前辈的经验&#xff08;已经忘记具体是从哪篇文章得到的帮助&#xff09;之后自己做的笔记。在某些界面中static cell与dynamic …...

各手机厂商定制版app/seo招聘信息

假设我们需要使用 Oracle 数据库&#xff0c;那么首先需要在 pom.xml 中引用 Oracle 数据库驱动包&#xff1a;12.2.0.1...com.oracleojdbc8${oracle.version}1 直接配置在 application.yml 中配置数据源参数&#xff0c;形如&#xff1a;spring:datasource:url: jdbc:oracle:t…...

电子网站风格设计/中国联通腾讯

概述 最后更新&#xff1a;2018/10/17 企业微信JS-SDK是企业微信面向网页开发者提供的基于企业微信内的网页开发工具包。 通过使用企业微信JS-SDK&#xff0c;网页开发者可借助企业微信高效地使用拍照、选图、语音、位置等手机系统的能力&#xff0c;同时可以直接使用企业微…...

有什么网站是专门做电商详情页/互联网广告代理

通过Report Utilization查看资源利用率报告时&#xff0c;会生成如下图所示的一个表格。在这个表格中Resource对应的列会有LUT和LUTRAM&#xff0c;那么两者到底有什么区别呢&#xff1f;是包含关系吗&#xff1f;不过&#xff0c;可以断定的是LUTRAM是指将LUT用做分布式RAM/RO…...