1.说一下java的面向对象?

要说Java的面向对象,先得理解面向过程。面向过程就是把一件事的完成分成不同步骤,按照流程去依次执行。这样是比较符合常规思维的,这样做逻辑清晰,但是如果需求经常发生变化,会导致经常大量修改,难以维护。面向对象就此应运而生,完成某件事情的时候,去抽象出几个类,每个类有自己的方法和属性,他们分别干自己的活。缺点在于把类抽象出来比较困难,但是以后的拓展就会比较简单。(毕竟有封装,继承,多态)。

2.说一下java的HashMap?

java的老版HashMap是数组加链表实现的,jdk1.8后就是数组加链表加红黑树。在单个链表长大于8时或数组长度大于64位时,会启用红黑树存储。HashMap是双列集合,键值对存储。根据键计算hash值,根据hash值找到hash表的索引,然后存储值。

 

3.java sleep方法和wait方法的区别

1.sleep方法是线程中的方法,wait方法是object中的方法

2.sleep方法会释放锁,wait方法不会释放锁

3.sleep方法不依赖synchronized同步器,而wait方法需要依赖同步器

4.sleep不需要别个线程来唤醒,而wait需要

 

4.final,finalize,finally的不同之处

final是一个修饰符,可以修饰变量,方法,类,如果修饰变量,意味着该变量不可改变

finally是一个关键字,与try,catch一起使用。无论try中是否有异常,finally一定会执行

(try {}里有一个return语句,那么紧跟在这个try后的finally {}里的code会不会被执行,什么时候被执行,在return前还是后?会执行,在return前)

finalize方法是在对象被回收之前调用的方法,给对象最后一次复活机会,但是什么时候调用没有保证 (已过时)

 

5.HashCode 方法有什么用呢?与equals方法有什么区别呢?

HashCod是用于一般的对象比较,作为大范围筛选比较。如果hashCode相等,在去进行equals比较是否完全相等。如果hashCode不相等,那么对象就一定不相等,可以减少equals方法的比较次数。(equals方法执行效率比较低),而hashCode查找速度就比较快,它的存在主要是提高查询效率。

 

6.a==b 与 equals 的差别

==比较的是两个变量的值是否相等,如果是对象的话,就比较对象的引用是否相等。而equals表示对象的内容是否相等,比较的是两个独立对象的长相(字符串重写了equals)。

 

7.ArrayList和LinkedList的区别

ArrayList是基于数组存储,而LinkedList是基于链表存储。

ArrayList的查询快,LinkedList较慢(因为需要从头或从尾部遍历)。

LinkedList的删改较快

LinkedList需要更多的内存(每个结点三个遍历)。

 

8.Collection 和 Collections 的区别

Conllection是单列集合的接口,如set,list。Collections是工具类,定义了许多操作容器的静态方法。

 

9.HashTable 和 HashMap的区别

安全性:HashTable是线程安全的(加了锁),HashMap是非线程安全的。因此hashMap效率会高一点,安全性低一点。

是否可以使用null作为key:hashTable不允许,而hashMap允许。hashMap使用null位key时,总是存储在table数组第一个节点。

默认容量及扩容机制:

HashMap 的 初始容量为16,HashTable的初始容量为11,两者的填充因子默认都是0.75

HashMap的扩容是容量(capacity)翻倍,hashTable的扩容是capacity * 2 + 1

 

10.Integer 和 int 哪个占用内存多?

答案是Integer。Integer是对象,它有一个控制作用。在数据库操作中,经常要使用Integer,因为可以接受null,有对象的性质。

 

11.Java 中的++ 操作符是线程安全吗?

不是线程安全的操作。它涉及到多个操作,如读取变量值,增加,然后存储到内存,这个过程可能会出现多个线程交错从而导致值的不正确性。

 

12.java如何去实现序列化,有什么意义呢?

1.为什么要实现序列化?

因为网络传输的数据是二进制的,而java是对象。是没有办法在网络中传输的,所以需要对Java对象进行序列化,同时要求这个转化算法是可逆的,不然不知道你传过来的是个什么鬼东西。

2:java原生序列化

只要让类实现 Serializable 接口就行,序列化具体的实现是由 ObjectOutputStream 和 ObjectInputStream 来实现的

一般使用第三方的json实现

 

13.String str = new String(“abc”); 中实现了几个对象的创建?

两个对象,一个是常量池的”abc”,一个是new 创建在堆的对象,堆对象的引用指向常量池。

 

14.abstract class 和 interface 区别?

接口是对动作的抽象,抽象类是对根源的抽象。

一个类只能继承单个抽象类,所以成本代价是比较高的。而接口是可以多继承的。

抽象类的功能远超过接口,因为抽象类中可以定义构造器,可以有抽象方法和具体方法。而接口不能定义构造方法,且

全部方法都是抽象方法。

 

15.GC是什么? 为什么要有GC?

GC是gabage collection,内存处理是一个容易出错的问题,忘记或错误的内存回收会导致系统不稳定,甚至奔溃。java提供的gc

功能可以自动检测对象是否超过作用域从而达到自动回收,java没有提供释放已分配内存的显式操作方法。

 

16.写一个Singleton出来

//第一种方法
public class ASingleton{
   private static ASington instance = new ASingleton();
   public static ASingleton getInstance(){
       return instance;
  }
}

//第二种方法
public class BSingleton{
   private static BSington instance = null;
   public static synchronized BSingleton getInsetance(){ //提高了效率
       if(instance==null){
           instance = new BSingleton();
      }
       return instance;
  }
}

 

17.构造器constructor能否被override?

不能。构造器不能重写,即overriding,但是可以重载overloading。

 

18.写几个常见的runtime exception

NullPointException

ArithmeticException

ClassCastException

IndexOutOfBoundsExcepton

 

19.启动一个线程是使用run方法还是start方法?

start方法。使用start方法表示该线程所代表的处理机进入可运行状态,可以由jvm调度运行。这并不意味着可以立即执行。

 

 

20.如何通过反射调用对象的方法?

