区块链或后端方面面经

1.      线程栈:先是会自动扩展,到达最大值才会溢出,溢出之后程序会收到一个段错误(java表现为异常),调高堆栈容量可能会增加内存开销和启动时间

2.      堆和栈的区别:(总结,栈的一切由系统管理,所以堆有各种碎片问题)

•        管理方式:栈由编译器自动管理;堆由程序员控制,使用方便,但易产生内存泄露。

•        生长方向:栈向低地址扩展(即”向下生长”),是连续的内存区域;堆向高地址扩展(即”向上生长”),是不连续的内存区域。这是由于系统用链表来存储空闲内存地址,自然不连续,而链表从低地址向高地址遍历。

•        空间大小:栈顶地址和栈的最大容量由系统预先规定(通常默认2M或10M);堆的大小则受限于计算机系统中有效的虚拟内存,32位Linux系统中堆内存可达2.9G空间。

•        存储内容:栈用于函数调用等,堆的内容由程序员决定。

•        分配方式:栈可静态分配或动态分配。静态分配由编译器完成,如局部变量的分配。动态分配由alloca函数在栈上申请空间,用完后自动释放。堆只能动态分配且手工释放。

•        分配效率:栈由计算机底层提供支持:分配专门的寄存器存放栈地址,压栈出栈由专门的指令执行,因此效率较高。堆由函数库提供,机制复杂,效率比栈低得多。Windows系统中VirtualAlloc可直接在进程地址空间中分配一块内存,快速且灵活。

•        分配后系统响应:只要栈剩余空间大于所申请空间,系统将为程序提供内存,否则报告异常提示栈溢出。

•        碎片问题:栈不会存在碎片问题,因为栈是先进后出的队列,内存块弹出栈之前,在其上面的后进的栈内容已弹出。而频繁申请释放操作会造成堆内存空间的不连续,从而造成大量碎片,使程序效率降低。

2. linux中有几种栈:进程栈、线程栈、内核栈( 在执行系统调用陷入内核之后,这些内核代码所使用的栈并不是原先进程用户空间中的栈,而是一个单独内核空间的栈,这个称作进程内核栈)、中断栈

3.      类加载过程:加载、连接(验证、准备、解析)、初始化、使用、卸载

4.      什么时候需要类加载:new、反射、发现父类未初始化、主类、动态语言支持(注意,被动引用不触发初始化,如数组引用,通过子类引用父类)

5. synchronized和lock的区别

• synchronized:可以只对需要同步的使用与wait()/notify()/nitifyAll()一起使用时,比较方便

• lock:可控性更好,在并发量比较小的情况下,使用synchronized是个不错的选择,但是在并发量比较高的情况下,其性能下降很严重,此时ReentrantLock是个不错的方案。

6. synchronized锁:

• Synchronized修饰非静态方法,实际上是对调用该方法的对象加锁,俗称“对象锁”。

• Synchronized修饰静态方法,实际上是对该类对象加锁,俗称“类锁”

11. java实现计数器:原子操作类、加锁

13. sql语句:

• select * from TableA left join TableB on TableA.id=TableB.id 左外连接

• select * from TableA right join TableB on TableA.id=TableB.id 右外连接

• select * from TableA full join TableB on TableA.id=TableB.id 全外连接

全连接:完整外部联接返回左表和右表中的所有行。当某行在另一个表中没有匹配行时,则另一个表的选择列表列包含空值。如果表之间有匹配行,则整个结果集行包含基表的数据值。

• select * from TableA JOIN TableB on TableA.id=TableB.id 内连接

自然连接:在连接条件中使用等于(=)运算符比较被连接列的列值,但它使用选择列表指出查询结果集合中所包括的列,并删除连接表中的重复列。

• select * from TableA cross join TableB 交叉连接

交叉连接:交叉联接返回左表中的所有行,左表中的每一行与右表中的所有行组合。交叉联接也称作笛卡尔积。

14.    目录树数据库表设计:用一个一级分类表,一个二级表,用父节点id表示。本质上是一个一对多的关系,可以借鉴下面这个表:

l ID 编号 int

l aDept_DeptID 部门代码 char

l aDept_DeptName 部门名称 char

