去哪儿打响了互联网反卷的第一枪
共 10896字,需浏览 22分钟
·
2024-07-11 14:04
大家好,我是二哥呀。
7 月 9 日的时候,去哪儿 CEO 发布了全员信,说:兄弟们,从 7 月 15 号开始,每周三和周五,咱们去哪儿的兄弟姐妹们可以灵活选择办公地点,公司或者在家都可以。
并且不需要审批哦。这种混合办公的形式,我觉得挺好的,尤其是通勤时间比较久的小伙伴,真的能节省不少时间。就是可能要费点家里的电了,哈哈。
图片里的字比较小,我给大家再抽取一点关键信息:
-
有的同学利用通勤的时间撸铁,瘦了 8 斤; -
有的同学为了线上开会,自学了沟通技巧; -
有的同学跨域通勤,早一天回家陪家人; -
有的同学在家里上班的样子成了孩子的榜样,成绩都上去了。
这。。。真好啊,如果这些都确定真的话,那驼厂的小伙伴可太幸福了啊。去哪儿也算是打响了互联网反卷的第一枪,棒👍
希望所有的互联网公司都能争相模仿起来,不仅混合办公,最好减少加班的时间,别 996 了,965 吧。哪怕是做做样子。
向往自由办公的小伙伴估计看到这就忍不住了,想冲去哪儿了!尤其是 25 届秋招的小伙伴。
那今天我们就以《Java 面试指南》中收录的《去哪儿面经同学 1》 技术二面为例,来看看去哪儿面试官都喜欢问哪些问题,好做到知彼知己百战不殆。
1、二哥的 Linux 速查备忘手册.pdf 下载 2、三分恶面渣逆袭在线版:https://javabetter.cn/sidebar/sanfene/nixi.html
去哪儿同学一二面面经
项目的难点,为什么做这个项目
我在做 PmHub 这个项目时,印象最深刻的三个点分别是:
-
1、将流程引擎丝滑地结合到项目管理业务中,需要系统的设计,我用到了 DDD 抽象模型,抽象工厂模式设计监听器等。 -
2、当海量请求触发流程流转时,如何解决缓存穿透、缓存和数据库一致性问题? -
3、以及如何利用分布式事务保证任务审批状态一致性等。
从个人角度来说,我觉得现有的项目管理系统无论是禅道还是 TAPD,更多关注的是需求迭代和缺陷本身,对项目的资源管控以及流程引擎关注度不够,PmHub 的诞生就是希望打造一套智能的项目管理系统,核心是可以对项目资源录入、任务智能流转分配,未来还打算增加企业物料管理、供应商管理、采购管理、仓库管理等,我们的目标是开源一套完整的 CRM 系统,结合现在的 LLM,实现智能化的项目管理。
java集合用过哪些——collection继承哪些接口
最经常用的就是封装了动态数组的 ArrayList 和封装了链表的 LinkedList;以及键值对 HashMap。
Collection 继承了 Iterable 接口,这意味着所有实现 Collection 接口的类都必须实现 iterator()
方法,之后就可以使用增强型 for 循环遍历集合中的元素了。
接口可以多继承吗
接口可以多继承,一个接口可以继承多个接口,使用逗号分隔。
interface InterfaceA {
void methodA();
}
interface InterfaceB {
void methodB();
}
interface InterfaceC extends InterfaceA, InterfaceB {
void methodC();
}
class MyClass implements InterfaceC {
public void methodA() {
System.out.println("Method A");
}
public void methodB() {
System.out.println("Method B");
}
public void methodC() {
System.out.println("Method C");
}
public static void main(String[] args) {
MyClass myClass = new MyClass();
myClass.methodA();
myClass.methodB();
myClass.methodC();
}
}
在上面的例子中,InterfaceA 和 InterfaceB 是两个独立的接口。
InterfaceC 继承了 InterfaceA 和 InterfaceB,并且定义了自己的方法 methodC。
MyClass 实现了 InterfaceC,因此需要实现 InterfaceA 和 InterfaceB 中的方法 methodA 和 methodB,以及 InterfaceC 中的方法 methodC。
异常和错误的区别,受检异常和非受检异常,常用的有哪些,公共的父类是哪个
Throwable
是 Java 语言中所有错误和异常的基类。它有两个主要的子类:Error 和 Exception,这两个类分别代表了 Java 异常处理体系中的两个分支。
Error 类代表那些严重的错误,这类错误通常是程序无法处理的。比如,OutOfMemoryError 表示内存不足,StackOverflowError 表示栈溢出。这些错误通常与 JVM 的运行状态有关,一旦发生,应用程序通常无法恢复。
Exception 类代表程序可以处理的异常。它分为两大类:编译时异常(Checked Exception)和运行时异常(Runtime Exception)。
①、编译时异常(Checked Exception):这类异常在编译时必须被显式处理(捕获或声明抛出)。
如果方法可能抛出某种编译时异常,但没有捕获它(try-catch)或没有在方法声明中用 throws 子句声明它,那么编译将不会通过。例如:IOException、SQLException 等。
②、运行时异常(Runtime Exception):这类异常在运行时抛出,它们都是 RuntimeException 的子类。对于运行时异常,Java 编译器不要求必须处理它们(即不需要捕获也不需要声明抛出)。
运行时异常通常是由程序逻辑错误导致的,如 NullPointerException、IndexOutOfBoundsException 等。
Object底层的数据结构(蒙了)
在 HotSpot 中,对象在堆内存中的存储布局可以划分为三个部分:对象头(Object Header)、实例数据(Instance Data)和对齐填充(Padding)。
①、对象头是每个对象都有的,包含三部分主要信息:
-
标记字(Mark Word):包含了对象自身的运行时数据,如哈希码(HashCode)、垃圾回收分代年龄、锁状态标志、线程持有的锁、偏向线程 ID 等信息。在 64 位操作系统下占 8 个字节,32 位操作系统下占 4 个字节。 -
类型指针(Class Pointer):指向对象所属类的元数据的指针,JVM 通过这个指针来确定对象的类。在开启了压缩指针的情况下,这个指针可以被压缩。在开启指针压缩的情况下占 4 个字节,否则占 8 个字节。 -
数组长度(Array Length):如果对象是数组类型,还会有一个额外的数组长度字段。占 4 个字节。
②、实例数据存储了对象的具体信息,即在类中定义的各种字段数据(不包括由父类继承的字段)。这部分的大小取决于对象的属性和它们的类型(如 int、long、引用类型等)。JVM 会对这些数据进行对齐,以确保高效的访问速度。
③、对齐填充,为了使对象的总大小是 8 字节的倍数(这在大多数现代计算机体系结构中是最优访问边界),JVM 可能会在对象末尾添加一些填充。这部分是为了满足内存对齐的需求,并不包含任何具体的数据。
用过哪些设计模式,设计模式有哪些好处
比如说单例模式,在需要控制资源访问,如配置管理、连接池管理时经常使用单例模式。它确保了全局只有一个实例,并提供了一个全局访问点。
在有多种算法或策略可以切换使用的情况下,我会使用策略模式。像技术派实战项目中,我就使用策略模式对接了讯飞星火、OpenAI 等多家 API 服务,实现了一个可以自由切换 AI 服务的对话聊天服务。
这样就不用在代码中写 if/else 判断,而是将不同的 AI 服务封装成不同的策略类,通过工厂模式创建不同的 AI 服务实例,从而实现 AI 服务的动态切换。
后面想添加新的 AI 服务,只需要增加一个新的策略类,不需要修改原有代码,这样就提高了代码的可扩展性。
设计模式是软件工程中常用的解决特定问题的模版或者蓝图,可以帮助我们开发者以一种更加清晰、高效和可重用的方式来编写代码。
锁升级,synchronized底层,会不会牵扯到os层面
锁升级是 Java 虚拟机中的一个优化机制,用于提高多线程环境下 synchronized 的并发性能。锁升级涉及从较轻的锁状态(如无锁或偏向锁)逐步升级到较重的锁状态(如轻量级锁和重量级锁),以适应不同程度的竞争情况。
Java 对象头里的 Mark Word
会记录锁的状态,一共有四种状态:
①、无锁状态,在这个状态下,没有线程试图获取锁。
②、偏向锁,当第一个线程访问同步块时,锁会进入偏向模式。Mark Word 会被设置为偏向模式,并且存储了获取它的线程 ID。
偏向锁的目的是消除同一线程的后续锁获取和释放的开销。如果同一线程再次请求锁,就无需再次同步。
③、当有多个线程竞争锁,但没有锁竞争的强烈迹象(即线程交替执行同步块)时,偏向锁会升级为轻量级锁。
线程尝试通过CAS 操作(Compare-And-Swap)将对象头的 Mark Word 替换为指向锁记录的指针。如果成功,当前线程获取轻量级锁;如果失败,说明有竞争。
④、重量级锁,当锁竞争激烈时,轻量级锁会膨胀为重量级锁。
重量级锁通过将对象头的 Mark Word 指向监视器(Monitor)对象来实现,该对象包含了锁的持有者、锁的等待队列等信息。
synchronized 是 JVM 帮我们实现的,因此在使用的时候不用手动去 lock 和 unlock,JVM 会帮我们自动加锁和解锁。
①、synchronized 修饰代码块时,JVM 会通过 monitorenter
、monitorexit
两个指令来实现同步:
-
monitorenter
指向同步代码块的开始位置 -
monitorexit
指向同步代码块的结束位置。
使用 javap -c -s -v -l SynchronizedDemo.class
反编译一段 synchronized 代码块时,可以看到 monitorenter 和 monitorexit 指令。
②、synchronized 修饰方法时,JVM 会通过 ACC_SYNCHRONIZED
标记符来实现同步。
会,synchronized 升级为重量级锁时,依赖于操作系统的互斥量(mutex)来实现,mutex 用于保证任何给定时间内,只有一个线程可以执行某一段特定的代码段。
spring的容器、web容器、springmvc的容器之间的区别
Spring 容器是 Spring 框架的核心部分,负责管理应用程序中的对象生命周期和依赖注入。
Web 容器(也称 Servlet 容器),是用于运行 Java Web 应用程序的服务器环境,支持 Servlet、JSP 等 Web 组件。常见的 Web 容器包括 Apache Tomcat、Jetty等。
Spring MVC 是 Spring 框架的一部分,专门用于处理 Web 请求,基于 MVC(Model-View-Controller)设计模式。
springboot的好处(一面的问题又问了一遍)
Spring Boot 是一个开源的、用于简化 Spring 应用初始化和开发过程的框架。提供了一套默认配置,约定优于配置,来帮助我们快速搭建 Spring 项目骨架,极大地提高了我们的生产效率,再也不用为 Spring 的繁琐配置而烦恼了。
以前的 Spring 开发需要配置大量的 xml 文件,并且需要引入大量的第三方 jar 包,还需要手动放到 classpath 下。
Spring Boot 的优点非常多,比如说:
-
通过 Intellij IDEA 或者官方的 Spring Initializr 就可以快速创建新项目,只需要选择需要的依赖就可以五分钟内搭建一个项目骨架。 -
Spring Boot 内嵌了 Tomcat、Jetty、Undertow 等容器,不需要在服务器上部署 WAR 包了,直接运行 jar 包就可以启动项目,超级方便。 -
Spring Boot 无需再像以前一样在 web.xml、applicationContext.xml 等配置文件里配置大量的内容,大部分初始工作 Spring Boot 都帮我们做好了。例如,如果项目中添加了 spring-boot-starter-web,Spring Boot 会自动配置 Tomcat 和 Spring MVC。 -
Spring Boot 允许我们通过 yaml 来管理应用的配置,比传统的 properties 文件更加简洁。 -
Spring Boot 提供了一系列的 Starter,可以快速集成常用的框架,例如 Spring Data JPA、Spring Security、MyBatis 等。 -
Spring Boot 提供了一系列的 Actuator,可以帮助我们监控和管理应用,比如健康检查、审计、统计等。 -
配合 Spring Cloud 可以快速构建微服务架构。
mysql为什么用索引
数据库文件是存储在磁盘上的,磁盘 I/O 是数据库操作中最耗时的部分之一。没有索引时,数据库会进行全表扫描(Sequential Scan),这意味着它必须读取表中的每一行数据来查找匹配的行(时间效率为 O(n))。当表的数据量非常大时,就会导致大量的磁盘 I/O 操作。
有了索引,就可以直接跳到索引指示的数据位置,而不必扫描整张表,从而大大减少了磁盘 I/O 操作的次数。
MySQL 的 InnoDB 存储引擎默认使用 B+ 树来作为索引的数据结构,而 B+ 树的查询效率非常高,时间复杂度为 O(logN)。
索引文件相较于数据库文件,体积小得多,查到索引之后再映射到数据库记录,查询效率就会高很多。
索引就好像书的目录,通过目录去查找对应的章节内容会比一页一页的翻书快很多。
事务的理解 事务的隔离属性
事务是一个或多个 SQL 语句组成的一个执行单元,这些 SQL 语句要么全部执行成功,要么全部不执行,不会出现部分执行的情况。事务是数据库管理系统执行过程中的一个逻辑单位,由一个有限的数据库操作序列构成。
事务的主要作用是保证数据库操作的一致性,即事务内的操作,要么全部成功,要么全部失败回滚,不会出现中间状态。这对于维护数据库的完整性和一致性非常重要。
事务具有四个基本特性,也就是通常所说的 ACID 特性,即原子性(Atomicity)、一致性(Consistency)、隔离性(Isolation)和持久性(Durability)。
什么是原子性?
原子性子性意味着事务中的所有操作要么全部完成,要么全部不完成,它是不可分割的单位。如果事务中的任何一个操作失败了,整个事务都会回滚到事务开始之前的状态,如同这些操作从未被执行过一样。
什么是一致性?
一致性确保事务从一个一致的状态转换到另一个一致的状态。
比如在银行转账事务中,无论发生什么,转账前后两个账户的总金额应保持不变。假如 A 账户(100 块)给 B 账户(10 块)转了 10 块钱,不管成功与否,A 和 B 的总金额都是 110 块。
什么是隔离性?
隔离性意味着并发执行的事务是彼此隔离的,一个事务的执行不会被其他事务干扰。就是事务之间是井水不犯河水的。
隔离性主要是为了解决事务并发执行时可能出现的问题,如脏读、不可重复读、幻读等。
数据库系统通过事务隔离级别(如读未提交、读已提交、可重复读、串行化)来实现事务的隔离性。
什么是持久性?
持久性确保事务一旦提交,它对数据库所做的更改就是永久性的,即使发生系统崩溃,数据库也能恢复到最近一次提交的状态。通常,持久性是通过数据库的恢复和日志机制来实现的,确保提交的事务更改不会丢失。
redis内存淘汰和过期策略
当 Redis 内存使用达到设置的最大值时(通过 maxmemory 参数设置),它会根据配置的内存淘汰策略来决定如何处理新的写请求。
我先说三种淘汰策略:
-
noeviction:默认策略,不进行任何数据淘汰,直接返回错误信息。适用于不能丢失数据的场景。 -
volatile-lru:从设置了过期时间的键中,使用 LRU 算法淘汰最不常用的键。 -
allkeys-lru:从所有键中,使用 LRU(最近最少使用)算法淘汰最不常用的键。适用于缓存场景,优先保留最近使用的数据。
Redis 支持为键设置过期时间,当键的过期时间到达后,Redis 会自动删除这些键。过期回收策略主要有两种:惰性删除和定期删除。
什么是惰性删除?
当某个键被访问时,如果发现它已经过期,Redis 会立即删除该键。这意味着如果一个已过期的键从未被访问,它不会被自动删除,可能会占用额外的内存。
什么是定期删除?
Redis 会定期随机测试一些键,并删除其中已过期的键。这个过程是 Redis 内部自动执行的,旨在减少过期键对内存的占用。
redis和本地缓存的区别,哪个效率高
Redis 可以部署在多个节点上,支持数据分片,适用于跨服务器的缓存共享。而本地缓存只能在单个服务器上使用。
Redis 还可以持久化数据,支持数据备份和恢复,适用于对数据安全性要求较高的场景。并且支持发布/订阅、事务、Lua 脚本等高级功能。
效率上,Redis 和本地缓存都是存储在内存中,读写速度都非常快。
JMM模型
Java 内存模型(Java Memory Model)是一种抽象的模型,简称 JMM,主要用来定义多线程中变量的访问规则,用来解决变量的可见性、有序性和原子性问题,确保在并发环境中安全地访问共享变量。
JMM 定义了线程内存和主内存之间的抽象关系:线程之间的共享变量存储在主内存
(Main Memory)中,每个线程都有一个私有的本地内存
(Local Memory),本地内存中存储了共享变量的副本,用来进行线程内部的读写操作。
-
当一个线程更改了本地内存中共享变量的副本后,它需要将这些更改刷新到主内存中,以确保其他线程可以看到这些更改。 -
当一个线程需要读取共享变量时,它可能首先从本地内存中读取。如果本地内存中的副本是过时的,线程将从主内存中重新加载共享变量的最新值到本地内存中。
内容来源
-
星球嘉宾三分恶的面渣逆袭:https://javabetter.cn/sidebar/sanfene/nixi.html -
二哥的 Java 进阶之路(GitHub 已有 12000+star):https://javabetter.cn
ending
一个人可以走得很快,但一群人才能走得更远。二哥的编程星球已经有 5700 多名球友加入了,如果你也需要一个良好的学习环境,戳链接 🔗 加入我们吧。这是一个编程学习指南 + Java 项目实战 + LeetCode 刷题的私密圈子,你可以阅读星球专栏、向二哥提问、帮你制定学习计划、和球友一起打卡成长。
两个置顶帖「球友必看」和「知识图谱」里已经沉淀了非常多优质的学习资源,相信能帮助你走的更快、更稳、更远。
欢迎点击左下角阅读原文了解二哥的编程星球,这可能是你学习求职路上最有含金量的一次点击。
最后,把二哥的座右铭送给大家:没有什么使我停留——除了目的,纵然岸旁有玫瑰、有绿荫、有宁静的港湾,我是不系之舟。共勉 💪。