数据研发面经——字节跳动
-
-
- 1.抽象类与接口
- 2.多态
- 3.四种引用
- 4.锁,并发怎么处理
- 5.进程和线程的区别
- 6.shuffle机制 mapreduce流程
- 7.JVM虚拟机,为什么需要虚拟机
- 8.内存区域,五部分。栈和堆区别,具体存放的东西?String在哪里?字符串池或者内存中新开辟(应该是这样)。线程在哪里?(是不是堆中?)
- 9.ArrayList和LinkedList区别?底层实现?两者扩容机制
- 10.集合相关
- 11.数仓分层
- 12.Hive的优化策略,分区,分桶
- 13hashmap的底层实现原理
- 14.Mysql索引
- 15.关系型数据库和非关系型数据库的区别
- 16.HDFS分布式文件系统如何进行存储的
- 17.hive是什么
- 18.hive中外表和内表的区别
- 19.hive元数据中有什么
- 20.MySQL有什么引擎,有什么区别?
- 21.MySQL中char和varchar有什么区别?
- 22.详细说下数据库事务的特点
- 23.hadoop中的shuffle机制
- 24.聚簇索引
- 24非聚簇索引
- 25.B-树索引和B+树索引
- 26.Hash索引和B+Tree索引的区别
- 27.手撕代码:求字符串的最长回文子序列
- 28.Hive避免数据倾斜有哪些优化手段
- 29.Hive中分桶技术
- 30.操作系统中进程和线程的定义和区别
- 31.数据库锁机制
- 32.锁相关 sync,lock类
- 33.线程和多线程的问题
-
1.抽象类与接口
接口的出现:
- 有时候,必须从多个类中派生出一个类,但是java中的类是单继承的
- 从几个类中抽取出一些共同的行为特征,但是他们之间没有is-a的关系,仅仅是具有相同的行为特征而已
相同点
- 都不能被实例化
- 接口的实现类和抽象类的子类只有全部实现了接口或者抽象类中的方法后才可以被实例化
不同点
- 抽象类中可以有普通成员变量,接口中没有
- 抽象类中有非抽象的普通方法,接口中只有抽象方法
- 抽象类中的抽象方法的访问类型可以是public,protected,接口中的抽象方法只能是public的
- 抽象类和接口中都可以包括静态成员变量,抽象类中的静态成员变量的访问类型可以任意,但接口中定义的变量只能是public static final类型的,接口中都是常量
- 一个类可以实现多个接口,但是只能集成一个抽象类
2.多态
- 子类集成父类,并对父类的方法重写
3.四种引用
- 强引用:java默认的引用,垃圾回收器永远不会回收被引用的对象,内存不足会抛出异常
- 软引用:内存足够,不会被回收,内存不足,系统会回收软引用对象,如果回收了软引用之后仍然没有足够的内存,才会抛出内存溢出异常,常被用来实现缓存技术
SoftReference<byte[]> sr = new SoftReference<>(buff);
java.lang.ref.SoftReference类来表示软引用 - 弱引用:无论内存是否足够,只要JVM开始进行垃圾回收,弱引用关联的对象都会被回收
WeakReference<byte[]> sr = new WeakReference<>(buff)
用 java.lang.ref.WeakReference 来表示弱引用 - 虚引用:随时可能被回收,和没有任何引用一样,查看源码发现它只有一个构造函数和一个 get() 方法,而且它的 get() 方法仅仅是返回一个null,也就是说将永远无法通过虚引用来获取对象必须和引用队列ReferenceQueue 一起使用
用 PhantomReference 类来表示
4.锁,并发怎么处理
加锁防止并发
-
共享锁,读锁,可以查看但无法修改和删除数据,当数据库被别人增加了读锁的时候,其他新来的事务可以读数据,但是不能写,也就是,如果事务T对数据A加上共享锁后,则其他事务只能对A再加共享锁,不能加排他锁,获得共享锁的事务只能读数据,不能修改数据
-
排他锁,写锁,既能读数据,也能修改数据。如果数据库已经被别人加了排他锁,那么后面的事务无法在数据库上加任何锁
-
悲观锁,借助数据库锁机制,在修改数据之前先锁定,一个事务如果锁定了某行数据,其他事务必须等待该事务处理完才可以处理那行数据。
- 在对记录修改前,先尝试为该记录加上排他锁
- 如果加锁失败,说明该记录正在被修改
- 如果枷锁成功,就可以对该记录做修改
- 其间如果有其他事务要对该记录做加锁的操作,都要等待或者抛异常
-
乐观锁,不会使用数据库提供的锁机制,记录数据版本
5.进程和线程的区别
- 程序:一段静态的代码
- 进程:在系统中正在运行的一个应用程序,程序一旦运行就是进程,进程是资源分配的最小单位,支持多线程,同一时间并行执行多个线程
- 线程:系统分配处理器时间资源的基本单位,进程之内独立执行的一个单元执行流,线程是程序执行的最小单位,一个程序内部的一条执行路径,
- 一个程序至少一个进程,一个进程中至少有一个线程
- 进程要分配一大部分的内存,线程只需要分配一部分栈就可以了
6.shuffle机制 mapreduce流程
- shuffle是map之后,reduce之前的操作,在map task端和reduce task端都有,首先map处理之后的结果进入到shuffle阶段,在进入到环形缓冲区之前,先进行分区,环形缓冲区相当于内存,map之后的数据写到缓冲区,当到80%的时候开始反向溢写,可以看做又开了一个线程,之前的继续写到缓冲区,新的将缓冲区的溢写到磁盘,在溢写之前,进行一次快排,保证区内有序,当所有的文件都溢写到磁盘之后,再进行一次归并排序,保证区内有序,最后都保存到了磁盘上,这时reduce来拉取对应分区的数据,并进行一次归并排序,按照相同的key分组,相同的key进入到同一个reduce中。
- mapreduce,首先提交job,向yarn提交三份东西,split,jar,xml,开启mrAppmaster,根据切片数开启map task的个数。
7.JVM虚拟机,为什么需要虚拟机
- java虚拟机(java virtual machine JVM) 来负责java程序在该系统中的运行
- 通过java语言编写的应用程序在不同的系统平台上都可以运行
8.内存区域,五部分。栈和堆区别,具体存放的东西?String在哪里?字符串池或者内存中新开辟(应该是这样)。线程在哪里?(是不是堆中?)
- 程序计数器
- 虚拟机栈:局部变量
- 本地方法栈
- 堆:new的对象和成员变量
- 方法区:类信息、静态变量和常量,常量池属于方法区(存放字面量和符号引用)
- String有两种定义方法,字面量定义存储在方法区的字符串常量池中,new的方法定义存储在堆中。
- 线程:共享一套堆和方法区,每个线程的栈是互相独立的。
- 进程:一个进程有一个堆,这个堆为本进程中所有线程共享。
总结
- 栈:为即时调用的方法开辟空间,存储局部变量、变量引用
- 堆:存放引用类型的对象,new出来的,数组值,类的非静态成员变量值(基本数据类型)
- 方法区:存放class二进制文件,包括类信息、静态变量、常量池(string字符串和final修饰的常量值),类的版本号
- 堆用来存放对象,栈用来执行程序。栈的存取速度快,但是大小和生成周期必须确定。
- 成员变量:静态的存在方法区,非静态的存在堆中。
9.ArrayList和LinkedList区别?底层实现?两者扩容机制
相同点
- 三个类都实现了list接口,存储数据的特点相同,存储有序的、可重复的数据
不同点
- Arraylist:底层使用Object[]数组存