15.    长连接怎么实现:

16.    什么时候选择innodb、myisam:前者支持更多功能,如行级锁,后者效率更高,节省存储

17. hashmap和hashtable的区别:能不能接受null,线程安全,快速失败迭代,扩容方式

18.    数据库索引什么时候会失效:

1、索引列有函数处理或隐式转换,不走索引
2、索引列倾斜,个别值查询时,走索引代价比走全表扫描高,所以不走索引
3、索引列没有限制 not null,索引不存储空值,如果不限制索引列是not null,oracle会认为索引列有可能存在空值,所以不会按照索引计算)

19. java如何实现不可变类:

•        所有成员都是 private final 的

•        不提供对成员的改变方法,例如:setXXXX

•        确保所有的方法不会被重载。手段有两种:使用final Class(强不可变类),或者将所有类方法加上final(弱不可变类)。

•        如果某一个类成员不是基本类型(primitive type)或不可变类,必须通过在成员初始化(in)或者getter方法(out)时通过深度拷贝(即复制一个该类的新实例而非引用)方法,来确保类的不可变。

•        如果有必要,重写hashCode和equals方法,同时应保证两个用equals方法判断为相等的对象,其hashCode也应相等。

20. reactor和proactor有什么区别:

21.    如何设计无锁数据结构:CAS、自旋锁

22. jdk1.8中对hashMap的优化:

23.    不可变类的优点:

•        只有当字符串是不可变的,字符串池才有可能实现。字符串池的实现可以在运行时节约很多heap空间,因为不同的字符串变量都指向池中的同一个字符串。但如果字符串是可变的,那么String interning将不能实现(译者注:String interning是指对不同的字符串仅仅只保存一个,即不会保存多个相同的字符串。),因为这样的话,如果变量改变了它的值,那么其它指向这个值的变量的值也会一起改变。

•        如果字符串是可变的,那么会引起很严重的安全问题。譬如,数据库的用户名、密码都是以字符串的形式传入来获得数据库的连接,或者在socket编程中,主机名和端口都是以字符串的形式传入。因为字符串是不可变的,所以它的值是不可改变的,否则黑客们可以钻到空子,改变字符串指向的对象的值,造成安全漏洞。

•        因为字符串是不可变的,所以是多线程安全的,同一个字符串实例可以被多个线程共享。这样便不用因为线程安全问题而使用同步。字符串自己便是线程安全的。

•        类加载器要用到字符串,不可变性提供了安全性,以便正确的类被加载。譬如你想加载java.sql.Connection类,而这个值被改成了myhacked.Connection,那么会对你的数据库造成不可知的破坏。

•        因为字符串是不可变的,所以在它创建的时候hashcode就被缓存了,不需要重新计算。这就使得字符串很适合作为Map中的键,字符串的处理速度要快过其它的键对象。这就是HashMap中的键往往都使用字符串。

24.    怎么实现一个不可变类:

•        将类声明为final,所以它不能被继承

•        将所有的成员声明为私有的,这样就不允许直接访问这些成员

•        对变量不要提供setter方法

•        将所有可变的成员声明为final,这样只能对它们赋值一次

•        通过构造器初始化所有成员,进行深拷贝(deep copy)

•        在getter方法中,不要直接返回对象本身,而是克隆对象,并返回对象的拷贝

25.    内存泄露的可能原因:

•        静态集合类引起内存泄漏:

•        当集合里面的对象属性被修改后,再调用remove()方法时不起作用。(key被修改,hashcode发生了改变)

•        监听器

•        数据库连接等

•        内部类和外部模块的引用

•        单例模式

26.    数据库索引有哪些

•        唯一索引/非唯一索引

•        主键索引(主索引)(有约束,但是索引没有)

•        聚集索引/非聚集索引

•        组合索引

27.    序列化原理

l  (1)将对象实例相关的类元数据输出。

l  (2)递归地输出类的超类描述直到不再有超类。

l  (3)类元数据完了以后,开始从最顶层的超类开始输出对象实例的实际数据值。

l  (4)从上至下递归输出实例的数据

28.    如何实现equal

l  将显示参数命名为otherObject,稍后转化为目标类型并命名为other;