Class c = Student.class;
Object obj = c.getConstruct().newInstance();
Method m = c.getMethod("run");
m.invoke(obj);

 

21.两个不相等的对象可不可能有相等的hashCode?

可能。这就是为什么hashMap会有hash冲突。

“Aa”.hashCode == “Bb”.hashCode==”c#”.hashCode

 

22.重载和重写的区别?

重载是一个类中的方法名不同,参数列表多样性。重写是子类对父类的相同方法的改造,体系java多态性(即父类的引用去调用方法,既可以使用自己的方法,也可以使用子类继承后改造的方法)。

 

23.什么是用户线程?什么是内核线程?

在java中,基本我们说的都是用户线程。应对到操作系统上,另一种叫内核线程。

用户线程和内核线程对应着某种联系。多对一,一对一。

多对一线程:多个用户对应到同一内核线程上,线程的创建,调度,同步的所有细节全部由进程的用户空间线程库来处理。

优点:用户线程的很多操作对内核来说都是透明的,不需要用户态和内核态之间的频繁切换。使线程的创建,调度,同步等非常快。

缺点: 由于多个用户线程对应到同一个内核线程,如果其中一个用户线程阻塞,那么其他用户线程无法执行。内核并不知道用户态有

哪些线程,无法向内核线程一样实现较为完整的调度,优先级。

 

一对一模型:即一个用户线程对应一个内核线程,内核负责每个线程的调度。

优点:比如把所有线程操作都交给了jvm,所以实现起来简单。

缺点:对用户线程的操作都会映射到内核线程上,引起用户态和内核态的频繁切换;内核为每个线程都映射内核实体,若存在大量线程,

会对系统性能造成影响。

 

24.什么是jvm,与jdk有什么区别?

jvm是java virtual machine,是Java程序运行的底层平台。与java库一起构成了java程序的执行环境。

.java -> .class -> jvm -> 操作系统

区别:JRE = JVM + java标准库

JDK = JRE + 开发调试工具

 

25.说一下jvm的跨平台,跨语言?

跨语言:jvm只识别字节码,所以jvm其实跟语言是解耦的。

跨平台:写一个类可以运行在不同的操作系统上。

 

26.JVM的运行时数据区有哪些?

运行时数据区的定义:java虚拟机在执行程序时,会把内存分成多个不同的数据区。

数据区包括以下几个部分:

程序计数器(线程私有区)

java虚拟机

本地方法栈

堆内存(线程共享区)

方法区

运行时常量池

 

27.什么是堆空间?堆内存包括哪些部分?

堆是jvm最大的内存区。我们申请的所有对象都是在这申请的。堆空间为了方便gc模块进行对象的分配和回收,

把堆空间分为新生代( eden(8) + s0(1) + s1(1) )和老生代。

image-20220310122053794

 

 

28.什么是内存溢出?

out of memory 是指jvm内存不足,jvm运行需要使用的内存最大值溢出。会导致jvm异常。

常见的oom有:

栈溢出

堆溢出

方法区溢出

本机直接内存溢出

 

29.什么是内存泄漏?和内存溢出有什么区别?

memory leak 是指本来无用的对象却继续占用内存,没有在恰当的时机释放内存。不使用的内存没有被释放,叫做内存泄漏。

如果存在严重的内存泄露,必然会导致内存溢出。

内存泄漏一般是资源管理问题和程序的bug,内存溢出是内存空间不足或内存泄漏后的最终结果。

 

30.对象头包含哪些部分?

在hotSpot虚拟机中,对象在虚拟机中存储的布局可以分为三个区域:对象头,实例数据,对其填充。

image-20220310123947593

 

 

31.给定一个具体的类,分析对象的内存占用?

image-20220310124531987

 

32.常用的jvm启动参数有哪些?

设置堆内存:-Xmx4g 堆最大空间 -Xms4g 堆初始化空间

指定gc算法:-XX:+UseG1GC -XX:MaxGCPauseMillis=50

指定gc并行线程数:-XX:ParallelGCThreads=4

打印gc日志:-XX:+PrintGCDetails -XX:+PrintGCDateStamps

指定gc日志文件:-Xloggc:gc.log

指定mata区的最大值:-XX:MaxMataspaceSize=2g

设置单个线程的大小:-Xss1m

指定jvm内存溢出进行自动dump:-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath:/usr/local/

 

33.设置堆空间的最大值(-Xmx)应该要考虑哪些因素?

需要根据系统的配置来确定。要给操作系统和其他内存区(栈,方法区)留下一定的空间。

建议系统或容器的可用内存的70% ~ 80%

 

34.java 8 默认使用的垃圾收集器是什么?

parallel gc 并行垃圾回收器

 

35.什么是并行垃圾回收器?

并行垃圾回收器是指多个线程并行的执行垃圾回收,能充分利用cpu多核的能力,缩短垃圾收集的暂停时间。

除了单线程的gc,其他的垃圾收集器,比如ps,cms,g1等新的垃圾收集器都使用了多个线程来执行gc工作。

 

36.什么是STW?什么是安全点?什么是安全区域?

因为gc过程中,所有应用线程都需要暂停之后才能执行gc,这时候就叫做STW,或者叫gc暂停。

什么是安全点:用户线程要暂停,gc线程要开始工作,但是要确保用户线程暂停的这些字节码指令是不是会导致引用的变化

所有jvm会在字节码指令中,选一些指令,作为安全点,比如方法的调用,循环跳转,异常跳转等,一般是这些指令才会产生

安全点。为什么叫做安全点,是这样的,gc要暂停业务线程,并不是抢占式中断(立马把业务线程中断),而是主动中断。

主动式中断是设置一个标志,这个标志是中断标志,各业务线程在运行过程中会不停的主动去轮询这个标志,一旦发现中断

标志为true,就会在自己最近的安全点上主动中断挂起。

为什么需要安全区域?

要是业务都不执行,(业务线程处于sleep和blooked状态),那么程序就没办法进入安全点,对于这种情况,就必须引入安全区域。

