携程的面试比较注重八股文和项目,算法相关没有字节腾讯严厉,大家参加携程的技术岗面试需要重视八股文和项目细节,要学会深挖项目,希望大家早日oc😊👍
HashMap底层原理,扩容机制,从并发问题引出ConcurrentHashMap,问如何上锁
HashMap底层原理:
- HashMap 基于数组和链表(在 JDK 1.8 之后引入了红黑树)实现。它通过哈希函数将键映射到数组的索引位置上。
- 当发生哈希冲突时,会将相同索引位置的元素存储在一个链表中或转换为红黑树。
扩容机制:
- 当 HashMap 中的元素数量超过数组容量的负载因子(默认 0.75)时,会触发扩容操作,将容量加倍并重新分配所有元素到新的数组中。
- 扩容时需要重新计算所有元素的哈希值,并重新插入到新的数组位置上。
并发问题与 ConcurrentHashMap:
- HashMap 在多线程环境中会出现数据不一致的问题,例如死循环、数据丢失等。
- ConcurrentHashMap 通过分段锁机制进行并发控制,将整个 Map 分成多个 Segment,每个 Segment 独立加锁,减少锁竞争。
- JDK 8 之后,ConcurrentHashMap 改用 CAS(Compare-And-Swap)和 Synchronized 结合的方式来提高并发性能。
线程通信的方式
- wait() 和 notify()/notifyAll():通过对象监视器进行通信,wait() 使线程等待,notify() 唤醒等待的线程。
- Condition:Java 5 引入的更灵活的线程通信机制,与 ReentrantLock 结合使用。
- 阻塞队列(BlockingQueue):生产者-消费者模式下常用,如 ArrayBlockingQueue、LinkedBlockingQueue。
- 信号量(Semaphore):控制同时访问特定资源的线程数量。
- 管道流(PipedInputStream 和 PipedOutputStream):用于线程间数据传输。
线程池参数以及线程池的好处
线程池参数:
- corePoolSize:核心线程数,始终保持在线的线程数量。
- maximumPoolSize:最大线程数,线程池能容纳的最大线程数。
- keepAliveTime:空闲线程存活时间,当线程数超过核心线程数时,多余的空闲线程会在指定时间后终止。
- unit:keepAliveTime 的时间单位。
- workQueue:用于存放等待执行任务的队列。
- threadFactory:线程工厂,用于创建新线程。
- handler:拒绝策略,当任务队列已满且无法继续创建线程时,处理新任务的策略。
线程池的好处:
- 重用线程:减少了频繁创建和销毁线程的开销。
- 控制最大并发数:通过配置最大线程数来控制并发数量,防止系统资源耗尽。
- 管理任务队列:有助于任务的排队和调度。
- 提高响应速度:线程池中的线程可以及时处理新任务,减少等待时间。
Mysql索引底层数据结构,用B+树的好处
Mysql索引底层数据结构:
- B+树 是 MySQL 索引的主要数据结构,适用于大多数存储引擎,如 InnoDB。
- B+树是一种平衡树,所有叶子节点在同一层,并通过双向链表连接。
B+树的好处:
- 有序性:有助于范围查询和排序操作。
- 磁盘读写效率高:B+树节点包含多个元素,一次磁盘读取可以获取更多数据,减少磁盘I/O次数。
- 查询效率高:通过树的平衡性保证查询的时间复杂度为 O(log n)。
- 适合范围查询:通过叶子节点的链表,可以高效地进行范围查询。
索引的类型
- 主键索引(Primary Key Index):唯一标识表中的每一行,不允许重复和空值。
- 唯一索引(Unique Index):保证列中的值唯一,但允许空值。
- 普通索引(Index):加速查询,没有唯一性限制。
- 全文索引(Full-text Index):用于全文搜索,如匹配关键字。
- 组合索引(Composite Index):在多个列上创建的索引,加速多条件查询。
如何优化查询语句
- 使用合适的索引:建立并使用索引,避免全表扫描。
- 选择合适的字段:只查询必要的字段,减少数据传输量。
- 避免使用 SELECT *:明确指定查询的列。
- 使用 WHERE 子句过滤数据:减少结果集的大小。
- 避免在 WHERE 子句中进行函数运算:可能导致索引失效。
- 使用 JOIN 代替子查询:提高查询效率。
- 适当使用 LIMIT:限制结果集大小,减少不必要的数据处理。
- 分析查询执行计划:使用 EXPLAIN 关键字查看查询的执行计划,找出瓶颈。
网络七层模型和四层模型的区别
网络七层模型(OSI模型):
- 物理层:传输原始比特流。
- 数据链路层:提供节点间的数据传输,进行帧的传输和纠错。
- 网络层:负责数据包的路由和转发。
- 传输层:提供端到端的通信,确保数据完整性和可靠传输。
- 会话层:管理会话,控制建立、维护和终止会话。
- 表示层:数据的表示、加密和解密、数据格式转换。
- 应用层:提供应用服务,如HTTP、FTP、SMTP等。
四层模型(TCP/IP模型):
- 网络接口层:对应OSI模型的物理层和数据链路层。
- 互联网层:对应OSI模型的网络层。
- 传输层:对应OSI模型的传输层。
- 应用层:对应OSI模型的会话层、表示层和应用层。
输入网址到网页显示,期间发生了什么
- DNS解析:将域名转换为IP地址。
- 建立TCP连接:通过三次握手与服务器建立TCP连接。
- 发送HTTP请求:客户端向服务器发送HTTP请求报文。
- 服务器处理请求:服务器处理请求并生成响应。
- 发送HTTP响应:服务器将响应报文返回给客户端。
- 浏览器渲染页面:浏览器解析HTML、CSS、JavaScript等文件,构建DOM树和渲染树,绘制页面。
网络传输如何保证可靠性和安全性
可靠性:
- TCP协议:通过序列号、确认机制、重传机制和窗口控制实现可靠数据传输。
- 错误检测:使用校验和等方法检测并纠正传输错误。
- 拥塞控制:避免网络拥塞,提高传输效率。
安全性:
- 加密:使用TLS/SSL协议加密数据,保护传输过程中的数据安全。
- 身份验证:验证通信双方的身份,防止伪装和中间人攻击。
- 数据完整性:使用消息摘要算法确保数据在传输过程中未被篡改。
手撕算法:最大连续子数组和(hot 100)
问题描述: 找到一个整数数组的一个连续子数组,使得该子数组的和最大,并返回这个最大和。
示例代码(Java):
public int maxSubArray(int[] nums) {
int maxSoFar = nums[0];
int maxEndingHere = nums[0];
for (int i = 1; i < nums.length; i++) {
maxEndingHere = Math.max(nums[i], maxEndingHere + nums[i]);
maxSoFar = Math.max(maxSoFar, maxEndingHere);
}
return maxSoFar;
}
解释:
- 初始化:
maxSoFar
和maxEndingHere
都初始化为数组的第一个元素。 - 迭代:遍历数组,对于每个元素,更新
maxEndingHere
为当前元素和maxEndingHere
之和的较大值。 - 更新最大值:每次都更新
maxSoFar
为maxSoFar
和maxEndingHere
中的较大值。 - 返回结果:返回
maxSoFar
即为最大子数组和。