l  检查this和otherObject是否相同;

l  检查otherObject是否为空,为空则返回false;

l  检查this和otherObject类型是否相同;

l  将otherObject转化为目标类型,并命名为other;

l  对类型中定义的属性进行比较,如果是基础数据类型使用==,如果是引用类型使用equals()。

29. java的基本数据类型:8位:Byte(字节型) 16位:short(短整型)、char(字符型) 32位:int(整型)、float(单精度型/浮点型) 64位:long(长整型)、double(双精度型) 最后一个:boolean(布尔类型)

1.7中,永久代仍存在于JDK1.7中,并没完全移除,譬如符号引用(Symbols)转移到了native heap;字面量(interned strings)转移到了java heap;类的静态变量(class statics)转移到了java heap。

31. java泛型的理解,以及和c++的不同

l C++模板可以使用int等基本数据类型。Java则不行,必须转而使用Integer

l Java中,可以将模板的类型参数限定为某种特定类型。例如,你可能会使用泛型实现CardDeck,并规定参数必须扩展自CardGame。

l C++中,类型参数可以实例化,Java不可以实例化

l Java中,类型参数(即MyClass<Foo>中的Foo)不能用于静态方法和变量,因为他们会被MyClass<Foo>和MyClass<Bar>共享。但在C++中,这些类是不同的,类型参数可以用于静态方法和静态变量。

l  在Java中,不管类型参数是什么,MyClass的所有实例都是同一类型。类型参数会在运行时被抹去。而C++中,参数类型不同,实例类型也不同

32. Threadlocal的实现:https://www.cnblogs.com/WuXuanKun/p/5827060.html

33.    接口和抽象类的区别

l  接口的修饰符可以为public和default。将接口定义成protected和private是没有意义的,而且编译器也不允许这么做

l  接口可以extends接口,但是接口不能继承或者实现抽象类

l  接口中的变量默认都会被final修饰为常量,亦可以加static修饰符将其定义成静态常量,

l  接口中的变量由于是常量,须在定义接口的时候就为其初始化

l  接口方法的修饰符有public abstract均为默认修饰

l  关于接口中方法的实现:并不所有的子类都必须实现接口的方法,当子类是抽象类的时候,可以不实现接口中的方法

36. java exception类型:

l 1、Error

l 2、Runtime Exception 运行时异常

l 3、Exception

l 4、throw 用户自定义异常

37. HashMap什么情况下发生死链:并发环境下,hash冲突之后的互指

38.    索引一定有效吗?失效的情况?索引是怎么实现的?

l  隐式转换导致索引失效.

l  对索引列进行运算导致索引失效

l  使用Oracle内部函数导致索引失效

l a. 使用 <> 、not in 、not exist、!=

l b. like "%_" 百分号在前(可采用在建立索引时用reverse(columnName)这种方法处理)

39.    如果你的项目数据量大100倍,1000倍的话,数据库要怎么进行改进?(分库分表,然而我就知道分库分表并不知道怎么做。。)

40.    面向对象的原则

• 1. 单一职责原则(Single Responsibility Principle)每一个类应该专注于做一件事情。

• 2. 里氏替换原则(Liskov Substitution Principle)超类存在的地方,子类是可以替换的。

• 3. 依赖倒置原则(Dependence Inversion Principle)实现尽量依赖抽象,不依赖具体实现。

• 4. 接口隔离原则(Interface Segregation Principle)应当为客户端提供尽可能小的单独的接口,而不是提供大的总的接口。

• 5. 迪米特法则(Law Of Demeter)又叫最少知识原则,一个软件实体应当尽可能少的与其他实体发生相互作用。

• 6. 开闭原则(Open Close Principle)面向扩展开放,面向修改关闭。

• 7. 组合/聚合复用原则(Composite/Aggregate Reuse Principle CARP)尽量使用合成/聚合达到复用,尽量少用继承。原则: 一个类中有另一个类的对象。

41. ArrayList的sublist修改是否影响list本身:会,如果有扩容,父list会导致子list失效,子list会映射到父list

42.    分别介绍一下NIO,AIO,BIO

43. countdownLatch的底层实现:队列同步器

