不愧是字节跳动,今年这薪资。。

科技   2024-11-12 14:04   河南  

大家好,我是二哥呀。

字节也开奖了,薪资待遇整体和去年变化不大,但也配得上互联网一线梯队的水平了。我这里同步了一些《Java 面试指南》中收录的信息给大家做个参考,好看看自己处在一个什么样的段位。

  • 硕士 985,上海地区,后端岗,能开到 32k*15,逼近 50 万了,算是 SSP 吧
  • 硕士 211,开发岗,开到了 26k*15,算是小 SP,北京地区
  • 硕士 985,开发岗,也是 26k*15,不过是上海地区,本来打算拿字节 A 别家的,结果这个薪资完全拿不出手
  • 产品经理岗,开到了 24Kx15,北京,算是 sp,但打算拒了,感觉性价比不高

从目前已有的信息来看,字节的薪资和去年变化不大,不像京东那样,给的年包让人都不敢接。

字节跳动自2012年成立以来,已发展成为涵盖多领域的全球科技公司。其核心业务主要包括:

  • 内容平台:旗下拥有抖音(国际版为TikTok)和今日头条等产品,程序员社区网站掘金也算一个。
  • 社交媒体:飞书,企业协作和沟通工具,口碑很高。
  • 大模型:目前主推的豆包,我之前给大家也推荐过它们的豆包MarsCode 代码练习平台,还不错
  • 其他 APP:像兼营、番茄小说、face激萌、轻颜相机等也都是字节旗下的产品
截图来自知乎的GoeCycle

那接下来,我们就以Java 面试指南中收录的字节同学 17 后端技术面试为例来看看,字节的的面试官都喜欢问哪些技术问题。

背八股就认准三分恶的面渣逆袭

字节同学 17 后端技术面试

面向对象 项目里有哪些面向对象的案例

面向对象是以对象为核心,通过对象交互完成任务,程序结构是类和对象组成的模块化结构,代码可以通过继承、组合、多态等方式复用。

在技术派实战项目中,像 VO、DTO 都是业务抽象后的对象实体类,而 Service、Controller 则是业务逻辑的实现,这其实就是面向对象的思想。

技术派实战项目源码截图

jvm结构 运行时数据区有什么结构 堆存什么

JVM 大致可以划分为三个部分:类加载器、运行时数据区和执行引擎。

截图来源于网络

按照 Java 的虚拟机规范,JVM 的内存区域(JVM 的内存结构/JVM 运行时数据区)可以细分为程序计数器虚拟机栈本地方法栈方法区等。

三分恶面渣逆袭:Java虚拟机运行时数据区

其中方法区是线程共享的,虚拟机栈本地方法栈程序计数器是线程私有的。

堆是 JVM 中最大的一块内存区域,被所有线程共享,在 JVM 启动时创建,主要用来存储对象的。

二哥的 Java 进阶之路:堆

垃圾回收机制 为什么要学jvm 内存泄漏场景

垃圾回收(Garbage Collection,GC)就是对内存堆中已经死亡的或者长时间没有使用的对象进行清除和回收。

JVM 在做 GC 之前,会先搞清楚什么是垃圾,什么不是垃圾,通常会通过可达性分析算法来判断对象是否存活。

二哥的 Java 进阶之路:可达性分析

在确定了哪些垃圾可以被回收后,垃圾收集器(如 CMS、G1、ZGC)要做的事情就是进行垃圾回收,可以采用标记清除算法、复制算法、标记整理算法、分代收集算法等。

技术派项目使用的 JDK 8,所以默认采用的是 CMS 垃圾收集器。

为什么要学习 JVM?

学习 JVM 可以帮助我们更好地优化程序性能、避免内存问题。

首先,了解 JVM 的内存模型和垃圾回收机制,可以帮助我们合理配置内存、减少 GC 停顿。

此外,掌握 JVM 的类加载机制可以帮助排查类加载冲突或异常。

JVM 还提供了很多调试和监控工具,比如使用 jmap 和 jstat 可以分析内存和线程的使用情况。

内存泄漏可能由哪些原因导致呢?

比如说:

①、静态的集合中添加的对象越来越多,但却没有及时清理;

public class OOM {
 static List list = new ArrayList();

 public void oomTests(){
   Object obj = new Object();

   list.add(obj);
  }
}

