JAVA - 总结
1.自我介绍+项目介绍
2.java常用的集合类有哪些?
set,list,map
3.线程安全的类有哪些
Vector:是一个同步的动态数组,使用synchronized关键字来保证线程安全。
Hashtable:是一个同步的哈希表,也使用synchronized关键字来保证线程安全。
ConcurrentHashMap:是一个线程安全的哈希表,使用锁分段技术来提高并发性能。
CopyOnWriteArrayList:是一个线程安全的动态数组,内部使用可重入锁来保证线程安全,对于读操作效率高。
4.HashMap1.8做了哪些改进?
1.链表到达一定条件会转换为红黑树
2.由头插法变为尾插法 5.你对设计模式有了解吗?挑一种讲讲
一共23种设计模式
单例模式 工厂模式
工厂模式是一种创建对象的设计模式,它通过将对象的创建逻辑封装在工厂类中,以提供统一的接口来创建对象。工厂模式可以隐藏对象的具体实现细节,使得对象的创建与使用相分离,提高了代码的灵活性和可维护性。
工厂模式主要包括三个角色:
抽象产品(Abstract Product):定义产品的共同接口,具体产品需要实现该接口。
具体产品(Concrete Product):实现抽象产品接口,是工厂模式所创建的对象。
工厂(Factory):负责创建具体产品的对象,提供统一的接口供客户端使用。
工厂模式的核心思想是将对象的创建过程封装在工厂类中,客户端通过调用工厂类的方法来获取所需的产品对象。这样做的好处是,当需要更换或增加新的产品时,只需要修改工厂类的代码,而不需要修改客户端的代码,符合开闭原则。
6.spring的理解(IOC和AOP)
Spring IOC 解决的是对象管理和对象依赖的问题。本来是我们自己手动new出来的对象,现在则把对象交给Spring的IOC容器管理 IOC容器可以理解为一个对象工厂,我们都把该对象交给工厂,工厂管理这些对象的创建以及依赖关系 等我们需要用对象的时候,从工厂里边获取就好了
「控制反转」指的就是:把原有自己掌控的事交给别人去处理 它更多的是一种思想或者可以理解为设计模式 比如:本来由我们自己new出来的对象,现在交由IOC容器,把对象的控制权交给它方了
「依赖注入」在我的理解下,它其实是「控制反转」的实现方式 对象无需自行创建或者管理它的依赖关系,依赖关系将被「自动注入」到需要它们的对象当中去
Spring AOP 解决的是 非业务代码抽取的问题 AOP 底层的技术是动态代理,在Spring内实现依赖的是BeanPostProcessor 比如我们需要在方法上注入些「重复性」的非业务代码,就可以利用Spring AOP 所谓的「面向切面编程」在我理解下其实就是在方法前后增加非业务代码
7.MyBatis里#{}和${}符号的区别是什么
${} 是将参数直接替换到SQL中 会出现安全问题
#{} 则是使用占位符的方式,用预处理的方式来执行业务
8.SQL优化会从哪些方面进行优化
1. 创建索引
禁止给表中每一列都建立单独索引
每个Innodb表都必须有一个主键
要注意组合索引的字段顺序
优先考虑覆盖索引
避免使用外键约束
2. 避免索引失效
失效场景:
以%开头的like查询
在索引列上的操作,函数操作,<> , != , not in , not exists , or 等
创建了组合索引,但是查询条件不满足最左匹配原则
查询条件中使用or,且or的前后条件中有一个列没有索引,则其中涉及的索引就都不会被使用
3. 锁粒度(行锁还是表锁)
4. 分页查询优化
5. 避免查询所有字段
6. 分析SQL的执行计划
7. show profile 分析SQL的执行性能
9.分库分表,分表要从哪些维度进行分(有1亿的订单表,进行分表从哪些维度进行拆分)
时间维度:按照订单生成时间进行分表,例如按照年份、月份、季度等时间段进行分表。这样可以将历史订单和最新订单分开存储,便于管理和维护。
地域维度:如果订单数据与地域相关,可以按照地域进行分表,比如按照国家、城市、省份等进行分表。这样可以将不同地域的订单分开存储,减少跨地域查询的开销。
业务维度:根据订单的业务属性进行分表,比如按照产品类型、订单类型、支付方式等进行分表。这样可以将不同类型的订单分开存储,提高查询效率。
用户维度:如果订单数据与用户相关,可以按照用户进行分表,例如按照用户ID进行哈希分表或者按照用户手机号码的后几位进行分表。这样可以将不同用户的订单分开存储,避免单表数据过大。
热度维度:根据订单的访问频率进行分表,将热点数据和冷数据分开存储。例如,将最近经常被查询的订单放在一个表中,将不经常访问的订单放在另一个表中,以提高查询效率。
热数据:使用mysql进行存储,当然需要分库分表;
冷数据:ES 或TiDB或Hive存储;
10.Redis的基本类型
11.Redis对热点数据如何处理
缓存热点数据:Redis 可以将经常访问的热点数据存储在内存中,以提高访问速度。通过将数据存储在内存中,可以快速读取和写入数据,减少对磁盘的访问,从而提高性能。
设置过期时间:对于热点数据,可以设置适当的过期时间,以保持数据的新鲜性。当数据过期时,Redis 会自动将其删除,从而释放内存空间。通过设置过期时间,可以避免内存被长时间占用,保持系统的稳定性。
使用数据结构:Redis 提供了丰富的数据结构,如字符串、哈希、列表、集合和有序集合等。根据数据的特点,选择合适的数据结构存储热点数据,以提高数据的访问效率。例如,对于计数器等场景可以使用 Redis 的原子操作来更新数据,保证数据的一致性。
使用缓存淘汰策略:当内存空间不足时,Redis 可以根据一定的策略淘汰部分数据以释放内存空间。常见的缓存淘汰策略包括LRU(最近最少使用)、LFU(最不经常使用)、随机淘汰等。通过合理选择淘汰策略,可以保证热点数据的存储并释放空间。
使用分区和复制:对于特别大的热点数据,可以使用 Redis 的分区和复制功能,将数据分散存储在多个节点上,以提高系统的扩展性和容错性。通过分区和复制,可以将热点数据均匀分布在多个节点上,避免单节点压力过大。 12.Redis做过分布式锁吗
基于 SETNX 和 EXPIRE 实现简单的分布式锁:
使用 SETNX 命令来设置一个键的值,如果该键不存在,则设置成功,返回 1,表示获得了锁;
使用 EXPIRE 命令设置键的过期时间,确保在一段时间后锁会自动释放;
在释放锁时,可以使用 DEL 命令来删除键 13.springcloud用过哪些组件
14.nacos注册中心的主要作用
15.服务间调用用的是那个组件(feign)
16.MQ如何避免重复消费问题
消息去重机制:
在消息生产端生成消息时,为每条消息生成一个唯一标识符,比如消息ID。
在消息消费端,在处理消息之前,先检查该消息的唯一标识符是否已经被处理过,如果已经处理过,则丢弃该消息,否则继续处理。
消息去重可以通过数据库、缓存或者分布式存储等方式实现,确保消息的唯一性。
消息消费确认机制:
消费端消费完消息后,向消息队列发送确认消息,告知消息队列该消息已经被成功处理。
消息队列在接收到消费端的确认消息后,将该消息标记为已消费,避免重复发送给其他消费者。
通过消息消费确认机制,可以确保每条消息只会被处理一次。
消息幂等性处理:
在设计消费端的业务逻辑时,尽量保证处理消息的业务逻辑是幂等的,即多次处理同一条消息的结果和一次处理的结果是一样的。
这样即使消息被重复消费,也不会对系统造成影响。
消息延迟重试:
如果消息消费端出现异常或者网络问题导致消息处理失败,可以使用消息队列的重试机制,将消息重新发送给消费者进行处理。
在重试过程中,可以设置一定的延迟时间,避免过于频繁地重试。
消息状态管理:
消费端在处理消息时,可以将消息的处理状态记录到数据库或者缓存中,确保同一条消息不会被重复处理 17.对jdk8新特性了解多少
18.jdk8中Stream流问题
能让我们快速完成许多复杂的操作,如筛选、切片、映射、查找、去除重复,统计,匹配和归约。
19.你想问我什么
1.自我介绍+项目介绍
2.java中的对象拷贝
3.日常工作中如何实现一个深拷贝
a.使用序列化和反序列化: 将对象序列化为字节流,然后再反序列化为新的对象。这种方法可以实现对象的完全复制,包括对象内部的所有属性和引用对象。需要注意的是,被拷贝的对象及其引用对象都必须实现 Serializable 接口。
b.递归复制: 遍历对象的所有属性,并递归地复制引用类型的属性。这种方法需要确保对象及其引用对象都是可变的,否则会出现浅拷贝。
c.使用第三方库: 可以使用一些第三方库如 Apache Commons Lang 或 Gson 提供的深拷贝方法。这些库提供了更简单的方式来实现对象的深拷贝。 4.ArrayList和LinkedList的区别
当需要频繁地进行随机访问操作时,应选择 ArrayList;当需要频繁进行插入和删除操作时,应选择 LinkedList
5.日常工作中HashMap常用方法有哪些
put(key, value): 将指定的键值对存储到 HashMap 中。
get(key): 根据键获取对应的值。
containsKey(key): 判断 HashMap 中是否包含指定的键。
containsValue(value): 判断 HashMap 中是否包含指定的值。
remove(key): 根据键移除对应的键值对。
size(): 返回 HashMap 中键值对的数量。
isEmpty(): 判断 HashMap 是否为空。
clear(): 清空 HashMap 中的所有键值对。
keySet(): 返回 HashMap 中所有键组成的集合。
values(): 返回 HashMap 中所有值组成的集合。
entrySet(): 返回 HashMap 中所有键值对组成的集合。
putAll(map): 将另一个 Map 中的所有键值对存储到当前 HashMap 中。
replace(key, value): 替换指定键的值。
replace(key, oldValue, newValue): 替换指定键的值,仅当当前值与给定的旧值相等时才替换。
computeIfAbsent(key, mappingFunction): 如果指定的键不存在,则根据提供的函数计算其值并存储。
computeIfPresent(key, remappingFunction): 如果指定的键存在,则根据提供的函数计算其新值并存储。
compute(key, remappingFunction): 根据指定的键和函数计算新值,并存储。
merge(key, value, remappingFunction): 将指定键的值与给定值组合,并存储结果。
forEach(action): 对 HashMap 中的每个键值对执行指定操作。 6.日常工作中ConcurrenHashMap常用方法有哪些
7.多线程中,线程池的工作原理
线程池的创建: 在应用程序启动时,通过创建线程池对象来初始化线程池。可以设置线程池的核心线程数、最大线程数、线程存活时间等参数。
任务提交: 当应用程序有任务需要执行时,将任务提交给线程池。任务可以是实现了Runnable接口或Callable接口的对象。
任务队列: 线程池内部维护一个任务队列,用于存放提交的任务。如果线程池中的线程数未达到核心线程数,则会创建新的线程来执行任务,否则将任务添加到任务队列中等待执行。
线程执行任务: 线程池中的线程从任务队列中获取任务,并执行任务的run方法。
线程复用: 执行完任务后,线程并不被销毁,而是继续留在线程池中等待下一个任务的到来,从而减少了线程的创建和销毁开销。
核心线程数和最大线程数的控制: 线程池中的线程数量由核心线程数和最大线程数来控制。如果线程池中的线程数量超过核心线程数,但未达到最大线程数,则线程池会根据任务队列的情况决定是否创建新的线程来执行任务。
线程池的扩容和缩容: 如果任务队列中的任务过多,导致线程池中的线程数已经达到最大线程数,则可以根据需要动态地扩容线程池。相反,如果线程池中的线程长时间处于空闲状态,可以根据需要动态地缩减线程池的大小,释放系统资源。
异常处理: 线程池会捕获任务执行过程中抛出的异常,并根据配置进行处理,比如记录日志、重新执行任务等。 8.拒绝策略有几种情况
1.直接丢弃任务,抛异常
2.不丢弃,用当前线程去执行任务
3.忽略,不抛异常
4.移除最早进入队列的任务
5.还可以实现一共拒绝策略处理器接口自己定义拒绝策略
延伸:我们公司用的是不拒绝,因为我们公司的业务不能丢失
9.spring中Bean的组装过程
Spring中Bean的组装过程主要分为三个步骤:实例化、属性注入和初始化。
实例化:Spring容器根据配置文件或注解的信息,创建Bean的实例。可以通过构造方法实例化,也可以通过工厂方法实例化。
属性注入:在实例化Bean后,Spring容器会通过依赖注入的方式,将配置文件或注解中定义的属性值注入到Bean中。依赖注入可以通过构造器注入、setter方法注入或直接注入到字段上。
初始化:在属性注入完成后,Spring容器会调用Bean的初始化方法,进行一些自定义的初始化操作。初始化方法可以是实现了InitializingBean接口的afterPropertiesSet()方法,也可以是通过@Bean注解中的initMethod属性指定的自定义初始化方法。
在组装完成后,Bean就可以在应用中使用了。Spring容器会管理Bean的生命周期,包括创建、销毁等操作。
Sharding-JDBC/Mycat的不同点:
他们类似于SpringCloud Ribbon与Nginx区别。
Mycat是基于Proxy,类似于nginx,它复写了MySQL协议,将MycatServer伪装成一个MySQL数据库。优点是保证数据库的安全性,归并数据结果完全解耦,缺点是效率偏低。
Sharding-JDBC是基于JDBC的扩展,是以jar包的形式提供轻量级服务的。优点是效率较高,缺点是归并数据结果没有实现解耦,有可能会影响到我们业务逻辑代码。还容易内存溢出,所以要做分页处理。
MyCat是一个第三方服务器端数据库中间件,客户端所有的jdbc请求都必须要先交给MyCat,再有MyCat转发到具体的真实服务器中。
Sharding-Jdbc是一个本地数据库中间件框架,采用Jar形式,在本地应用层重写Jdbc原生的方法,实现数据库分片形式。
什么是全文检索?
全文检索是指计算机索引程序通过扫描文章中的每一个词,对每一个词建立一个索引,指明该词在文章中出现的次数和位置,当用户查询时,检索程序就根据事先建立的索引进行查找,并将查找的结果反馈给用户的检索方式。这个过程类似于通过字典中的检索字表查字的过程。
全文检索可以简单理解为通过索引搜索文章。
1. 设计并发查询接口时,针对热点数据、读多写少、字典数据均使用Redis进行缓存,优化查询性能,并针对性的设计TTL过期时间,以及一些常规的缓存问题进行处理;
2. 针对热点文章,使用Freemarker视图渲染模版引擎,实现页面静态化,将静态化资源部署到nginx服务器,降低对tomcat的压力;
3. 使用Redis的ZSet进行分值计算,求出某时间段内的热点文章、热点资讯;
4. 使用MinIO搭建分布式文件存储集群,存储图像、视频、音频等项目资源;
5. 使用OCR技术,实现图文识别功能,将图片中的文字提取,并进行录入;
6. 使用Redis的Zset数据类型的去重有序(分数排序)特点实现延迟队列效果,在审核文章场景、发布文章场景中有所应用;
7. 为了应对海量数据采集、审核、存储,所以使用Kafka作为中间件进行缓冲,填补采集(生产)与审核(消费)速率不协调的问题;
8. 在分布式检索场景中,使用Elasticsearch实现检索服务设计,基于倒排索引和分词机制,更加精准、高效的实现查询;
9. 在定时业务场景中,如:定时发布、下架、计算热点文章业务场景中,使用XXL-JOB实现分布式定时任务调度;
1. 自定义切面,实现公共字段填充,如:创建时间、创建人ID、修改时间、修改人ID
2. 在素材管理模块中,采用七牛云云存储保存视频、音频、图片等资源;
3. 使用Redis缓存店铺状态、SKU分类数据、商品套餐信息、用户购物车套餐数据;
4. 对接微信登录,并自定义封装了HttpClient工具类,自定义对接微信接口的方法,如:微信登录、获取用户资源等方法;
5. 基于JWT封装用户Token,并自定义封装了拦截器校验JWT的数据有效性;
6. 使用SpringCache优化了缓存编码设计;
7. 生成订单的时候,基于Redis,使用防重Token进行幂等性校验,防止重复提交;
8. 使用Spring Task定时扫描超时未支付的订单及时关闭;超时却处于派送的订单,会发送到MQ中,由客服系统人工介入;
9. 使用WebSocket全双工协议,设计商家听单(接单、催单)业务需求以及客户、配送、商家的在线聊天设计;
10. 在平台运营管理端,数据统计模块中,使用Apache Echarts多种图表对接后端接口,展示营业数据、用户统计数据、订单统计,使用Apache POI完成各项经营数据的导出;
11.整合高德地图轨迹服务,电子围栏,划分派送范围,实现实时查询骑手的运动轨迹;