安全区域是指,确保在某一代码片段中,引用关系不会发生变化,因此,在这个片段中的任何时候进行垃圾回收都是安全的。我们可以

把安全区域看作被拓展拉伸的安全点。

 

37.如过cpu频率突然飙升,你该如何排查?

1.先通过top命令找到消耗cpu很高的进程id(假如是2372)

2.执行top -p 2372单独监控该进程

3.在第二步的监控界面输入H,获取当前进程下的所有线程信息

4.找到消耗cpu特别高的线程编号(假设是2734)

5.执行jstack 2372 对当前的进程做 dump,输出所有日志信息。同时将第四步得到的十进制线程id转换成16进制(AEE),在

堆栈信息里面去找对应线程内容。

6.最后解读线程信息,定位具体代码位置

 

38.CMS,G1垃圾回收器的三色标记你了解吗?

三色标记法是一种垃圾回收法,它可以让jvm不发生或短时间发生(stw)stop the world,从而达到清除jvm内存垃圾的目的。

三色标记法,将对象的颜色分为黑,白,灰,三种颜色。

黑色:该对象已经被标记过了,且该对象一下的所有属性都标记了。

灰色:对象已经被垃圾收集器扫描过了,但是该对象还存在没有扫描的引用

白色:表示对象没有被垃圾收集器扫描过,即表示不可达

 

三色标记的漏标问题

不是垃圾的当作垃圾

CMS解决方案:Incremental Update 重新扫描

G1的解决方案:SATB(snapshot at the beginnig)

 

39.讲一讲类加载和类加载器?

一个类从被加载到java虚拟机内存开始,到卸出内存为止,它的整个生命周期将会经历加载(loading),验证(varification),

准备(preparation),解析(resolution),初始化(initilization),使用(using),卸载(unloading)七个阶段。

其中验证,准备,解析三个部分统称连接。

加载阶段需要完成以下三件事:

1.通过一个类的全限定名来获取此类的定义此类的二进制字节流

2.将这个字节流所代表的静态存储结构转化为方法区的运行时数据结构

3.在内存中生成一个代表这个类的java.lang.Class对象,作为方法区这个类的各种数据的访问入口

java虚拟机团队把类加载阶段中通过一个类的全限定名来获取描述该类的二进制流这个动作放到java

虚拟机外部去实现。便于程序应用自己决定如何获取所需的类。实现这个动作的代码被叫做类加载

 

40.什么是双亲委派机制?它有什么作用?

双亲委派机制的意思是除了顶层的启动类加载器以外,其余的类加载器,在加载之前,都会委派给它的父加载器进行加载。

这样一层层向上传递,直到祖先们都无法胜任,它才会真正的加载。

作用:

1.通过带有优先级的层级关系可以避免类的重复加载。

2.保证java程序安全稳定运行,java核心api定义类型不会被随意替换

 

image-20220312145459749

 

41.G1收集器有哪些特点?

G1的全称是garbage-first,意为垃圾优先。哪一块的垃圾最多就优先清理它。

特点:

1.空间整合

2.多线程+并发+可预测停顿

 

42.你有哪些手段来排查OOM?

当jvm中内存不够,并且垃圾回收的速度跟不上内存的分配速度,就会发生oo现象。

jdk1.8推荐生产环境开启以下两个参数:

-XX:+HeapDumpOnOutOfMemoryError 当oom发生时,自动dump堆内存信息

-XX:HeapDumpPath=/tmp/heapdump.hrof dump 堆信息存放目录

 

43.使用过哪些JVM相关的命令工具?

命令行工具;

jps:列出当前机器上正在运行的虚拟机进程

jstat:用于监视虚拟机各种运行状态信息的命令行工具

jinfo:查看和修改虚拟机的参数

jmap:

jhat:

jstack:

 

43.为什么使用消息队列MQ?

三个核心:解耦,异步,削峰

image-20220320125926129

image-20220320130145837

image-20220320131028327

44.如何选择合适的消息队列

RabbitMQ:

image-20220320131314314

image-20220320131447837

kafka:性能相当优越

RocketMQ:有非常多的中文社区

 

45.RabbitMQ如何保证消息不丢失?

image-20220320132457825

1.确保消息到MQ:发送方的确认模式

2.确保消息路由到正确的队列:路由失败通知

3.确保消息在队列正确的存储:交换器,队列,消息都需要持久化

4.确保消息从队列正确的投递至消费者:手动确认->交给消费者来确认

46.什么是MQ中的消息重复?

image-20220407074610210

image-20220407074722077

 

第二类原因

image-20220407074829960

image-20220407074949974

 

47.如何解决MQ中的重复消息?

1.MVCC:多版本并发控制,乐观锁的一种实现方式(每个version只有一次执行成功的机会)

2.设计去重表

image-20220324081513136

48.如何实现RocketQueue的性能调优?

jvm方面:监控暂停,消除偏向锁,垃圾回收参数

操作系统层面:基本参数

网卡:网络接口控制器

image-20220324082819399

49.Mysql有哪些存储引擎?

mysql的最大一个特点:插件式表的存储引擎。每个存储引擎都有各自的特点,能够根据具体的应用建立不同存储引擎表。

InnoDB存储引擎:

InnoDB是mysql默认的存储引擎,也是最重要,最广泛的存储引擎,它被设计用来处理大量的短期(short-live)事务,涉及事务,优先考虑InnoDB。

MyISAM:

在mysql5.1之前,MyISAM是默认的存储引擎。

但是MyISAM不支持事务和行级锁,而且崩溃后无法安全恢复

同时MyISAM对整张表加锁,很容易因为表锁的问题影响性能

Memory引擎:

至少要比MyISAM快一个数量级,数据文件是存储在内存中。

memory表的结构在重启后还会保留,但数据会丢失。

Memory表在很多场景中可以发挥好的作用:

用于查找或映射表,例如将邮编和州名映射的表。

用于缓存周期性聚合数据的结果。

用于保存数据分析中产生的中间数据。

Archive引擎:

Archive引擎只支持INSERT和SECLECT操作,会缓存所有的写并利用zlib对插入的行进行压缩,所有回避Archive表的磁盘I/O更少。但是

每次select查询都需要执行全表扫描。所有Achive适合日志的数据采集类应用。

CSV引擎:

CSV引擎可以将普通的csv文件(逗号分隔值的文件)作为mysql的表来处理,但这种表不支持索引。它作为一种数据交换的机制,非常有用。

50.MyISAM和InnoDB的区别是什么?

1.InnoDB支持事务,MyISAM不支持事务。

这是MyISAM变成InnoDB的重要原因之一。

2.InnoDB支持外键

3.InnoDB是聚集索引。

4.InnoDB不保存表的行数

5.InnoDB最小锁的粒度是行锁,MyISAM最小的锁粒度是表锁。

51.数据库表设计时,字段你会如何选择?

整型 > date,time, > enum char > varchar > blob,text

image-20220324102640938

image-20220324102728279

image-20220324102845537

52.Mysql中VARCHAR(M)最多能存储多少数据?

对于这种数据类型最多可以定义65535个字节,但是实际上,除了blob和text外,其他所有的列占用的字节长度都不能超过65535.

53.请说一下事务的基本特性?

原子(要么成要么败),持续(永久保存),隔离(最终提交前,其他事务对它不可见),一致(守恒)

54.事务并发可能引发什么问题?

脏读:

读取到另外一个没有提交的数据

不可重复读:

同一个事务中,前后两次读取的数据不一致

幻读:

同一个事务中,读到了前一次没有看到的数据。(强调集合的增减)

55.简单描述一下MySQL的各种索引?

按字段特性分类:主键,普通,前缀索引

1.主键索引

2.唯一索引 UNIQUE:

索引列值允许为空,出现多个空置不会发生重复冲突

3.前缀索引:

是指对字符类型字段的前几个字符或二进制类型字段的前几个bytes建立的索引,前缀索引可以建立在类型为char,varchar,binary,varbinary的列上,可以大大减少索引占用的存储空间,也能提升索引的查询效率

前缀索引是一种使索引更小更快的有效方法,但是无法使用前缀索引做order by和group by操作

56.什么是三星索引?

对于一个查询而言,一个三星索引,可能是其最好的索引。

如果查询使用三星索引,一次查询通常只需要进行一次磁盘随机读以及一次窄索引片的扫描,因此比普通索引所花时间少几个数量集

image-20220324105846051

57.InnoDB一棵B+树可以存放多少行数据?

答案:约2千万

InnoDB存储引擎有最小存储单元–页,一个页的大小是16k。

InnoDB的所有数据文件(后缀名为ibd的文件),它的大小始终是16k的整数倍。

58.如何提高insert的性能?

1.合并多条Insert为一条

原因:合并后,日志量会减少,降低日志刷盘的数据量和频率,从而提高效率。通过合并sql语句,也可以减少sql语句解析的次数,

减少网络传输的io。

2.修改参数 bulk_insert_buffer_size,调大批量删除的缓存

image-20220330193233105

4.手动使用事务

因为mysql默认是autoCommit的,这样每次插入一条数据,会进行一次commit;我们可以在一次事务中插入多条数据再提交

59.什么是全局锁,共享锁,排他锁?

全局锁就是对整个数据库的实例加锁。这个命令可以使整个库处于只读状态。使用该命令后,数据更新语句,数据定义语句,更新事务

的提交语句等操作都会被阻塞。

共享锁又称读锁。其他用户可以并发读取数据,但是不能更改数据,直到已释放所有共享锁。如果事务对读锁进行修改操作,

可能会导致死锁。

排他锁又称写锁。若某个事务对某一行加上了写锁,只能整个事务对他进行读写。其他事务不能对其加任何锁,其他进程可以读,

但是不能写,需等待其释放。它是悲观锁的一种实现方式。

 

60.谈一下mysql中的死锁?

死锁是指两个或两个以上的进程在执行过程中,因争夺资源而造成的一种相互等待的现象,若无外力作用,它们将无法继续推进。此时称

系统处于死锁或系统产生死锁。

如何查看死锁?

使用命令 show engine innodb status 查看最近的一次死锁。

InnoDB Lock Monitor 打开监控锁,每15s输出一次日志。使用完毕后建议关闭,否则会影响数据库性能。

对待死锁常见的两种策略:

1.innodblockwait_timeout来设置超时世间,一直等待直到超时。

2.发起死锁检测,发现死锁后,主动回滚死锁中的某一事务,让其他事务继续执行。

 

61.什么是Redis?

Redis是现在最受欢迎的数据库之一,包含多种数据结构,支持网络,基于内存,可选持久性的键值对存储数据结构。有以下特点:

1.基于内存运行,性能高效

2.支持分布式,理论上支持无限拓展

3.key-value存储系统(key是字符串,键有字符串,列表,集合,散列表,有序集合等)

4.使用c语言编写,开源的,提供多种语言的api

 

62.Redis有哪些数据类型?各自的使用场景?

Redis主要有5种数据类型,String,List,set,zset,hash,满足大部分的使用要求。但redis还提供了几种高级的数据结构,

bitmaps,Hyperlonglong,geo等,其中bitmap,HyperLongLong底层是基于String,Geo则是基于zset

 

String:是redis最基础的数据结构,首先键都是String类型,而且其他几种数据结构都是建立在它的基础上。

字符串类型的值可以是字符串(简单的字符串,复杂的字符串(例如JSON,XML)),数字(整数,浮点数),甚至

是二进制(图片,音频,视频),但是值最大不能超过512M.

字符串类型的使用场景:(非常广泛)

1.缓存功能:Redis作为缓存层,Mysql作为存储层,绝大部分数据都是从redis获取。由于redis具有支持高并发

的特性,加速后端读写和降低后端压力的作用

2.计数:使用redis作为计数的的基础工具,它可以实现快速计数,查询缓存的功能。同时数据可以异步到其他数据源。