44. mysql锁:

l  行锁(Record Lock):锁直接加在索引记录上面。

l  间隙锁(Gap Lock):锁加在不存在的空闲空间,可以是两个索引记录之间,也可能是第一个索引记录之前或最后一个索引之后的空间。

l Next-Key Lock:行锁与间隙锁组合起来用就叫做Next-Key Lock。

45. tryLock()在什么场景下用

46. 502和504的区别:

a)      作为网关或者代理工作的服务器尝试执行请求时,从上游服务器接收到无效的响应,

b)      作为网关或者代理工作的服务器尝试执行请求时,未能及时从上游服务器(URI标识出的服务器,例如HTTP、FTP、LDAP)或者辅助服务器(例如DNS)收到响应。

58.    什么是ack攻击

a)      软件开发过程中的流程、敏捷开发的优势缺点、需求分析与设计

b) OSI七层模型: :物理层、数据链路层、网络层、传输层、会话层、表示层和应用层。

59.    • sql中的连接:内连接、外连接(左、右)、交叉连接。总结(左连接:左边有的,右边没有的为null 右连接:左边没有的,右边有的为null 内连接:显示左边右边共有的)

a)      数据库事务:ACID特性(原子性,一致性,隔离性,持久性),针对以下三个问题,提供了四种不同的事务隔离级别。

b)      脏读:读取了另一个未提交事务中的数据(事务执行了,但是未提交,可能会回滚)

c)      不可重复读:读取了前一事务提交的数据,造成读取前后不同

d)      幻读:和不可重复度相同,不同的是这个针对一批数据

60.    三级封锁协议:

a) 1 级封锁协议是:事务T在修改数据R之前必须先对其加X锁,直到事务结束才释放。事务结束包括正常结束(COMMIT)和非正常结束(ROLLBACK)。 1级封锁协议可防止丢失修改,并保证事务T是可恢复的。在1级封锁协议中,如果仅仅是读数据不对其进行修改,是不需要加锁的,所以它不能保证可重复读和不 读"脏"数据。

b) 2级封锁协议是:1级封锁协议加上事务T在读取数据R之前必须先对其加S锁,读完后即可释放S锁。2级封锁协议除防止了丢失修改,还可进一步防止读"脏"数据。

c) 3级封锁协议是:1级封锁协议加上事务T在读取数据R之前必须先对其加S锁,直到事务结束才释放。3级封锁协议除防止了丢失修改和不读'脏'数据外,还进一步防止了不可重复读。

61.    两段锁协议:在加锁阶段,事务只能加锁,也可以操作数据,但不能解锁,直到事务释放第一个锁,就进入解锁阶段,此过程中事务只能解锁,也可以操作数据,不能再加锁。

62.    方法区里面存放了什么,怎么判断是否需要收集方法区?答:类数据,方法数据等。实例已被回收,classloader已被回收以及无反射调用时可以回收。

63.    哪些可以作为GCRoot?虚拟机栈引用对象、静态属性引用对象、方法区中常量引用的对象、Native方法引用的对象。

64.    红黑树

(1)   每个节点或者是黑色,或者是红色。

(2)   根节点是黑色。

(3)   每个叶子节点是黑色。 [注意:这里叶子节点,是指为空的叶子节点!]

(4)   如果一个节点是红色的,则它的子节点必须是黑色的。

(5)   从一个节点到该节点的子孙节点的所有路径上包含相同数目的黑节点。

65.    代码运行的几个阶段?

66.    编译:预处理(编译头文件,替换宏等)、编译(转换为汇编语言文件)、汇编(得到机器语言)、链接(链接不同的.o文件,得到可执行程序)

67.    多态的好处:

a)      应用程序不必为每一个派生类编写功能调用,只需要对抽象基类进行处理即可。大大提高程序的可复用性。//继承

b)      派生类的功能可以被基类的方法或引用变量所调用,这叫向后兼容,可以提高可扩充性和可维护性。 //多态的真正作用,

68. 11. 重载和覆盖

a)      重载方法: 在一个类中用相同的名字创建多个方法(每个方法的参数表不同)