②、单例模式下对象持有的外部引用无法及时释放;

③、数据库、IO、Socket 等连接资源没有及时关闭;

try {
    Connection conn = null;
    Class.forName("com.mysql.jdbc.Driver");
    conn = DriverManager.getConnection("url""""");
    Statement stmt = conn.createStatement();
    ResultSet rs = stmt.executeQuery("....");
  } catch (Exception e) {

  }finally {
    //不关闭连接
  }

④、变量的作用域不合理;

class Simple {
    Object object;
    public void method1(){
        object = new Object();
        //...其他代码
        //由于作用域原因,method1执行完成之后,object 对象所分配的内存不会马上释放
    }
}

⑤、hash 值发生变化但对象却没有改变,这也是为什么 String 被设计成不可变对象的原因之一,就是因为假如 String 的哈希值发生了改变,但对应的值没变,就导致 HashMap 中的对象无法被及时清理;

⑥、使用完 ThreadLocal 没有使用 remove 方法来进行清除。

堆这个数据结构的应用场景和特点

堆是一种完全二叉树的数据结构,主要分为最大堆和最小堆。堆的特点是插入和删除的时间复杂度都是 O(log n)。

堆的应用场景包括:优先队列、Top K 问题、堆排序、合并 K 个有序链表以及动态数据流的中位数等。

用过哪些策略模式

策略模式是一种行为型设计模式,它定义了一系列的算法,将每个算法封装起来,使得它们可以相互替换。这种模式通常用于实现不同的业务规则,其中每种策略封装了特定的行为或算法。

图片来源于天未(闵大为)

特别适合优化程序中的复杂条件分支语句(if-else)。

在策略模式中,有三个角色:上下文、策略接口和具体策略。

  • 策略接口:定义所有支持算法的公共接口。
  • 具体策略:实现策略接口的类,提供具体的算法实现。
  • 上下文:使用策略的类。通常包含一个引用指向策略接口,可以在运行时改变其具体策略。
技术派教程

比如说在技术派中,用户可以自由切换 AI 服务,服务端可以通过 if/esle 进行判断,但如果后续需要增加新的 AI 服务,就需要修改代码,这样不够灵活。

因此,我们使用了策略模式,将不同的 AI 服务封装成不同的策略类,通过工厂模式创建不同的 AI 服务实例,从而实现 AI 服务的动态切换。

@Service
public class PaiAiDemoServiceImpl extends AbsChatService {

    @Override
    public AISourceEnum source() {
        return AISourceEnum.PAI_AI;
    }
}

@Slf4j
@Service
public class ChatGptAiServiceImpl extends AbsChatService {
    @Override
    public AISourceEnum source() {
        return AISourceEnum.CHAT_GPT_3_5;
    }
}

@Slf4j
@Service
public class XunFeiAiServiceImpl extends AbsChatService {
    @Override
    public AISourceEnum source() {
        return AISourceEnum.XUN_FEI_AI;
    }
}

get和post啥区别

三分恶面渣逆袭:Get 和 Post 区别

GET 请求主要用于获取数据,参数附加在 URL 中,存在长度限制,且容易被浏览器缓存,有安全风险;而 POST 请求用于提交数据,参数放在请求体中,适合提交大量或敏感的数据。

另外,GET 请求是幂等的,多次请求不会改变服务器状态;而 POST 请求不是幂等的,可能对服务器数据有影响。

什么是事务 事务为什么要有隔离级别 幻读是什么 什么时候要解决幻读 什么时候不用解决

事务是一条或多条 SQL 语句组成的执行单元,要么全部执行成功,要么全部失败,不会出现部分执行的情况。

事务具有四个基本特性,也就是通常所说的 ACID 特性,即原子性、一致性、隔离性和持久性。主要作用是保证数据库操作的一致性。

三分恶面渣逆袭:事务四大特性

幻读指的是在同一事务中执行相同的查询时,返回的结果集中出现了之前没有的数据行。这是因为在事务执行过程中,另外一个事务插入了新的数据。

比如说事务 A 在第一次查询某个条件范围的数据行后,事务 B 插入了一条新数据且符合条件范围,事务 A 再次查询时,发现多了一条数据。

-- 事务 A
START TRANSACTION;
SELECT * FROM employees WHERE department = 'HR';  -- 读取到 10 条记录

-- 事务 B
START TRANSACTION;
INSERT INTO employees (idname, department) VALUES (11'John Doe''HR');
COMMIT;

-- 事务 A 再次查询
SELECT * FROM employees WHERE department = 'HR';  -- 读取到 11 条记录 (幻读)
COMMIT;

需要解决幻读的场景一般是对数据一致性要求较高的业务,例如银行转账、库存管理等,而在一些只要求最终一致性的应用场景中(如统计功能),可以忽略幻读问题。

springmvc执行流程

首先,客户端发送请求,DispatcherServlet 拦截并通过 HandlerMapping 找到对应的控制器。

DispatcherServlet 使用 HandlerAdapter 调用控制器方法,执行具体的业务逻辑,返回一个 ModelAndView 对象。

然后 DispatcherServlet 通过 ViewResolver 解析视图。

最后,DispatcherServlet 渲染视图并将响应返回给客户端。

三分恶面渣逆袭:Spring MVC的工作流程

session共享的解决方案 对比

在分布式系统中,为了保持用户会话状态,常用的 Session 共享方案包括 Session 复制、Session 绑定、Session 存储到数据库、Session 存储到缓存以及基于 JWT 的无状态 Token。

  • Session 复制将 Session 数据同步到每个节点,适合小型集群,但扩展性较差。
  • Session 绑定将用户请求固定在同一节点,性能较高,但容错性差,适合轻量级应用。
  • Session 存储到数据库可以保证数据一致性,但数据库频繁读写可能成为性能瓶颈。
  • Session 存储到 Redis 可以提供高性能和扩展性,适合高并发场景。
  • 而 JWT 是无状态的 Token,不需要服务端存储会话数据,适合前后端分离的系统。

双写一致性怎么解决的

在技术派实战项目中,我采用的是先写 MySQL,再删除 Redis 的方式来保证缓存和数据库的数据一致性。

技术派教程

我举例说明一下。

对于第一次查询,请求 B 查询到的缓存数据是 10,但 MySQL 被请求 A 更新为了 11,此时数据库和缓存不一致。

但也只存在这一次不一致的情况,对于不是强一致性的业务,可以容忍。

当请求 B 第二次查询时,因为请求 A 更新完数据库把缓存删除了,所以请求 B 这次不会命中缓存,会重新查一次 MySQL,然后回写到 Redis。

缓存和数据库又一致了。

分布式事务怎么实现 为什么要用延迟队列

分布式事务的实现方式主要包括:

  • 二阶段提交(2PC):通过准备和提交阶段保证一致性,但性能较差。
  • 三阶段提交(3PC):在 2PC 的基础上增加了一个超时机制,降低了阻塞,但依旧存在数据不一致的风险。
  • TCC:根据业务逻辑拆分为 Try、Confirm 和 Cancel 三个阶段,适合锁定资源的业务场景。
  • 本地消息表:在数据库中存储事务事件,通过定时任务处理消息。
  • 基于 MQ 的分布式事务:通过消息队列来实现异步确保,利用重试机制保障最终一致性,适用于对实时性要求不高的场景。
三分恶面渣逆袭:基于 MQ 的分布式事务

延迟队列在分布式事务中主要用于异步补偿和定时校验,确保数据最终一致。比如,当事务的某个子操作失败时,可以使用延迟队列在一段时间后触发重试操作,或者检查数据是否一致。

ending

一个人可以走得很快,但一群人才能走得更远。二哥的编程星球已经有 6500 多名球友加入了,如果你也需要一个良好的学习环境,戳链接 🔗 加入我们吧。这是一个 编程学习指南 + Java 项目实战 + LeetCode 刷题 + 简历精修 的私密圈子,你可以阅读星球专栏、向二哥提问、帮你制定学习计划、和球友一起打卡成长。

两个置顶帖「球友必看」和「知识图谱」里已经沉淀了非常多优质的学习资源,相信能帮助你走的更快、更稳、更远

欢迎点击左下角阅读原文了解二哥的编程星球,这可能是你学习求职路上最有含金量的一次点击。

最后,把二哥的座右铭送给大家:没有什么使我停留——除了目的,纵然岸旁有玫瑰、有绿荫、有宁静的港湾,我是不系之舟。共勉 💪。

沉默王二
技术文通俗易懂,吹水文风趣幽默。学 Java,认准二哥的网站 javabetter.cn
 最新文章