3.共享session:一个分布式web服务将用户的session信息(例如用户登录信息)保存在各自服务器中,这样会造成一个问题,

处于负载均衡的考虑,分布式服务会将用户的访问均衡到不同的服务器上,用户刷新一次访问可能会发现需要重新登录,这个

问题是用户无法容忍的。为了解决这个问题,可以使用redis将用户的session进行集中管理,在这种模式下只要保证Redis是高可用

和拓展性的,每次用户更新或查询登录信息都直接从Redis中直接获取。

4.限速:比如很多应用出于安全考虑,会在每次用户在进行登录时,让用户输入手机验证码,从而确定是否用户本人。但是为了短信接口

不被频繁访问,会限制用户每分钟获取验证码的频率,例如一分钟不超过5次。一些网站限制一个ip地址不能在一秒钟之内访问n次也采用

类似的思路。

 

list(链表):即链表,列表类型是用来存储多个有序的字符串,a,b,c,d,e五个元素从左到右组成了一个有序的列表,列表中的每个字符串

称为元素。

列表类型的两个特点:1.元素是有序的 2.元素可以重复

使用场景:

1.消息列表,Redis的lpush + brpop 命令组合即可实现阻塞队列,生产者客户端使用Irpush从列表左测插入元素,多个消费者客户端使用brpop命令阻塞式的 “抢”列表尾部的元素,多个客户端保证了消费的负载均衡和高可用性。

2.文章列表:

每个用户有属于自己的文章列表,现需要分页展示文章列表。此时可以考虑使用列表,因为列表不但是有序的,同时支持按照索引范围获取元素。

3.实现其他数据结构:

lpush + lpop = statck (栈)

lpush + rpop = queue(队列)

lpush + ltrim = capped collection(有限集合)

lpush + brpop = message queue (消息队列)

 

hash:hash类似于JDK1.8前的HashMap,内部实现也差不多(数组+链表)。

使用场景:

哈希类型比较适宜存放对象类型的数据,如果数据库中的记录为:

image-20220331211225079

使用string类型:

set user:1:name king;

set user:1:age 18;

set user:1:sex boy;

优点:简单直观,每个键对应一个值

缺点:键数过多,占用内存多,用户信息过于分散,不用于生产环境

将对象序列化存入redis

set user:1 serialize(userInfo);

优点:编程简单,若使用序列化合理内存使用率高

缺点:序列化和反序列有一定开销,更新属性时需要把userInfo全部取出来进行反序列化,更新后在序列化到redis

使用hash类型:

hmset user:1 name king age 18 sex boy

优点:简单直观,使用合理可减少内存空间消耗

缺点:要控制内部编码格式,不恰当的格式会消耗更多的内存

 

set:类似于java的hashset。redis的set类型是一种无序集合,集合中的元素没有先后顺序。当你需要存储一个列表数据,又不需要重复

数据,set是一个很好的选择。

image-20220331212636102

使用场景:

set提供了判断某个成员是否在一个set集合内的一个接口,这个也是list集合不能提供的。可以基于set实现交集,并集,差集的操作。

集合类型比较典型的使用场景就是标签(tag)。例如一个用户可能对娱乐,体育比较感兴趣,另一个用户可能对历史,新闻比较感兴趣,这些兴趣点就是标签。有了这些数据就可以得到喜欢同一个标签的人,以及用户的共同喜好的标签,这些数据对于用户的以及增加

用户的粘稠度比较重要。例如一个电子商务的网站会对不同标签的用户做不同的类型推荐,例如对数码产品比较有兴趣的人,在各个页面

或者通过邮件的形式给他们推荐最新的数码产品,为网站带来更多利益。

除此之外,集合还可以通过生产随机数进行抽奖活动,以及社交图谱等。

 

zset:有序集合,它使用分数(score)排序,有序集合提供了获取指定分数和元素范围查询,计算成员排名等功能,合理的利于有序集合能帮助我们在实际开发中许多问题。

使用场景:有序集合比较典型的场景就是排行榜。例如视频网站需要对用户上传的视频做排行榜,榜单的维度可能是多维度的:按时间,

按照播放量,获得赞数等。

 

bitmaps:现代计算机使用二进制信息作为存储单位,1个字节表示8位,例如”big”字符是由3个字节组成,但实际在计算机存储时,将其使用二进制表示,”big“对应的ASCLL码分别为98,105,103,二进制表示为……

bitmaps本身不是一种数据结构,实际上它就是字符串,但是它可以对字符串的位进行操作。bitmaps单独提供了一套命令,所以在redis中使用bitmaps和使用字符串的方法不太相同。可以把bitmaps想象成以位为单位的数组,数组的每个单位只能存储0,1,数组的下标在

bitsmap中叫做偏移量

使用场景:适合需要保存状态信息(比如是否签到,是否登录…)并需要对这些信息进行分析的场景。比如用户签到情况,活跃用户情况,用户行为统计(比如是否点赞过某个视频)

 

63.为什么要使用redis缓存呢?

主要从高性能和高并发来考虑。

高性能:假如用户第一次访问数据库中的某些数据,这个过程会比较缓慢,因为是从硬盘中读取的。将该用户的数据放到缓存中,

这样下一次要访问时就直接从缓存中获取了。操作缓存就是直接操作内存,所以速度会相当快。如果数据库中的数据发生改变后,

同步改变缓存中的数据即可。

高并发:直接操作缓存能承受的请求是远远大于直接访问数据库的,所以我们可以考虑把数据库中的部分数据转移到缓存中去,

这样用户的一部分请求会直接到缓存这里,而不需要经过数据库。

 

64.Redis和Memcached的区别?

两者都是非关系型内存键值数据库,现在公司一般都是使用redis实现缓存。而且redis自身也越来越强大了。它们主要两点不同:

1.memcached所有的值都是字符串,redis作为替代者,有丰富的数据类型

2.redis的速度要快很多

3.redis可以持久化数据

 

65.Redis的应用场景?

计数器:

可以对string进行自增,自减运算,从而实现计数器功能。redis这种内存型数据库的读写性能非常高,很适合存储频繁读写的计数量