b)      方法覆盖: 在一个类中创建的方法与父类中方法的名字、 返回类型和参数表相同,覆盖是针对两个类说的,而且必须是子类(或孙类,孙孙类等)覆盖掉父类的方法

69. IO原理:DMA方式从磁盘读取到内存

70. NIO原理:buffer、channel和选择器(channel监控)

71. hashmap为什么扩充时2的幂次:代码中用到了位运算

72.    线程状态转换:新建、运行、阻塞、等待、死亡

17.    二叉树能代替B树么:不能,二叉树有最坏情况,平衡二叉树维护开销大

18.    内存调度算法: LRU:最近最少使用(Least Recently Used)、 FIFO:先进先出(First In First Out)、 Clock:时钟替换算法(Clock)

19.    数据库范式:第一范式(不可分割)、第二范式(有主键,消除依赖)、第三范式(消除非主属性的传递依赖)、BCNF(消除主属性的传递依赖)、第四范式(消除多值依赖)

20.    排序算法:基于交换、基于插入、堆、归并等

21.    操作系统主要组成部分:内核、shell、文件系统、应用程序

22.    操作系统内核的主要工作: 它负责管理系统的进程、内存、设备驱动程序、文件和网络系统

23.    模块方式加载的优点: 模块本身不编译进内核,从而控制了内核的大小;模块一旦被加载,将和其它的部分完全一样。可能产生模块不兼容

24. redis数据结构

25. TIME_WAIT和CLOESE_WAIT的区别:第一个是收到FIN并且发送ACK,等待一定时间就可以关闭了,第二个是收到FIN,等待去关闭连接(https://www.cnblogs.com/qlee/archive/2011/07/12/2104089.html

26. Xmx和Xms设置:内存分配,xms是开始垃圾回收值,xmx是最大内存

27. full gc日志格式:时间,停顿类型,区域,回收前后内存使用,gc占用时间

28. java 代理模式:静态、动态、Cglib代理(见魏世康java基础)

a) JDK:(代理模式:代理类和目标类实现共同的接口)

73.    代理模式的作用是:为其它对象提供一种代理以控制对这个对象的访问。在某些情况下,一个客户不想直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介作用。(分为抽象角色,代理角色和真实角色)

74.    实现InvocationHandler接口来实现一个动态代理类,再使用Proxy.newProxyInstance方法来动态创建一个代理对象的类。

a) CGLIB:(代理类是目标类的子类)

75. JDK的动态代理机制只能代理实现了接口的类,而不能实现接口的类就不能实现JDK的动态代理,cglib是针对类来实现代理的。(动态创建子类)

76.    代理类实现MethodInterceptor接口

77.    优点:CGLib创建的动态代理对象性能比JDK创建的动态代理对象的性能高不少,但是CGLib在创建代理对象时所花费的时间却比JDK多得多,所以对于单例的对象,因为无需频繁创建对象,用CGLib合适,反之,使用JDK方式要更为合适一些。同时,由于CGLib由于是采用动态创建子类的方法,对于final方法,无法进行代理。

78. 25. 序列化的实现:

a)      将对象实例相关的类元数据输出。

b)      递归地输出类的超类描述直到不再有超类。

c)      类元数据完了以后,开始从最顶层的超类开始输出对象实例的实际数据值。

d)      从上至下递归输出实例的数据

79. 26. 随机数生成,给1-5,生成1-7:https://blog.csdn.net/MDreamlove/article/details/48599107

1.     进程和线程的区别:

a)      进程是资源分配的最小单位,线程是程序执行的最小单位。

b)      进程有自己的独立地址空间,每启动一个进程,系统就会为它分配地址空间,建立数据表来维护代码段、堆栈段和数据段,这种操作非常昂贵。而线程是共享进程中的数据的,使用相同的地址空间,因此CPU切换一个线程的花费远比进程要小很多,同时创建一个线程的开销也比进程要小很多。

c)      线程之间的通信更方便,同一进程下的线程共享全局变量、静态变量等数据,而进程之间的通信需要以通信的方式(IPC)进行。不过如何处理好同步与互斥是编写多线程程序的难点。

