4.22腾讯CDG后台开发一面

  • 腾讯
  • 一面
大约 9 分钟全民制作人ikun

4.22腾讯CDG后台开发一面

1.自我介绍

2.介绍一下tcp协议?如何唯一确定一个tcp连接?

参考链接open in new window

TCP(传输控制协议)是一种面向连接的、可靠的、基于字节流的传输层协议。它主要具有以下特点:

  1. 面向连接:一定是「一对一」才能连接,不能像 UDP 协议可以一个主机同时向多个主机发送消息,也就是一对多是无法做到的;

  2. 可靠的:无论的网络链路中出现了怎样的链路变化,TCP 都可以保证一个报文一定能够到达接收端;

  3. 字节流:用户消息通过 TCP 协议传输时,消息可能会被操作系统「分组」成多个的 TCP 报文,如果接收方的程序如果不知道「消息的边界」,是无法读出一个有效的用户消息的。并且 TCP 报文是「有序的」,当「前一个」TCP 报文没有收到的时候,即使它先收到了后面的 TCP 报文,那么也不能扔给应用层去处理,同时对「重复」的 TCP 报文会自动丢弃。

TCP 四元组可以唯一的确定一个连接,四元组包括如下:

  • 源地址
  • 源端口
  • 目的地址
  • 目的端口

3.Http是基于什么协议?

参考链接open in new window

  • HTTP 协议是基于 TCP/IP,并且使用了「请求 - 应答」的通信模式,所以性能的关键就在这两点里。

  • HTTP/2 协议是基于 HTTPS 的,所以 HTTP/2 的安全性也是有保障的。

  • HTTP/3 把 HTTP 下层的 TCP 协议改成了 UDP!基于 UDP 的 QUIC 协议 可以实现类似 TCP 的可靠性传输

4.为什么是三次握手,两次四次会有什么问题?

参考连接open in new window

首先看两次,三次,四次分别是什么?

两次握手:

  • A发送同步信号SYN+A的初始序列号
  • B发送同步信号SYN+B的初始序列号+B的ACK序列号

三次握手:

  • A发送同步信号SYN+A的初始序列号
  • B确认收到A的SYN,发送SYN+B的初始序列号 + B的ACK序列号(确认A的序列号)
  • A确认收到B的SYN+ACK,发送ACK报文

四次握手:

  • A发送同步信号SYN+A的初始序列号
  • B确认收到A的同步信号,并记录A的ISN到本地,命名B的ACK序列号
  • B发送同步信号SYN+B的初始序列号
  • A确认收到B的同步信号,并记录B的ISN到本地,命名A的ACK序列号

TCP 建立连接时,通过三次握手能防止历史连接的建立,能减少双方不必要的资源开销,能帮助双方同步初始化序列号。序列号能够保证数据包不重复、不丢弃和按序传输。

不使用「两次握手」和「四次握手」的原因:

  • 「两次握手」:无法防止历史连接的建立,会造成双方资源的浪费,也无法可靠的同步双方序列号;
  • 「四次握手」:三次握手就已经理论上最少可靠连接建立,所以不需要使用更多的通信次数。

5.什么是IOC?

参考链接open in new window

IOC(Inversion of Control,控制反转)是一种设计模式,它颠覆了传统的代码编写方式,将对象的创建和依赖管理的控制权从程序本身转移到外部容器(如框架或库)。是一种思想不是一个技术实现。

IOC 的核心思想是:

  1. 创建对象的控制权不在程序内部,而是交由外部容器负责。
  2. 对象之间的依赖关系也由外部容器来管理,程序不需要自己管理依赖。

例如:现有类 A 依赖于类 B

  • 传统的开发方式 :往往是在类 A 中手动通过 new 关键字来 new 一个 B 的对象出来
  • 使用 IoC 思想的开发方式 :不通过 new 关键字来创建对象,而是通过 IoC 容器(Spring 框架) 来帮助我们实例化对象。我们需要哪个对象,直接从 IoC 容器里面去取即可。

为什么叫控制反转?

  • 控制 :指的是对象创建(实例化、管理)的权力
  • 反转 :控制权交给外部环境(IoC 容器)

6.Spring在容器启动阶段会做什么?

参考链接open in new window

  1. 加载配置文件:Spring容器会从指定的配置文件中读取配置信息,包括bean的定义、依赖关系open in new window、AOP切面等。
  2. 创建容器:Spring容器启动后会创建一个容器实例,容器负责管理bean的生命周期和依赖关系。
  3. 扫描包并创建bean定义:Spring容器会扫描指定的包路径,自动创建包中标注了@Component、@Service、@Controller、@Repository等注解的类的bean定义。
  4. 解析依赖关系:Spring容器会根据bean定义中的依赖关系,自动将依赖的bean注入到需要的bean中。
  5. 初始化bean:容器会按照指定的顺序依次对bean进行初始化,包括实例化、属性注入、初始化方法执行等。
  6. 设置代理对象:如果bean需要被AOP切面增强,则容器会为其创建代理对象。
  7. 完成容器初始化:所有bean初始化完成后,Spring容器启动完成。