缓存:

将热点数据放到内存中,设置内存的最大使用量以及淘汰策略来保证缓存的命中率。

会话缓存(FPC):

除基本的会话token外,redis还提供了简单的FPC平台。以magento为例,magento提供了一个插件来使用redis作为全页缓存后端,

此外,wordPress的用户来说,pantheon有一个非常好的插件wp-redis,这个插件帮助你以最快的速度加载你曾经访问过的页面。

查找表:例如DNS记录就很适合使用redis进行存储,查找表和缓存类似,也是利用了redis快速查找的特型。但是查找表的内容不能失效,而缓存的内容可以失效,因为缓存不作为可靠数据的来源。

消息队列(发布/订阅功能):

List是一个双向链表,可以通过Ipush 和 rpop 写入和读取消息。不过最好使用Kafka,rabbitMQ等消息中间键

分布式锁:

在分布式场景下,无法使用单机环境下锁来对多个节点的进程进行同步。可以使用Redis自带的SETNX命令实现分布式锁,

除此之外,还可以使用官方提供的RedLock分布式锁实现

其他:set可以实现交集,并集等操作,从而实现共同好友等功能。zset可以实现有序性操作,从而实现排行榜功能。

 

66.Redis为什么这么快?

1.完全基于内存,绝大部分请求是基于内存操作,非常快速。数据存在内存中,类似于hashmap,hashmap的优势就是查找和操作的

时间复杂度都是o(1)

2.数据结构简单,对数据操作也简单,redis的数据结构是专门进行设置的

3.采用单线程,避免了不必要的上下文切换和竞争条件,也不存在多进程和多线程切换cpu带来的消耗,不用去担心各自锁的问题,不存在加锁和释放锁的操作。不可能因为死锁而导致性能消耗。

4.使用多路I/O复原模型,非阻塞I/O

5.使用底层模型不同,它们之间底层实现方式以及与客户端之间通信的协议不一样,redis直接自己构建了VM机制,因为一般的系统调用函数的话,会浪费一定的时间移动和请求。

 

67.为什么要用redis而不用map/guava做缓存?

缓存分为本地缓存和分布式缓存。

以java为例,使用map/guava实现的是本地缓存,最主要的特点是轻量快速,生命随jvm的销毁而结束。并且在多实例的情况下,每个实例都需要单独保存一份缓存,缓存具有不一致性。

使用redis和memcached之类的称为分布式缓存,在多实例的情况下,各实例共用一份缓存,缓存具有一致性,缺点是要保证redis和memcached服务的高可用,整体架构上较为复杂。

 

68.redis的持久化机制是什么?

redis的数据都是保存在内存中,如果突然宕机,数据就会全部丢失,因此必须有一种机制来保证redis的数据不会因为故障而丢失。这种机制就是redis的持久化机制。redis的持久化机制有两种,第一种是RDB快照,第二种是AOF日志

RDB持久化:

将某个时间节点的redis数据保存到一个RDB文件中。该文件是一个经过压缩的二进制文件,通过该文件可以还原生成rdb文件时redis中的数据。redis提供了两个命令来创建RDB文件,一个是SAVA,一个是BGSAVA

 

载入RDB文件:

载入RDB文件的目的是为了在redis服务器进程重新启动后还原之前存储在redis的数据,然后,redis载入RDB文件没有专门的命令,而是在redis服务器启动时自动执行的。而且,redis服务器启动时是否会载入RDB文件还取决于服务器是否启用了AOF功能,具体逻辑判断为:

1.只有在AOF处于关闭的状态下

2.如果启动了AOF,那么优先使用AOF文件来还原数据

 

image-20220403151825597

image-20220403152012638

image-20220403152238877

 

69.如何保证数据库和缓存双写时的数据一致?

什么是数据一致性问题?

只要使用到缓存,无论是本地缓存和网络缓存,都会存在数据同步的问题

image-20220403152909919

image-20220403153015917

image-20220403153205781

image-20220403153331775

image-20220403153428060

image-20220403153603513

image-20220403153834827

image-20220403153855529

image-20220403154307359

image-20220403154524057

image-20220403154545671

image-20220403154628232

image-20220403155044022

image-20220403155129228

image-20220403155708110

70.什么是缓存穿透?怎么解决?

image-20220405065504275

image-20220405065550671

image-20220405065604608

image-20220405065710105

image-20220405065727915

image-20220405065758230

 

71.进程和线程的区别?

image-20220405065852601

image-20220405070050370

72.什么是多线程中的上下文切换?

image-20220405070148668

image-20220405070215764

image-20220405070235345

 

73.Java的内存模型是什么?

JJM,java memory model

因为在不同的硬件生产商和不同的操作系统下,内存的访问有一定的差异,所以会造成相同的Java代码运行在不同的机器上会出现各自问题。所以java内存模型屏蔽掉各种硬件和操作系统的内存访问差异,以实现让Java程序在各平台下都能达到一致的并发效果。

java内存模型规定所有的内存保存在主内存中(包括实例变量,静态变量)

每个线程都有自己的工作内存,线程的工作内存保存了该线程使用的变量(局部变量)和主内存的副本拷贝,线程对变量的操作都在工作内存中进行。线程不能读写主内存中的变量。

image-20220405071258071

image-20220405071403644

 

74.什么是原子操作?在JUC中有哪些原子操作类?

原子操作是指一个不受其他操作影响的操作任务单元。原子操作是在多线程环境下避免数据不一致必须的手段。

比如:对在主内存的int进行++操作就不是原子的,在jmm中,需要从主内存进行读取复制到工作内存,然后线程进行

相加,最后把结果写回主内存。

所以当一个线程读取它的值并加1时,另外一个线程有可能会读到之前的值,就会引发错误。

为了解决这个问题,必须保证增加操作是原子的(确保操作不受其他线程影响)

所以JDK提供了很多原子操作类:

AtomicBoolean,AtomicInteger,AtomicLong,AtomicReference等等

75.什么是CAS操作,缺点是什么?

