前言:实习项目
一、健康险核心 batch 自动查询和一键重启
二、后端如何实现免密登录
-
Spring Boot与Spring Security:
- 如果你使用的是Spring框架,Spring Security可以为你提供大量的安全功能。
- 创建一个基于Spring Boot的新项目,并添加Spring Security依赖。
-
使用JWT:
- 使用JSON Web Tokens (JWT)为用户生成令牌。这些令牌在第一次验证后,可以为用户提供有限的访问时间,而不需要再次输入密码。
- 为Spring Security配置一个JWT过滤器,用于检查和验证请求头中的令牌。
-
存储和管理令牌:
- 当用户首次登录时,生成一个JWT并将其发送给客户端。
- 客户端应将此令牌保存在cookie或localStorage中,并在随后的每次请求中附带它。
- 服务器端应验证这个令牌,以确定用户是否已经验证,并且令牌是否仍然有效。
-
安全性:
- 使用HTTPS来加密客户端和服务器之间的所有通信。
- 定期旋转你的JWT签名密钥以增加安全性。
- 将令牌的有效期设置为相对较短,例如15分钟或1小时,但提供刷新机制。
-
日志和监控:
- 使用Java的日志库(如SLF4J或Logback)记录所有的登录尝试、令牌生成和验证失败。
- 这将帮助你在发生安全事件时进行调查和审计。
三、JWT登录流程?包含哪些结构?摘要算法用的是什么?
-
JWT登录流程:
- 用户登录:用户使用他们的凭据(如用户名和密码)来请求访问。
- 验证凭据:服务器验证用户提交的凭据。如果凭据是有效的,服务器将生成一个JWT。
- 生成JWT:一旦验证成功,服务器将使用密钥(通常只有服务器知道)来生成JWT,并将其发送回客户端。
- 客户端存储JWT:客户端接收JWT并存储在本地,常见的存储位置是Cookie或LocalStorage。
- 发送请求携带JWT:之后,每当客户端向服务器发送请求(尤其是对受保护资源的请求),它都会在其请求头中附带JWT。
- 服务器验证JWT:服务器接收到请求后,会验证请求头中的JWT。如果JWT有效,服务器会处理该请求;如果无效,服务器可能会返回一个错误。
- 到期/注销:JWT有一个到期时间,过了这个时间JWT就会失效。此外,如果用户注销,客户端通常会丢弃保存的JWT。
-
JWT结构包括三部分:
-
头(Header):它通常由两部分组成:令牌的类型(即JWT)和所使用的签名算法,如HMAC SHA256或RSA。
-
有效载荷(Payload):包含声明,这是关于实体(通常是用户)以及其他一些元数据的语句。这些声明被称为“claims”。
-
签名(Signature):为了获得签名部分,您必须获取编码的header,编码的payload,一个秘密,然后使用header中指定的算法进行签名。
-
摘要算法:JWT支持多种摘要算法,但最常见的算法是:
- HS256 (HMAC with SHA-256)
- RS256 (RSA signature with SHA-256)
其中,HS256使用共享密钥(客户端和服务器都知道的),而RS256使用私钥/公钥对,只有服务器知道私钥。这使得RS256更适合于公开的、可扩展的环境,因为只有生成JWT的服务器才能验证和接受令牌。
四、个人保险凭证打印,利用 Java 的 PDF 生成库 iText 为用户提供凭证的 PDF 生成功能
-
添加iText库依赖:
- 如果你使用的是Maven,可以在
pom.xml
中添加iText的依赖。不同版本的iText可能有所不同,所以要确保选择一个适合的版本。
- 如果你使用的是Maven,可以在
-
创建PDF文档:
- 使用
Document
类来创建一个新的PDF文档。 - 使用
PdfWriter.getInstance()
方法将这个Document
对象与一个文件输出流关联起来。
- 使用
-
开始编写内容:
- 打开文档:
document.open()
- 使用
document.add()
方法添加内容。iText提供了多种元素,如Paragraph
,Chapter
,Section
,List
,PdfPTable
等,你可以根据需要加入。 - 在为保险凭证填写具体信息时(如保单号、购买日期、姓名等),可以用这些基础元素组装。
- 打开文档:
-
格式化内容:
- 使用iText的字体和样式类来调整文本的外观。
- 使用
BaseFont
和Font
类来创建和应用不同的字体和样式。
-
创建表格:
- 如果需要整齐地显示某些信息,例如保险明细,可以使用
PdfPTable
类来创建表格。 - 表格可以有标题、多个行和列,并可以定义边框、背景等样式。
- 如果需要整齐地显示某些信息,例如保险明细,可以使用
-
添加图片或公司标志:
- 使用
Image
类来添加图片到文档。 - 图片可以是外部文件,也可以是内部资源。
- 使用
-
页眉和页脚:
- 使用
HeaderFooter
类或事件处理来添加页眉和页脚。这样可以为每一页自动添加页码、日期、公司标志等信息。
- 使用
-
完成文档:
- 一旦你添加了所有需要的内容,使用
document.close()
来关闭并保存文档。
- 一旦你添加了所有需要的内容,使用
-
提供给用户:
- 根据你的应用环境,你可以将生成的PDF文件保存到服务器、数据库,或直接作为HTTP响应的一部分发送给用户以供下载或在线预览。
1、RPC的重要组成有哪些?
-
客户端(Client):发起RPC请求的部分。客户端包含代表远程过程的存根(stub),它提供与本地过程相同的接口。
-
服务器(Server):接受RPC请求并执行服务的部分。服务器同样包含一个存根,负责接受请求、解码参数、执行请求并返回结果。
-
传输层:RPC需要一种通信方式来在客户端和服务器之间传输数据。这通常通过网络完成,例如使用TCP/IP或UDP。
-
消息格式/序列化:由于网络传输层通常只能传输字节流,RPC需要将数据(如过程参数和返回值)转换为这种格式。这个转换过程叫做序列化(将数据转换为字节流)和反序列化(将字节流转回原始数据)。
-
请求与响应:客户端发起的是请求,服务器返回的是响应。每个请求都与一个响应匹配。
-
服务注册与发现:在某些RPC系统中(如gRPC、Apache Thrift等),服务器可以注册其提供的服务,并且客户端可以发现这些服务。这可以使得客户端和服务器的连接更加动态和灵活。
-
错误处理:如果远程调用中发生错误(如网络问题、服务不可用等),RPC框架应该能够捕获并处理这些错误。
-
身份验证和授权:为了确保只有合法的客户端可以访问服务,RPC系统可能会包含身份验证和授权机制。
-
负载均衡:在多个服务器实例中,RPC系统可能会提供负载均衡功能,使得客户端的请求可以均匀地分配到不同的服务器。
2、注册中心怎么选?CP更重要还是AP?ZooKeeper是CP还是AP?
(1)选择CP还是AP取决于你的系统需求:
- 如果系统需要确保数据的一致性,并且可以承受某些请求失败或延迟,那么CP可能更合适。
- 如果系统需要确保高可用性,即使这意味着在某些情况下返回的数据可能是过时的,那么AP可能更合适。
(2)ZooKeeper 是一个CP系统。当网络分区发生时,为了维护一致性,ZooKeeper可能会牺牲可用性。这意味着在某些情况下,ZooKeeper可能不会响应客户端的请求,以确保数据的一致性。
3、序列化的作用是什么?Serializable的原理?
(1)在RPC(远程过程调用)中,序列化的主要作用是将数据或对象转化为可传输的格式,使其能够在网络上进行传输,从而实现不同节点或服务之间的通信。
具体作用如下:
-
数据交换:通过序列化,客户端可以将请求参数转化为字节流,在网络上发送到服务器;服务器接收到字节流后,再通过反序列化恢复为原始的请求参数。
-
保证数据完整性:序列化过程中可以将数据结构完整地转化为字节流,确保数据在传输过程中不丢失任何信息。
-
兼容性:有些序列化协议(如Protocol Buffers, Avro等)提供了版本控制和兼容性管理,使得数据格式可以随着时间演进而不影响已有的客户端和服务器之间的通信。
(2)Serializable的原理
Serializable
是Java中的一个标记性接口,用于指示一个类的对象可以被序列化。当一个类实现了Serializable
接口时,Java的对象序列化机制可以将其转换为字节流,反之也可以从字节流中重构对象。
4、redis的跳表,说下底层结构和查询过程和效率,和二叉树比较,为啥不用红黑树(红黑树不支持范围查找)?和B+树有什么区别?
(1) 跳表(SkipList)主要被用于有序集合(Sorted Sets, zset)的实现。它能实现快速查询、插入和删除操作。它是由多层链表组成,每一层都是一个有序链表。层级之间通过上下指针相互连接,底层是完整数据链表。
(2)查询过程和效率
- 从最顶层的链表开始,从左至右进行搜索,直到找到一个大于或等于目标值的节点或到达链表的末尾。
- 如果当前节点值等于目标值,查询成功。
- 如果当前节点值大于目标值或到达链表的末尾,则向下移动一层,并从左边的节点继续搜索。
- 如果到达底层链表还没有找到目标值,则查询失败。
查询效率为O(log n),因为每一次跳跃都大致减少了一半的搜索空间。
(3)与二叉树和红黑树的比较
-
平衡问题:二叉查找树(如红黑树)需要进行平衡操作,而跳表通过随机化的方法来确保层级结构的均衡,避免了复杂的旋转操作。
-
范围查询:红黑树不支持范围查询,而跳表的底层是完整的有序链表,所以很容易进行范围查询。
-
简单性和实现难度:跳表的结构和算法相对简单,而红黑树的实现相对复杂。
(4)与B+树的区别
-
结构:跳表是基于链表的,而B+树是基于树的结构。
-
存储方式:在B+树中,所有的值都在叶子节点,并且叶子节点形成了一个有序链表。而在跳表中,每一个节点可能出现在多个层级上。
-
查询效率:B+树和跳表的查询效率都是O(log n),但在实际应用中,由于B+树更适合磁盘存储和I/O操作,它通常用于数据库索引;而跳表因为其结构简单,经常用于内存数据结构,如Redis。
-
扩展性:跳表更容易进行水平扩展。
(5)为什服务器托管网么Redis选择跳表而不是红黑树?
Redis使用跳表来实现其有序集合数据类型(Sorted Set)。跳表相比红黑树来说,更容易实现,理解和维护。同时,跳表更容易支持范围查询和有序数据的快速插入/删除。红黑树的范围查找并不直接得到,需要进行额外的遍历操作。
5、Redis的数据类型?如何实现整数自增?
- 字符串(String):可以存储字符串、整数或浮点数。
- 列表(Lists):是字符串元素的集合,并且是有序的。Redis lists使用链表实现,所以插入和删除操作是快速的。
- 集合(Sets):是字符串的无序集合,并且集合中的每个字符串都是唯一的。
- 有序集合(Sorted Sets, zset):与集合类似,但每个元素都关联了一个分数,这使得元素能按分数进行排序。
- 哈希(Hashes):是键值对的集合。
- 位图(Bitmaps):实际上是字符串的特定操作方式,通过这种方式,你可以将字符串视为位数组,并能够对其进行操作。
- HyperLogLogs:这是一个概率数据结构,用于估计集合的基数。
- 流(Streams):新的数据类型(在Redis 5.0中引入),用于实现持久的日志数据类型。
要实现整数的自增功能,可以使用INCR
命令。如果键不存在,Redis会将它设置为0,然后执行自增操作。
6、Redis集群
Redis集群提供了一种方式,允许多个Redis节点协同工作,以此来提供更高的可用性和性能。其核心特点和概念包括:
- 数据分片:数据被分为多个片段,并在多个Redis节点上进行分布。
- 主从复制:每个Redis节点都会有0或多个复制品。这样,当主节点不可用时,其中一个从节点可以被提升为新的主节点。
- 自动故障转移:当主节点不可用时,Redis集群可以自动从相关的从节点中选择一个进行提升。
- 客户端与集群的通信:Redis客户端不需要连接集群中的所有节点,它可以连接到任何一个可用的节点,然后由该节点重定向到正确的节点(如果需要)。
- 节点之间的通信:使用二进制协议进行,主要用于节点间状态的广播。
集群模式不仅提高了Redis的性能(通过分片)和高可用性(通过主从复制和故障转移),而且还允许Redis部署规模更大、容纳更多数据。
7、Spring的Bean生命周期?
Bean 的生命周期指的是 Bean 在 Spring(IoC)中从创建到销毁的整个过程。Bean 的生命周期主要包含以下 5 个流程:
(1)实例化:为 Bean 分配内存空间;
(2)设置属性:将当前类依赖的 Bean 属性,进行注入和装配;
(3)初始化:
- 执行各种通知。
- 执行初始化的前置方法。
- 执行初始化方法。
- 执行初始化的后置方法。
(4)使用 Bean:在程序中使用 Bean 对象;
(5)销毁 Bean:将 Bean 对象进行销毁操作。
8、如果在bean初始化的时候加一些操作,有哪些方式?
- 实现BeanPostProcessor接口 其中有(before 和 after)方法
- 当bean需要在所有必要的属性被设置后执行一些初始化,可以实现
InitializingBean
接口的afterPropertiesSet
方法。 - 使用Java的
@PostConstruct
注解标记一个方法作为bean的初始化方法。 - 当使用XML配置bean时,可以使用
init-method
属性来指定bean的初始化方法。
10、分页查询的MySQL优化
-
避免使用
OFFSET
方法: 传统的使用LIMIT
和OFFSET
的方法在处理大量数据时可能会很慢,因为它跳过了OFFSET
之前的所有行,这在数据很多时会非常慢。 -
使用主键进行分页: 在大多数情况下,基于ID的分页查询效率更高。例如,假设上次的最后一个ID是1000,下次查询可以从ID>1000开始,然后使用
LIMIT
取下一页的数量。SELECT * FROM table WHERE id > 1000 ORDER BY id ASC LIMIT 10;
-
使用覆盖索引: 确保查询只使用索引中的列,这样MySQL可以只扫描索引,而不必查询实际的数据行。这称为“覆盖索引”。
-
避免
SELECT *
: 只选择需要的列,而不是使用SELECT *
,这样可以减少数据传输量。 -
缓存结果: 如果结果集不经常更改,可以考虑缓存分页结果,以减少对数据库的重复查询。
-
预估总数: 对于某些应用,不需要知道精确的总页数或总行数,可以考虑预估这个数字,以避免计算成本高的
COUNT
查询。 -
调整
innodb_buffer_pool_size
配置: 确保InnoDB缓冲池足够大,以缓存常用的数据和索引。 -
使用分区: 如果表非常大,可以考虑使用分区,这样查询可以只扫描感兴趣的分区,而不是整个表。
-
考虑使用摘要: 对于大量数据的分页显示,可能不需要显示每一行的所有数据。可以考虑只获取和显示摘要或预览,当用户需要查看详细信息时,再进行单独的查询。
-
减少每页显示的行数: 当处理大量数据时,考虑减少每页的行数,这样可以减少查询和渲染的时间。
11、MySQL的索引底层结构?
(1) Hash 表
哈希算法有个 Hash 冲突 问题,也就是说多个不同的 key 最后得到的 index 相同。通常情况下,我们常用的解决办法是 链地址法。链地址法就是将哈希冲突数据存放在链表中。就比如 JDK1.8 之前 HashMap
就是通过链地址法来解决哈希冲突的。不过,JDK1.8 以后HashMap
为了减少链表过长的时候搜索时间过长引入了红黑树。
为了减少 Hash 冲突的发生,一个好的哈希函数应该“均匀地”将数据分布在整个可能的哈希值集合中。既然哈希表这么快,为什么 MySQL 没有使用其作为索引的数据结构呢? 主要是因为 Hash 索引不支持顺序和范围查询。假如我们要对表中的数据进行排序或者进行范围查询,那 Hash 索引可就不行了。并且,每次 IO 只能取一个。
(2) B 树& B+树
B 树也称 B-树,全称为 多路平衡查找树 ,B+ 树是 B 树的一种变体。B 树和 B+树中的 B 是 Balanced
(平衡)的意思。
目前大部分数据库系统及文件系统都采用 B-Tree 或其变种 B+Tree 作为索引结构。
B 树& B+树两者有何异同呢?
- B 树的所有节点既存放键(key) 也存放 数据(data),而 B+树只有叶子节点存放 key 和 data,其他内节点只存放 key。
- B 树的叶子节点都是独立的;B+树的叶子节点有一条引用链指向与它相邻的叶子节点。
- B 树的检索的过程相当于对范围内的每个节点的关键字做二分查找,可能还没有到达叶子节点,检索就结束了。而 B+树的检索效率就很稳定了,任何查找都是从根节点到叶子节点的过程,叶子节点的顺序检索很明显。
12、MySQL的事务隔离级别?
-
读未提交 (READ UNCOMMITTED)
- 在这个隔离级别中,一个事务可以读取另一个未提交事务的修改。
- 问题:这种级别可能会导致”脏读”,即一个事务读取到另一个事务还未提交的数据,如果那个事务最终回滚,那么读取的数据就是无效的。
- 这是最低的隔离级别,锁定的需求最少。
-
读提交 (READ COMMITTED)
- 在这个隔离级别中,一个事务只能读取其他事务已经提交的修改。
- 问题:尽管可以避免”脏读”,但是可能会发生”不可重复读”,即在同一个事务中,后续的查询可能会看到前一个查询中未看到的行或列的不同值。
- 这是大多数数据库系统的默认隔离级别。
-
可重复读 (REPEATABLE READ)
- 在这个隔离级别中,其他事务不能在事务执行期间插入新行,从而防止了”幻读”。
- 问题:该隔离级别可以避免”脏读”和”不可重复读”,但是可能会导致”幻读”。”幻读”是指当某个事务在读取某个范围内的所有行时,另一个事务又在该范围内插入了新行,导致前一个事务再次读取时看到了额外的、早先不存在的行。
- 在MySQL的InnoDB存储引擎中,这是默认的隔离级别。
-
串行化 (SERIALIZABLE)
- 这是最严格的隔离级别。当一个事务选择了该隔离级别后,其他事务就不能并发执行,它们必须等待该事务完成。
- 问题:这种级别可以避免”脏读”、”不可重复读”和”幻读”,但是性能开销最大,因为事务之间完全是串行执行的。
- 这个隔离级别很少在实际应用中使用,除非是非常关键的操作。
13、可重复读是如何实现的?
-
多版本并发控制 (MVCC): InnoDB使用MVCC来实现可重复读。简单来说,对于每行数据,InnoDB既保存数据的当前值,也保存该行的之前版本的值。当一个事务读取一行数据时,它会读取该行数据在该事务开始时的版本,而不是最新版本。这就确保了事务在其生命周期内看到的数据是一致的。
-
Undo日志: 当一行数据被修改时,InnoDB会在Undo日志中保存该行的原始数据。如果其他事务需要读取这行数据的早期版本,它可以在Undo日志中找到。
-
Read View: 当事务开始时,InnoDB会为它创建一个“Read View”。Read View确定了该事务可以看到哪些行的哪个版本。基本上,事务只能看到在它开始之前就已经存在的行版本。
-
Next-Key Locking: InnoDB使用一种称为“Next-Key Locking”的方法,这种方法在读取行时为行和行的间隙加锁,从而防止其他事务插入新的行。
-
一致性非锁定读: 在可重复读隔离级别下,InnoDB默认进行一致性非锁定读。这意味着读操作不会设置任何锁,而是直接返回行的早期版本,如果可用的话。
-
快照读和当前读: 在可重复读隔离级别下,普通的SELECT(不带FOR UPDATE或LOCK IN SHARE MODE)是快照读,它返回数据的早期版本。而带FOR UPDATE或LOCK IN SHARE MODE的SELECT则是当前读,它返回数据的最新版本,并设置相应的锁。
14、多个事务读 和 多个事务写会发生什么问题?
-
脏读 (Dirty Read): 当一个事务读取了另一个事务尚未提交的数据,称为脏读。如果这个写事务在之后发生了回滚,那么读事务读取到的信息将是不准确的。
-
不可重复读 (Non-Repeatable Read): 在一个事务内,多次读取同一数据时,中间的某次读取返回了不同的数据,这种现象称为不可重复读。这通常是由于在两次读取之间,另一个事务修改了这些数据。
-
幻读 (Phantom Read): 在一个事务内,多次执行相同的查询,第一次查询返回了一些行,而第二次查询返回了不同的行,这称为幻读。这通常是因为在两次查询之间,另一个事务插入或删除了一些行。
-
写-写冲突: 当两个事务同时试图修改同一数据时,可能会发生写-写冲突。大多数数据库管理系统采用锁机制来避免这种冲突,确保每次只有一个事务可以写入数据。
-
读-写冲突: 当一个事务正在读取数据,而另一个事务试图同时写入相同的数据,就会发生读-写冲突。这可能会导致等待,直到写事务完成,或者读事务可能需要重新读取数据。
-
死锁 (Deadlock): 当两个或多个事务互相等待对方释放资源时,会发生死锁。例如,事务A等待事务B释放一个资源,而事务B同时等待事务A释放另一个资源。这些事务都进入了一个等待状态,无法前进。
-
资源竞争: 当多个事务都尝试访问和使用相同的资源(如数据、锁或内存)时,它们可能会相互干扰,导致系统的整体性能下降。
为了解决上述问题,数据库管理系统提供了事务隔离级别,以控制事务之间的交互方式。通过选择合适的隔离级别,可以在数据一致性和系统性能之间取得平衡
15、MySQL的索引什么时候失效
-
隐式类型转换: 当字段的数据类型和查询条件中的数据类型不匹配时,MySQL可能不会使用索引。例如,如果一个字段是字符型,但在WHERE子句中与数字进行比较,这将导致索引失效。
-
使用函数: 在列上使用函数会导致索引失效。例如,使用
UPPER()
函数来进行字符串比较。 -
使用OR: 当在WHERE子句中使用OR连接两个不同的列,如果其中一个列没有索引,那么整个查询可能不会使用索引。
-
非最左前缀: 对于联合索引,如果查询没有使用联合索引的最左部分,则索引可能不会被使用。例如,对于(a,b,c)的联合索引,如果查询只涉及b和c而不涉及a,则索引可能不会被使用。
-
LIKE的不正确使用: 当使用LI服务器托管网KE操作符时,如果搜索字符串的开头是通配符(如
%abc
),则索引将不会被使用。但如果模式是固定的开始(如abc%
),则会使用索引。 -
使用!=或: 使用这些操作符可能会导致全表扫描,从而不使用索引。
-
索引列的计算: 在WHERE子句中对索引列进行计算,例如
indexed_column / 2 = 100
,这将导致索引失效。 -
NULL检查: 使用IS NULL或IS NOT NULL操作符可能导致索引不被使用。
-
索引未被统计或统计信息过时: 如果MySQL查询优化器认为全表扫描比使用索引更快,或者索引统计信息不是最新的,它可能选择不使用索引。
-
使用JOIN: 如果在JOIN操作中不正确使用索引列,可能导致索引失效
16、MySQL存储字符串有哪些类型?
-
CHAR: 用于存储定长字符串。即使存储的字符串长度小于声明的长度,它也会占用为其分配的全部空间。例如,
CHAR(10)
用于存储长度为10的字符串。 -
VARCHAR: 用于存储变长字符串。只占用实际需要的空间加上一个或两个额外字节。例如,
VARCHAR(10)
可以存储最长为10个字符的字符串,但只占用实际字符数加上1个或2个字节的空间。 -
TINYTEXT: 可变长度文本字段,最大长度为255个字符。
-
TEXT: 可变长度文本字段,最大长度为65,535字符。
-
MEDIUMTEXT: 可变长度文本字段,最大长度为16,777,215字符。
-
LONGTEXT: 可变长度文本字段,最大长度为4,294,967,295字符。
-
ENUM: 用于存储预定义值列表中的一个值。在表创建时,会为列定义一个值列表,每个列值必须来自该列表。例如,
ENUM('RED', 'BLUE', 'GREEN')
。 -
SET: 类似于ENUM,但可以存储多个值。例如,
SET('RED', 'BLUE', 'GREEN')
可以存储如”RED,BLUE”这样的组合值
17、MVCC机制说一下?
MySQL 中并发事务的控制方式无非就两种:锁 和 MVCC。锁可以看作是悲观控制的模式,多版本并发控制(MVCC,Multiversion concurrency control)可以看作是乐观控制的模式。锁控制方式下会通过锁来显示控制共享资源而不是通过调度手段,MySQL 中主要是通过读写锁来实现并发控制。
MVCC 是多版本并发控制方法,即对一份数据会存储多个版本,通过事务的可见性来保证事务能看到自己应该看到的版本。通常会有一个全局的版本分配器来为每一行数据设置版本号,版本号是唯一的。
MVCC 在 MySQL 中实现所依赖的手段主要是: 隐藏字段、read view、undo log。
- undo log : undo log 用于记录某行数据的多个版本的数据。
- read view 和 隐藏字段 : 用来判断当前版本数据的可见性。
18、Linux中如何杀死一个进程?kill命令的原理?
19、有哪些锁?说一下synchronized和lock的区别
-
来源和类型:
-
synchronized
是Java的关键字,属于JVM层面的锁。通过监视器锁(monitor)来实现,每个对象都有监视器锁。 -
Lock
是Java类库提供的锁机制。例如ReentrantLock
。
-
-
手动性:
-
synchronized
的锁定和释放是隐式的,当线程进入synchronized
修饰的方法或代码块时,锁定,当退出时释放。 -
Lock
需要手动锁定和释放。如果忘记释放,可能导致死锁。
-
-
可中断性:
-
synchronized
是不可中断的。 -
Lock
提供了一个可以响应中断的锁获取操作,lockInterruptibly()
。
-
-
公平性:
-
synchronized
是非公平锁。 -
Lock
可以设置为公平锁或非公平锁。例如,ReentrantLock
在构造时可以指定是否为公平锁。
-
-
绑定多个条件:
-
synchronized
没有此功能。 -
Lock
可以与多个Condition
对象绑定,实现多路通知功能。
-
-
性能和效率:
- 在早期版本的Java中,
synchronized
的性能通常低于Lock
,但在近年的Java版本中,这两者的性能差异已经缩小。 -
Lock
提供了更高的灵活性,因此在某些复杂的场景下可能更有优势。
- 在早期版本的Java中,
- 总的来说,虽然
synchronized
和Lock
都可以用于多线程的同步,但Lock
提供了更高的灵活性和更细粒度的控制
20、hashmap怎么实现的,哈希冲突是什么,解决hash冲突的办法,
结构:
-
数组 + 链表结构:
HashMap
的基础是一个数组结构(Node[] table
)。每个数组的元素或称为桶 (bucket) 都保存了一个链表。 -
在 Java 8 之后,对于长链表还可能使用红黑树来有效地管理哈希冲突,并保持其操作的效率
解决哈希冲突的办法:
-
链地址法 (Chaining): 这是
HashMap
中使用的方法。在数组的同一索引位置上,所有具有相同哈希码或数组索引的元素都存储在一个链表中。如果在某个索引位置上发生了哈希冲突,那么新的键值对就被添加到那个位置的链表的末尾。 -
开放地址法 (Open Addressing): 当冲突发生时,查找数组中的下一个空位置并将键值对放置在那里。这种方法的一个变种是双散列,它使用两个哈希函数来确定元素的位置。
-
再哈希法 (Rehashing): 使用另一个哈希函数来确定键值对的位置。
-
线性探测 (Linear Probing): 当哈希冲突发生时,线性地查找数组中的下一个空位置。
-
二次探测 (Quadratic Probing): 当哈希冲突发生时,以二次的方式查找数组中的下一个空位置。
21、tcp连接,怎么保证可靠
-
三次握手(Three-way Handshake):建立连接时,TCP使用三次握手机制来确保双方都准备好进行通信。
-
确认应答(Acknowledgements):当接收到数据时,接收方会发送一个确认消息(ACK)回到发送方。发送方在发送数据后会启动一个计时器,等待ACK的到来。
-
超时重传:如果发送方在预定时间内没有收到ACK,它会假设数据包已丢失,并重新发送该数据包。
-
序列号:每个发送出去的字节都有一个序列号。接收方使用这些序列号来重新组装数据流并检测丢失的数据包。
-
滑动窗口:TCP使用滑动窗口协议来控制在一个给定的时间内发送者可以发送多少数据,以及何时需要确认。这不仅可以处理丢包,还可以进行流量控制,防止接收方被发送方的数据淹没。
-
错误检测:TCP头部有一个校验和字段,用于检查数据是否在传输过程中被损坏。
-
拥塞控制:如果网络出现拥塞,TCP会减少其发送数据的速率,避免更严重的网络问题。这是通过观察丢失的数据包来实现的,因为丢失的数据包通常是网络拥塞的一个标志。
-
四次挥手(Four-way Handshake):当连接的一方完成其发送任务后,它可以请求关闭连接,这需要一个四步过程来确保双方都完成了数据传输。
22、Java中如何实现多态
继承、重写和向上转型。 只有满足这3 个条件,开发人员才能够在同一个继承结构中使用统一的逻辑实现代码处理不同的对象,从而执行不同的行为。
- 继承:在多态中必须存在有继承关系的子类和父类。
- 重写:子类对父类中某些方法进行重新定义,在调用这些方法时就会调用子类的方法。
23、垃圾回收算法
JVM的垃圾回收机制是指在JVM中,有一个垃圾回收线程,它是低优先级的,在正常情况下是不会执行的,只有在虚拟机空闲或者当前堆内存不足时,才会触发执行。垃圾回收的过程主要包括以下几个步骤:
-
判定垃圾回收的对象。回收垃圾之前,首先要找到需要被当作垃圾而回收的对象。JVM分为五个区域——程序计数器、虚拟机栈、本地方法栈、堆、方法区。我们知道程序计数器与栈均是线程私有的,其生命周期取决于线程的生命周期。
-
标记存活对象。可达性算法是为了标记存活的对象,知道哪些是可回收对象。
-
垃圾回收算法进行回收。常见的几种垃圾回收算法有标记清除、复制算法、标记整理和分代收集算法。
-
压缩内存空间。在进行完垃圾回收之后,可能会出现内存空间不连续的情况,需要进行内存压缩。
24、HTTP和HTTPS的区别,HTTP请求的构成?
(1)HTTP与HTTPS的区别
-
安全性:
- HTTP:超文本传输协议,信息是明文传输,存在安全风险。
- HTTPS:即HTTP加入SSL层,超文本传输安全协议。信息是经过加密的,更加安全。
-
端口:
- HTTP:使用端口80。
- HTTPS:使用端口443。
-
性能:
- HTTP:因为没有加密,所以HTTP的速度比较快。
- HTTPS:需要进行加密处理,因此相对较慢(但随着现代技术的发展,这种差异已经被最小化)。
-
证书:
- HTTP:不需要证书。
- HTTPS:需要SSL证书。如果网站使用的是自签名的SSL证书,浏览器会提示访问者。
(2)HTTP请求结构
一个HTTP请求主要包含以下部分:
- 请求行:包括请求方法(如GET, POST, PUT, DELETE等)、请求URI以及HTTP版本。
- 请求头(Headers):描述请求的元数据或其他信息,如User-Agent(浏览器类型)、Accept(可接受的回复类型)、Host(请求的服务器)等。
- 空行:请求头和请求体之间的分隔符。
- 请求体(Body):POST或PUT请求中传送的数据。
(3)请求头的作用
请求头在HTTP请求中扮演了重要的角色,它为服务器提供了关于客户端请求的一些信息。以下是请求头的一些常见用途:
-
内容类型:通过
Content-Type
头部,客户端可以告诉服务器发送的数据是什么格式,如application/json
或text/html
。 -
内容长度:通过
Content-Length
头部,指示请求或响应体的大小。 -
认证:例如,
Authorization
头部用于包含凭据,通常用于API认证。 -
缓存控制:
Cache-Control
和其他相关的头部可以控制如何缓存响应内容。 -
用户代理:
User-Agent
头部描述了发出请求的客户端类型,如浏览器或其他客户端应用。 -
接受的内容类型:通过
Accept
头部,客户端可以告诉服务器它希望收到哪种类型的响应。 -
Cookies:
Cookie
头部可以包含服务器设置的任何cookie,它们在每个请求中发送回服务器。 -
跨域请求:
Origin
头部表示请求来自哪个源,与CORS(跨来源资源共享)策略相关。
25、GET和POST的区别?
26、介绍二叉树,平衡二叉树,完全二叉树,红黑树,b树,b+树,说下他们的特点,查询时间复杂度,区别和各自的优缺点。
(1)二叉树 (Binary Tree)
- 特点:每个节点最多有两个子节点:左子节点和右子节点。
- 查询时间复杂度:最坏情况下为O(n),平均为O(log n)。
- 优缺点:基础数据结构,简单易于实现;但如果不平衡,查询效率可能会受影响。
(2)平衡二叉树 (Balanced Binary Tree)
- 特点:也被称为AVL树。树中任何两个子树的高度差最大为1。
- 查询时间复杂度:O(log n)。
- 优缺点:自动保持平衡状态,查询时间效率较高;但插入和删除操作可能涉及多次“旋转”。
(3)全二叉树 (Complete Binary Tree)
- 特点:除最后一层外,其他层的节点数达到最大,并且最后一层的节点从左到右连续。
- 查询时间复杂度:O(log n)。
- 优缺点:适于顺序存储结构;不必像完满二叉树那样严格。
(4)红黑树 (Red-Black Tree)
- 特点:自平衡的二叉查找树。节点可以是红色或黑色,树满足特定的红黑性质。
- 查询时间复杂度:O(log n)。
- 优缺点:保证了最坏情况下的时间复杂度为O(log n);相对复杂的插入和删除操作。
(5)B树
- 特点:多路搜索树,通常用于数据库和文件系统。
- 查询时间复杂度:O(log n)。
- 优缺点:可以存储大量数据并减少磁盘I/O操作;结构比较复杂。
(6)B+树
- 特点:B树的扩展,所有的值都在叶子节点上,非叶子节点不存储数据,只用于索引。
- 查询时间复杂度:O(log n)。
- 优缺点:范围查询更加高效;每次查找都需要到达叶子节点。
区别和总结:
- 二叉树是最基础的数据结构,但不保证平衡。
- 平衡二叉树或AVL树确保了平衡,但需要在插入或删除时进行平衡操作。
- 完全二叉树尽可能地填充每一层,但不像满二叉树那样严格。
- 红黑树保证了最坏情况下的时间效率,但其结构和操作比AVL树更复杂。
- B树和B+树主要用于存储系统和数据库,优化磁盘I/O。B+树特别适合范围查询。
27、场景题:2个G的文件,里面有两或三条重复的数据记录,如何找出?
(1) 使用哈希函数:对每条数据记录计算哈希值。如果你的数据记录是字符串或其他数据类型,可以使用像MD5或SHA-1这样的哈希函数。计算哈希的目的是为了将大数据记录转化为较小的唯一标识符(哈希值),这样处理起来更加高效。
(2)外部排序:
- 因为2G的文件可能不适合全部加载到内存中,可以使用外部排序来处理它。首先,将文件划分为多个小的分块,使得每块可以被单独加载到内存中。
- 对每块数据使用内部排序算法(如快速排序或归并排序)进行排序。
- 使用多路归并排序算法合并所有已排序的分块。
(3)使用哈希表进行优化:
- 如果你的机器内存允许,可以考虑将数据的哈希值加载到一个哈希表中。
- 每次读取文件中的一条记录,计算其哈希值,然后查找哈希表中是否已存在该哈希值。
- 如果已存在,这条记录可能是重复的。可以对原始记录进行比较以确认是否真的重复。
注意:哈希函数可能会出现冲突,即不同的数据记录可能会有相同的哈希值。因此,当发现两条记录的哈希值相同时,应该进一步检查原始记录以确定是否确实重复。
服务器托管,北京服务器托管,服务器租用 http://www.fwqtg.net
相关推荐: 【Python】Locust持续优化:InfluxDB与Grafana实现数据持久化与可视化分析
前言 在进行性能测试时,我们需要对测试结果进行监控和分析,以便于及时发现问题并进行优化。 Locust在内存中维护了一个时间序列数据结构,用于存储每个事件的统计信息。 这个数据结构允许我们在Charts标签页中查看不同时间点的性能指标,但是正因为Locust …