7.Bean定义和依赖定义有哪些方式?

参考链接open in new window

有三种方式:直接编码方式配置文件方式注解方式

  • 直接编码方式:我们一般接触不到直接编码的方式,但其实其它的方式最终都要通过直接编码来实现。
  • 配置文件方式:通过xml、propreties类型的配置文件,配置相应的依赖关系,Spring读取配置文件,完成依赖关系的注入。
  • 注解方式:注解方式应该是我们用的最多的一种方式了,在相应的地方使用注解修饰,Spring会扫描注解,完成依赖关系的注入。

8.有哪些依赖注入的方法?

Spring支持构造方法注入Setter注入属性注入工厂方法注入,其中工厂方法注入,又可以分为静态工厂方法注入非静态工厂方法注入

9.Spring的Bean的作用域有哪些?几种在web应用中使用的作用域,了解吗?

Spring Bean支持作用域

  • singleton : 在Spring容器仅存在一个Bean实例,Bean以单实例的方式存在,是Bean默认的作用域。
  • prototype : 每次从容器重调用Bean时,都会返回一个新的实例。

以下三个作用域于只在Web应用中适用:

  • request : 每一次HTTP请求都会产生一个新的Bean,该Bean仅在当前HTTP Request内有效。
  • session : 同一个HTTP Session共享一个Bean,不同的HTTP Session使用不同的Bean。
  • globalSession:同一个全局Session共享一个Bean,只用于基于Protlet的Web应用,Spring5中已经不存在了。

10.Spring中的单例Bean会存在线程安全问题吗?

首先结论在这:Spring中的单例Bean不是线程安全的

因为单例Bean,是全局只有一个Bean,所有线程共享。如果说单例Bean,是一个无状态的,也就是线程中的操作不会对Bean中的成员变量执行查询以外的操作,那么这个单例Bean是线程安全的。比如Spring mvc 的 Controller、Service、Dao等,这些Bean大多是无状态的,只关注于方法本身。

假如这个Bean是有状态的,也就是会对Bean中的成员变量进行写操作,那么可能就存在线程安全的问题。

解决办法:

  1. 将Bean定义为多例这样每一个线程请求过来都会创建一个新的Bean,但是这样容器就不好管理Bean,不能这么办。
  2. 在Bean对象中尽量避免定义可变的成员变量削足适履了属于是,也不能这么干。
  3. 将Bean中的成员变量保存在ThreadLocal中⭐我们知道ThredLoca能保证多线程下变量的隔离,可以在类中定义一个ThreadLocal成员变量,将需要的可变成员变量保存在ThreadLocal里,这是推荐的一种方式。

11.Spring中循环依赖问题了解过吗?

12.循环依赖问题会发生在哪些Spring作用域中?

13.一定要三级缓存吗,两级不行吗?

14.AOP了解过吗?这样做有什么好处?

15.AOP的实现是动态代理,那你知道Spring中的AOP是怎么实现的吗?

16.JDK动态代理和CGLib动态代理分别怎么选择?

17.Spring的事务有哪些?声明式事务和编程式事务深入了解过吗?————没深入了解过,pass跳过

18.Java对象创建的过程了解吗?

19.有听过指针碰撞吗?

20.如果你来设计一门语言,你觉得GC要做哪些事?

21.Redis在实际项目中使用过吗,什么场景下用的?

22.在什么场景下需要使用分布式锁?

23.Redis有哪些常用数据结构,底层分别怎么实现?

24.粉丝点赞排行榜怎么实现?zset的函数使用使用过吗?具体点score存什么?

25.听说过延迟队列吗?

26.如何通过Redis实现分布式锁,底层讲讲?穿插一些项目中redis的使用

27.MySQL有哪些常用存储引擎?MyISAM和InnoDB在主键上有区别吗?在count方法执行上有区别吗?

28.聚簇索引和非聚簇索引?为什么要用B+树?

29.有了解过意向锁吗?

30.挑一个有挑战的项目聊聊?

31.手撕:两个有序数组合并为一个有序数组

题目链接open in new window

class Solution {
public:
    void merge(vector<int>& nums1, int m, vector<int>& nums2, int n) {
        int cur = n+m-1;
        m--,n--;
        while(cur>=0){
            if(n<0) while(cur>=0 &&m>=0) nums1[cur--]=nums1[m--];
            if(m<0) while(cur>=0 &&n>=0)nums1[cur--]=nums2[n--];
            if(n>=0 && m>=0){
                if(nums1[m]>=nums2[n]) nums1[cur--]=nums1[m--];
                else nums1[cur--]=nums2[n--];
            }
        }
    }
};

32.反问?