CAS操作:Compare & Swap 或是 Compare & Set

在程序中我们使用 CAS + 自旋的方式就可以实现原子操作

image-20220405073217680

CAS的缺点:

1.只能支持一个变量的原子操作

2.CAS频繁失败导致cpu开销过高

3.ABA问题

 

76.Java中的volatile变量有什么作用?

1.保证了不同线程对该变量操作内存的可见性

2.禁止指令重排序

image-20220405074127533

image-20220405074359288

 

77.volatile变量和atomic变量有什么不同?

image-20220407075130273

image-20220407075357572

 

78.Local接口的优势是什么?对比Synchrnized它有什么优势?

Lock接口对比同步方法和同步块提供了更具拓展性的锁操作:

image-20220407075702408

image-20220407075906211

 

79.乐观锁和悲观锁如何理解及如何实现,有哪些实现方式?

image-20220407080149901

image-20220407080257084

 

80.什么是死锁?死锁的危害?

死锁:是指两个或两个以上的进程(或线程)在执行过程中,因争夺资源而造成的一种相互等待的现象,若无外力作用,它们都将无法推进下去。

image-20220407080826256

image-20220407080909161

 

81.什么是Callable 和 Futrue?

Callable类似于Runnable,但是Runnable不会返回结果,并且无法抛出没有返回结果的异常。

image-20220407081349641

image-20220407081430088

 

82. 什么是FutureTask?以及它的原理是什么?

image-20220407085801107

image-20220407085930128

image-20220407090015571

image-20220407090224497

 

83.什么是阻塞队列?阻塞队列的实现原理是什么?

阻塞队列(BlokingQueue)是一个支持附加两个操作的队列

image-20220409170142514

队列是一种特殊的线性表,特殊之处在于它只允许在表的前端(front)进行删除操作,而在表的后端进行插入。当队列满了,进行put时会

发生阻塞,当队列为空时进行take时,也会发生阻塞。它是多线程安全的,同时提供了一些阻塞的方法。

 

84.什么是不可变对象,它对写并发应用有什么帮助?

不可变对象即Inmutable Object ,该对象一旦被创建,它的状态(对象的数据,也即对象属性值)就不能改变,反之为可变对象,Mutable Object。

java平台库中包含了许多不可变类,如String,基本包装类,BigInteger,BigDecimal等。

不可变对象天生就是线程安全的,它们的常量域是在构造函数中创建的,既然它们无法修改,这些常量就无法改变。

不可变对象永远是线程安全的

只有满足两个条件才能叫不可变对象:

它的状态不能在创建后进行修改

所有域都是final类型,并且它被正确创建(创建期间没有发生this引用的逸出)

 

85.生产者和消费者模型的作用是什么?

1.通过平衡生产者的生产能力和消费者的消费能力来提升整个系统的运行效率,这是生产者消费者模型最重要的作用。

2.解耦。这是附带的作用,解耦意为着生产者和消费者之间的联系少,联系越少制约就越少

 

86.CopyOnWriteArrayList 可以用于什么应用场景?

CopyOnwriteArrayList 是 java.util.concurrent 包下提供的方法,它实现了读操作无锁,写操作则通过操作底层数组的新副本来实现,是一种读写分离的并发策略。(写实复制容器,guc下提供的一个方法)

CopyOnWrite并发容器用于绝大部分访问都是读,且只是偶尔写的并发场景,比如白名单,黑名单,商品类目的访问和更新场景。

透露的思想:

读写分离,读和写分开

最终一致性

使用另外开辟空间的思路,来解决并发冲突

 

87.用java写一个单例类?

单例:限制类的实例化,让他只能实例化一个对象

饿汉式:

public class Singleton {
   private static Singleton instance = new Singleton();
   public static Singleton getInstance() {
       return instance;
  }
}

懒汉式:

public class Singleton{
   private static Singleton instance = null;
   public static sychronized Singleton getInstance (){
       if (instance==null)  instance = new Singleton();
       return instance;
  }
}

 

88.单例的双重检查锁定(DCL)double check lock的单例是什么?

public class NObject{
   private volatile static NObject object;
   private NObject(){
       
  }
   //获取单例的方法
   public static NObject getObject(){
       if (object == null) {//第一次检查
           synchronized (NObject.class) {//加锁
               if (object==null) {//第二次检查
                   object = new NObject();
              }
          }
      }
       return object;
  }
}

 

89.请概述一下AQS?

image-20220410081955352

image-20220410082247496

 

90.为什么wait,notify和notifyAll这些方法不在Thread类里面?

Java提供的锁是对象级的,每个对象都有锁,通过线程获得。如果线程需要等待某些锁那么调用对象的wait()方法就有意义了。如果wait()方法定义在Thread类中,线程正在等待的是哪个锁就不明显了。简单来说,由于wait,notyfy,notyfyAll都是锁级别的操作,所以把他们定义在Object类中因为锁属于对象。

 

91.分布式服务接口的幂等性如何设计?

所谓幂等性,就是说一个接口,多次发起同一个请求,你这个接口得保证结果是准确的。不如不能多扣款,不能多插入一条数据,也不能将统计值多加了一,这就是幂等性。

如何确保幂等性?

对于每个请求必须有一个唯一的标识,举个例子:订单支付请求,肯定得包括订单id,一个订单id最多支付一次。

每次处理完请求后,必须有一个记录标识这个请求处理过了,比如说常见的方案是在mysql中记录一条支付流水去重表信息,比如支付之前记录一条这个订单的支付流水,而且支付流水去重表采用order id作为唯一键(unique key)。只有成功插入这个支付流水去重表,才可以执行实际的支付扣款。

相关的代码:

image-20220410085256615

 

92.说说你们的分布式session方案是啥?怎么做的?

image-20220410085722974

image-20220410085753322

image-20220410085815574

image-20220410090716888

image-20220410090833949

image-20220410090849992

image-20220410090906545

 

93.分布式事务了解吗?

image-20220412182821750

image-20220412182854888

 

 

94.讲一讲ZAB协议?

