当前位置:网站首页>1.整理华子面经--1
1.整理华子面经--1
2022-04-23 20:50:00 【兴趣使然的CV工程师】
细说项目中遇到的难点?
C++项目:
撤销恢复模块:
拥有三个属性:
QQueue<T> memo;//用于存储中间的逻辑的双向队列
int memoIndex;//用于找到当前位置前一个状态的索引
int capacity;//用于约束双向队列的行为,容量
主要函数:
- 有参初始化指定容量,无参初始化指定容量为Integer_Max;
- 获取上一个状态,获取当前状态
- 查看index是否在左右端点处
- 当传入一个新的备忘录对象的时候,当前索引之后的存储在队列中的对象,然后加入该对象
- 清空备忘录
底层模型数据结构设计,级联更新
以一个六面体网格为例,他需要保存的网格信息有,网格节点,网格线,网格面,网格单元,部件信息,这四者之间的关系是:
网格节点/网格线/网格面拥有它被哪些网格单元共有的信息,节点索引信息
网格单元/网格面/网格线有构成自己的网格节点顺序索引
网格节点拥有位置信息,是以上结构的基础
Java项目:
遇到的困难:人人开源返回类R的问题,Feign远程调用丢失请求头问题
项目经典逻辑:
合并购物车功能
背景:购物车分为离线购物车和在线购物车,离线购物车可以购买商品,在用户登录以后,离线购物车会被清空,所有商品被转移到在线购物车
- 存储:购物车数据放在redis中做持久化策略,因为经常要进行写操作,所以不适合放在mysql中
- ThreadLocal和Session和拦截器的使用:购物车服务中配置cookie,扩大cookie的作用域,使用springSession的redis类型作为session的存储,
- 在拦截器的preHandler方法中对Session中的用户对象进行处理(在登录模块放入),如果对象不为空,则为已经登录的用户,标记为可以合并购物车,从请求中拿到cookie区分用户,处理成购物车服务需要使用的对象Vo,放入ThreadLocal中避免对象多次跨方法传输
- 在拦截器的postHandler方法中获取到threadlocal中的对象,通过其属性值判断是否是临时用户或者第一次使用购物车的用户,此类用户需要设置cookie(常量key,用户id),在方法的最后remove对象
定时关单逻辑+自动解锁库存逻辑
秒杀逻辑
定时上架商品:定时任务扫描mysql将商品信息预热到redis中,考虑到分布式幂等性的问题,使用redisson分布式锁来实现
存储结构:一共有两块信息
- <场次+id,随机码>,随机码的作用是防止链接泄漏,提前拿到链接进行秒杀
- <随机码,商品数量>,使用redisson的分布式信号量来防止超卖
用户排重:用户如果已经进行了秒杀,使用一个key去redis中进行占位,以此来防止重复秒杀
异步削峰处理:在用户秒杀成功后,给rabbitMq发送消息,rabbitMq监听接口在拿到秒杀信息后,在数据库保存订单相关的结构
提交订单按钮的幂等性保证
在转到订单页的时候,在页面上存储一个token并且在redis中也存放一个token,在点击按钮的时候尝试删除这个token,如果删除成功就执行后续的操作,否则快速失败,其中检验token和删除token使用LUA脚本来保证原子操作
线程的优先级?操作系统线程和JVM线程?
Java中优先级分为1-10个级别,优先级高的线程得到的cpu资源多,线程优先级有继承特性,如果a线程启动了b线程,那么b线程将继承a线程的优先级
现在java中线程的本质其实就是操作系统中的线程,操作系统中进程的状态分为:创建,就绪,运行,等待和销毁,java的线程状态有创建,运行,等待,超时等待,阻塞和销毁
CAS怎么进行交换?
当要对变量进行修改的时候,会先将内存位置的值与预期的变量原值进行比较,如果一致就将内存位置更新为新值,否则不做操作,Java中的CAS的底层是Unsafe类和自旋锁,unsafe类中方法都是native修饰,不属于java代码,最后映射到操作系统的指令是cmpxchg;
数据库执行一条查询语句的过程?
- mysql执行器根据执行计划调用存储引擎的api查询数据
- 存储引擎先从缓存池buffer pool中查询数据,如果没有再去磁盘中查询,如果查询到了就将其放入缓存池中
- 在数据加载到buffer poll中的同时,会将这条数据的原始记录保存到undo log日志文件中
- innodb会在buffer poll中执行更新操作,更新后的数据会记录在redo log buffer中
- 提交事务在提交的同时会做三件事:将redo log buffer中的数据刷入redo log文件,将本次操作记录写入到bin log文件,将bin log文件名字和更新内容在bin log的位置记录到redo log中,同时在redo log最后添加commit标记
- 使用一个后台线程,它会在某个时机将我们buffer pool中的更新后的数据刷到mysql数据库中,这样保证内存和数据的统一
如何设计单点登录?
同域名下的单点登录:cookie的domain设置为当前父域,并且父域的cookie会被子域共享
不同域名下的单点登录:
方案一:由于不同域下的cookie不共享,可以部署一个认证中心,用于专门处理登录请求的独立web服务,用户在认证中心登录成功后,认证中心记录其登录状态,创建授权令牌,然后将授权令牌作为参数发送给各个子系统,应用系统通过检查当前请求有无token来了解用户登录状态;
方案二:在前后端分离框架中,将SessionId或者token保存到LocalStorage中,让前端每次向后端发送请求,主动将localStorage的数据传递给服务器,localstorage是html5的新特性,主要用于本地存储
最快最稳定的排序算法
Timsort结合了插入排序和归并排序,在数据量较少(<64)的情况下使用插入排序,否则使用归并排序+二分搜索来提高排序效率
Stream流式编程
- filter(T->boolean):保留boolean为true的元素
- distinct():去除重复元素,这个方法通过类的equals方法来判断元素相等,所以需要重写equals方法
- sorted((T,T)->int):排序
- limit(long n):返回前n个元素
- skip(long n):去除前n个元素
- map(T->R):把流中的每个元素T映射为R
- flatMap(T->stream):将流中的元素T映射为一个流
- boolean anyMatch/allMatch/noneMatch(T->boolean):流中是否有一个/所有/没有元素满足boolean条件
- reduce(T(初始值,可以没有),(T,T)->T):用于计算求和,最大值等
- count():返回流中元素个数,结果为long类型
- collect():收集器接口
- forEach:遍历
例题:筛选出年龄小于30并且id为偶数的用户名并且倒序输出
public static void main(String[] args) {
ArrayList<Person> people = new ArrayList<>();
people.add(new Person(1,10,"Charles"));
people.add(new Person(2,20,"Caarles"));
people.add(new Person(3,22,"Bharles"));
people.add(new Person(4,27,"Kharles"));
people.add(new Person(5,36,"Chazles"));
List<String> collect = people.stream().filter(a -> a.age < 30).filter(a -> a.id % 2 != 1).sorted((a, b) -> {
return b.name.compareTo(a.name);
}).map((a) -> a.name).collect(Collectors.toList());
for (String s : collect) {
System.out.println(s.toString());
}
//Kharles
//Caarles
}
Fork/Join是什么?
可以将一个大的任务拆分成多个子任务进行并行处理,以下是一个大量数字相加的简单的例子:
/**
* 这是一个简单的Join/Fork计算过程,将1—1001数字相加
*/
public class TestForkJoinPool {
private static final Integer MAX = 200;
static class MyForkJoinTask extends RecursiveTask<Integer> {
// 子任务开始计算的值
private Integer startValue;
// 子任务结束计算的值
private Integer endValue;
public MyForkJoinTask(Integer startValue , Integer endValue) {
this.startValue = startValue;
this.endValue = endValue;
}
@Override
protected Integer compute() {
// 如果条件成立,说明这个任务所需要计算的数值分为足够小了
// 可以正式进行累加计算了
if(endValue - startValue < MAX) {
System.out.println("开始计算的部分:startValue = " + startValue + ";endValue = " + endValue);
Integer totalValue = 0;
for(int index = this.startValue ; index <= this.endValue ; index++) {
totalValue += index;
}
return totalValue;
}
// 否则再进行任务拆分,拆分成两个任务
else {
MyForkJoinTask subTask1 = new MyForkJoinTask(startValue, (startValue + endValue) / 2);
subTask1.fork();
MyForkJoinTask subTask2 = new MyForkJoinTask((startValue + endValue) / 2 + 1 , endValue);
subTask2.fork();
return subTask1.join() + subTask2.join();
}
}
}
public static void main(String[] args) {
// 这是Fork/Join框架的线程池
ForkJoinPool pool = new ForkJoinPool();
ForkJoinTask<Integer> taskFuture = pool.submit(new MyForkJoinTask(1,1001));
try {
Integer result = taskFuture.get();
System.out.println("result = " + result);
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace(System.out);
}
}
}
其底层有多个工作队列,当通过invoke或者submit方法提交任务的时候,forkjoinpool根据一定的路由规则把任务提交到每个工作队列中,如果在任务执行过程中出现子任务,那么子任务会提交到工作线程对应的工作队列中,每个线程都维护着一个工作队列,这是一个双端队列,每个工作线程在处理自己的工作队列的同时,会尝试窃取一个任务,窃取的任务位于其他线程的工作队列的base,而新任务会放在工作队列的top,也就是说窃取时使用FIFO,处理自己队列时使用的是LIFO,在遇到join的时候,如果需要join的任务尚未完成,会先处理其他的任务并且等待其完成
Java默认有几个线程?
每当使用java命令执行一个类的时候,实际都会启用一个JVM,所以每个java运行的时候至少会启动两个线程,一个main线程,一个垃圾回收线程
二进制补码,反码?
- 反码:将二进制数按照位取反
- 补码:在反码的基础上+1得到补码
正数的源码,补码和反码都是一致的,要得到一个负数的二进制,首先拿到正数的二进制,取得反码后再得到补码
洗牌算法?
打乱一个没有重复元素的数组,在每次迭代中,生成一个范围在当下下标到数组末尾元素下标之间的随机整数,将当前元素与随机选出的下标所指定的元素进行交换,元素可以与自己进行交换
证明:设一个元素m被放入第i个位置的概率为P=前i-1个位置选择元素时没有选中m的概率*第i个位置选中m的概率
class Solution {
int[] array;
int[] original;
private Random random = new Random();
public Solution(int[] nums){
array = nums;
original = nums.clone();
}
public int[] reset(){
array = original;
original = original.clone();
return array;
}
public int[] shuffle(){
for(int i=0;i<array.length;i++){
int pickIdx = random.nextInt(array.length-i) + i;
int tmp = array[pickIdx];
array[pickIdx] = array[i];
array[i] = tmp;
}
return array;
}
}
版权声明
本文为[兴趣使然的CV工程师]所创,转载请带上原文链接,感谢
https://blog.csdn.net/weixin_51211461/article/details/124345508
边栏推荐
- A login and exit component based on token
- 居家第二十三天的午饭
- Opencv reports an error. Expected PTR < CV:: UMAT > for argument '% s'‘
- On the three paradigms of database design
- Reentrant function
- thinkphp5+数据大屏展示效果
- Psychological formula for converting RGB to gray value
- GO語言開發天天生鮮項目第三天 案例-新聞發布系統二
- Selenium 显示等待WebDriverWait
- Preliminary understanding of cache elimination algorithm (LRU and LFU)
猜你喜欢
Resolve the error - error identifier 'attr_ id‘ is not in camel case camelcase
Addition, deletion, modification and query of advanced MySQL data (DML)
A login and exit component based on token
Flex layout
CUDA, NVIDIA driver, cudnn download address and version correspondence
中创存储|想要一个好用的分布式存储云盘,到底该怎么选
GO语言开发天天生鲜项目第三天 案例-新闻发布系统二
Identifier CV is not defined in opencv4_ CAP_ PROP_ FPS; CV_ CAP_ PROP_ FRAME_ COUNT; CV_ CAP_ PROP_ POS_ Frames problem
vulnhub DC:1渗透笔记
Zhongchuang storage | how to choose a useful distributed storage cloud disk
随机推荐
GO語言開發天天生鮮項目第三天 案例-新聞發布系統二
Tensorflow and pytorch middle note feature map size adjustment to achieve up sampling
如何发挥测试策略的指导性作用
PHP的Laravel与Composer部署项目时常见问题
UKFslam
危机即机遇,远程办公效率为何会提升?
Prim、Kruskal
Keywords static, extern + global and local variables
MySQL基础合集
中创存储|想要一个好用的分布式存储云盘,到底该怎么选
管道和xargs
Vulnhub DC: 1 penetration notes
Factory mode
Matlab matrix index problem
laravel 发送邮件
Preliminary understanding of cache elimination algorithm (LRU and LFU)
Sharpness difference (SD) calculation method of image reconstruction and generation domain index
go defer
Bracket matching -- [implementation of one-dimensional array]
Psychological formula for converting RGB to gray value