d)      但是多进程程序更健壮,多线程程序只要有一个线程死掉,整个进程也死掉了,而一个进程死掉并不会对另外一个进程造成影响,因为进程有自己独立的地址空间。

3.      如何开启一个进程?fork()的优点

e) shell:效率低,需等待子进程返回

f) exec:替换原有进程,不返回原进程,继承原进程很多特性,效率高

g) fork:复制一个和子进程一模一样的进程,拥有自己的内存空间,需要注意僵尸子进程的问题

4. mySQL里有2000w数据,redis中只存20w的数据,如何保证redis中的数据都是热点数据

i.          相关知识:redis 内存数据集大小上升到一定大小的时候,就会施行数据淘汰策略(回收策略)。redis 提供 6种数据淘汰策略:

h) volatile-lru:从已设置过期时间的数据集(server.db[i].expires)中挑选最近最少使用的数据淘汰

i) volatile-ttl:从已设置过期时间的数据集(server.db[i].expires)中挑选将要过期的数据淘汰

j) volatile-random:从已设置过期时间的数据集(server.db[i].expires)中任意选择数据淘汰

k) allkeys-lru:从数据集(server.db[i].dict)中挑选最近最少使用的数据淘汰

l) allkeys-random:从数据集(server.db[i].dict)中任意选择数据淘汰

m) no-enviction(驱逐):禁止驱逐数据

5.      分布式存储rocksDB、redis、levelDB

6. tcp udp的区别, socket的使用 :

n)      基于连接与无连接;

o)      对系统资源的要求(TCP较多,UDP少);

p) UDP程序结构较简单;

q)      流模式与数据报模式 ;

r) TCP保证数据正确性,UDP可能丢包,TCP保证数据顺序,UDP不保证。

1. hash和树的区别:

s) hash查找较快,但是有最差情况。

t) hash需要提前分配很多地址,而树不需要,节约内存。

u)      树更适应动态插入,可扩展性较强,而hash负载过高需要扩容。

v)      树比较容易做成有序的。

2. http的服务器端和客户端能双向通信吗?可以,推送技术

3. full gc问题怎么定位?用什么工具?怎么定位到哪个线程和进程?答:年老代是否被写满、持久代是否被写满(动态类加载)、有没有显示调用System.gc()。用工具jmap(jhat)、jstack线程快照,用VisualVM可视化。

4.      单例模式实现:

w)     静态类+工厂模式

x)      单线程可以使用时生成

y)      枚举实现单例

z)      双重加锁,并发环境有问题

aa)    静态内部类:使用时才加载并且保证线程安全

5.      怎么用原生的JDBC访问数据库

bb)   加载JDBC驱动程序;

cc)    负责管理JDBC驱动程序的类 DriverManager 会识别加载的驱动程序,用 DriverManager 类的方法 getConnection()来创建一个数据库连接类的实例对象;

dd)   获取Connection对象的实例,用Connection对象的方法创建一个 Statement 对象实例,执行标准的SQL语句,对数据库、表进行相关操作。

ee)    返回的结果用 ResultSet 类来处理。

ff)      出现异常时,对事物进行回滚。

7. CPU使用率100%怎么分析解决:jps,top,jstack

8. CountDownLatch、CyclicBarrier和 Semaphore:

1. countDownLatch是计数器,初始化一个计数器,每个线程执行完减一,await最后被唤醒

2. CycliBarrier同步屏障,n个线程到达屏障时同时执行

3. Semaphore信号量,可控制并发的数量

9.      一致性hash原理,实现负载均衡

10.    为什么jvm调优经常会将-Xms和-Xmx参数设置成一样:减少动态调整消耗的资源

1. Get和Post请求

gg) GET 请求:

hh) GET 请求可被缓存

ii) GET 请求保留在浏览器历史记录中

jj) GET 请求可被收藏为书签

kk) GET 请求不应在处理敏感数据时使用

ll) GET 请求有长度限制

mm)GET 请求只应当用于取回数据

nn) POST 请求 :

oo) POST 请求不会被缓存

pp) POST 请求不会保留在浏览器历史记录中

qq) POST 不能被收藏为书签

rr) POST 请求对数据长度没有要求

猜你喜欢

转载自blog.csdn.net/u014381464/article/details/82788668