image-20220412183127610

 

95.Zookeeper 和 Redis 的区别,各自有什么优缺点?

image-20220412183458943

 

96.Zookeeper节点宕机该如何处理?

image-20220412183720896

 

97.Zookeeper中的四种类型的数据节点?

1.持久节点

除非手动删除,否则一直挂在Zookeeper上

2.临时节点

临时节点的生命周期与客户端会话绑定,一旦客户端会话失效(客户端与zookeeper连接断开不一定会话失效),那么这个客户端创建的

所有临时节点都会被移除。

3.持久顺序节点

基本特性同持久节点,只是增加了顺序属性,节点后面会追加一个由父节点维护的自增整型数字。

4.临时顺序节点

基本特性同临时节点,增加了顺序属性,节点后会增加一个由父节点维护的自增整型数字。

 

98.Dubbo的核心功能有哪些?

image-20220412184911158

image-20220412185128335

 

99.Dubbo 和 Spring Cloud 有什么区别?

Dubbo 的底层是基于使用 Netty 这样的 NIO 框架,是基于TCP 协议传输的,配合以 Hession 序列化完成 RPC 通信。

Spring Cloud 是基于 Http 协议 Rest 接口调用远程的通信,相对来说 Http 请求会有更大的报文,占的带宽会更多。

但是REST 相比 RPC 更为灵活,服务提供方和调用方的依赖只依赖一纸契约,不存在代码级别的强依赖,这在强调

快速演化的微服务环境下,显得更为合适,至于注重通信速度还是方便灵活性,具体情况具体考虑。

 

100.Dubbo 支持哪些协议?每组协议的应用场景,以及优缺点?

image-20220412192856503

 

101.Dubbo 集群提供了哪些负载均衡策略?

image-20220412193230832

102.Dubbo 有哪些注册中心?

image-20220412193335575

 

 

 

 

 

java基础

面向对象

封装:在于明确标识出允许外部使用的所有成员函数和数据项。

内部细节对外部调用透明,外部无需修改或者关心内部实现

1.javabean的属性设为私有

2.orm框架,object relational mapping

继承:继承基类的方法,并作出自己的改变或拓展

子类共性的方法直接使用父类的,而不需要自己再定义,只需拓展自己个性化的

多态:基于对象所属类的不同,外部对同一个方法的调用,实际执行的逻辑不同。

 

为什么局部内部类和匿名内部类只能访问局部final变量?

要知道当出现内部类的时候,会产生两个class文件,当外部class进入销毁期,可能内部类还会存在,这样导致局部变量在外部

类中销毁(垃圾回收),让内部类使用一个不存在的变量而出错。为防止出错,java虚拟机会copy一个给内部类使用,但是为了copy正确,就需要禁止去改变这个局部变量。

 

String ,StringBuffer,StringBuilder

image-20220412215533949

 

重载和重写的区别?

image-20220412220909030

 

接口和抽象类的区别:

初级程序员

1.抽象类可以有普通方法,接口必须是抽象方法

2.抽象类只能继承一个,接口可以实现多个

3.抽象类的成员变量没有限制,抽象类必须是public static final

中高级程序员

image-20220413160204104

 

list 和 set 的区别?

list有序,按对象进入顺序保存对象,可重复,允许多个null元素对象,可以使用iterator取出所有元素进行遍历,也可以使用get(index)来访问元素。

set无序,不可以重复,最多允许一个null值,只能使用iterator进行遍历

 

HashCode 和 equals?

image-20220413174507440

image-20220413174702174

image-20220413174813742

 

ArrayList 和 LinkedList 的区别?

 

线程安全的集合

HashMap –> CurrentHashMap

ArrayList –> CopyOnWriteArrayList

LikedList –> CurrentLinkedQueue

数据共享 –> BlokingQueue

跳表->CurrentSkipListMap

 

 

sql

使用mysql,oracle,sql server的分页查询?

假设分页参数pageNum标识第几页,rows表示每页条数,表名为student

mysql:

select

*

from

student

limit

(pageNum – 1) * rows,rows

 

oracle:

select

*

from

(

select s.*,ROWNUM rn

from

student s

)

where rn between (pageNum – 1) * rows and rows*pageNum

 

sqlServer:

top

 

网络

Http:

hyper text transfer protocol,是一个双向协议,运行在tcp上。

 

 

SOLID 原则:(设计模式六大原则)

single response principle

open closed principle

里氏替换原则

迪米特法则

接口依赖原则

依赖倒置原则

 

接口是什么?为什么要使用接口,而不是直接使用具体类?

除了单例,你还使用过哪些设计模式?

依赖注入,工厂模式,装饰模式或者观察者,动态代理,静态代理

里氏替换原则

父类可以替换子类,子类不能直接被父类替换

反迪米特法则?

“只和朋友说话,不要陌生人说话

适配器模式是什么?

适配器模式提供对接口的转换。如果你的客户端使用某些接口,但是你有另外一 些接口,你就可以写一个适配去来连接这些接口。

什么是“依赖注入”和“控制反转”?为什么有人使用?

控制反转(IOC)是 Spring 框架的核心思想,用我自己的话说,就是你要做一件 事,别自己可劲 new 了,你就说你要干啥,然后外包出去就好~ 依赖注入(DI) 在我浅薄的想法中,就是通过接口的引用和构造方法的表达,将 一些事情整好了反过来传给需要用到的地方~

构造器注入和 setter 依赖注入,那种方式更好?

1.强制性的依赖性或者当目标不可变时,使用构造函数注入(应该说尽量都使用构造器来注入

2.可选或多变的依赖使用setter注入(建议可以使用构造器结合setter的方式来注入

3.在大多数的情况下避免field域注入(感觉大多数同学可能会有异议,毕竟这个方式写起来非常简便,但是它的弊端确实远大于这些优点

4.Spring 4.3+ 的同学可以试一试构造器的隐式注入,采用此方式注入后,使得我们的代码更优雅,更独立,减少了对Spring的依赖性。

依赖注入和工厂模式之间有什么不同?