高频面试题

待了解原理
dubble的spi  redis 哨兵机制 服务挂了怎么选举 垃圾回收过程 ,垃圾收集器    云原生  mvcc springboot注解启动原理   maven底层   spring ioc aop原理  服务器优化 mysql优化  mq原理  springcloud   redis  
锁  序列化  设计模式  注解得使用  


redis哨兵模式(重点): 也是一种主从模式,哨兵定时去查询主机,如果主机太长时间没有相应,多个哨兵就投票选出新的主机。提高了可用性,但是在选举新的主节点期间,还是不能工作。
哨兵方案中由哨兵来选举出新的主机


Redis Cluster 中,当slave(从机)发现自己的master(主机)变为FAIL状态时,便尝试进行选举,以期成为新的master。其过程如下:
slave广播竞选信息
其它master收到信息,回应ack,每个主节点每轮选举只回应一次ack
slave收集master返回的ack
slave收到超过半数master的ack后变成新master
slave广播pong消息通知其他集群节点竞选成功。

HashMap  初始容量是16,负载因子0.75    (HashMap默认初始容量是16。HashMap 的容量必须是2的N次方,HashMap 会根据我们传入的容量计算一个大于等于该容量的最小的2的N次方,例如传 9,容量为16。)
HashMap 的默认初始容量为 16,Hashtable 为 11。
StringBuild  16
ArrayList 初始容量为0,默认最小容量是10
Vector通过synchronized实现了线程安全。初始容量为10    
HashMap是基于哈希表的对Map接口的实现,而哈希表的底层数据结构是数组和链表
HashMap内部是通过数组+链表的形式存储数据,1.8当同一个索引位置的节点链表长度大于8时会进化为红黑树,小于6时会退化为链表。
HashMap 1.7和1.8的实现有什么不同:

【解答】 (1) 存储结构不同,1.7是数组+链表,1.8是数组+链表+红黑树;
(2) 扩容转移数据的方式不同,1.7采用头插法,1.8是尾插法,而且达到转化红黑树的阈值要转化为红黑树;
(3) 扩容计算元素存储位置的方式不同,1.7是直接用hash&(newCap-1)计算,1.8是通过hash&oldCap==0来判断,1.7是一个一个键值对移动,1.8是先排列成两个链表然后直接把链表转移过去;
(4) 扩容和增加键值对顺序不同,1.7是先扩容后增加键值对,1.8是先增加键值对后扩容。
ConcurrentHashMap使用分段锁,也能保证线程安全,比HashTable效率更高
ConcurrentHashMap实现了线程安全。Java1.7通过分段锁来同时兼顾处理效率,默认并行度为16,即允许16个线程并发读写。
线程同步(线程安全),底层是哈希表。
ConcurrentHashMap本质上是一个HashMap,因此功能和HashMap是一样的,但是ConcurrentHashMap在HashMap的基础上提供了并发安全的一个实现。并发安全的主要实现主要通过对于Node节点去加锁,来保证数据更新的安全性。


其内部结构也是数组+链表,jdk1.8也有变成红黑树的操作。内部有一个分段锁数组,每一个分段锁对应一部分数据,
这样需要读取时只会锁住这一部分数据,而不会影响其他数据的读写。
Set  元素存放方式为散列存放

【解答】为什么要改成“数组+链表+红黑树”?    

主要是为了提升在 hash 冲突严重时(链表过长)的查找性能,使用链表的查找性能是 O(n),而使用红黑树是 O(logn)。
java创建一个对象的4种方式?

【解答】 (1) new (2) 反射 (3) 反序列化 (4) clone
sleep占着cpu休眠,wait

【解答】编写多线程程序有几种实现方式?
通常来说,可以认为有三种方式:1)继承 Thread 类;2)实现 Runnable 接口;3)实现 Callable 接口。

其中,Thread 其实也是实现了 Runable 接口。Runnable 和 Callable 的主要区别在于是否有返回值。

【解答】HashMap 和Hashtable 的区别?
HashMap 允许 key 和 value 为 null,Hashtable 不允许。

HashMap 的默认初始容量为 16,Hashtable 为 11。;00

HashMap 的扩容为原来的 2 倍,Hashtable 的扩容为原来的 2 倍加 1。

HashMap 是非线程安全的,Hashtable是线程安全的。

HashMap 的 hash 值重新计算过,Hashtable 直接使用 hashCode。

HashMap 去掉了 Hashtable 中的 contains 方法。

HashMap 继承自 AbstractMap 类,Hashtable 继承自 Dictionary 类。

为什么HashMap的初始容量和扩容都是2的次幂
为了减少哈希冲突。
因为计算元素存储的下标是(n-1)&哈希值,数组初始容量-1,得到的二进制都是1,这样可以减少哈希冲突,可以更好的均匀插入。
原理:
因为判断储存位置的下标为 : i = (n - 1) & hash,n就是数组的长度。
2的次幂 - 1,其二进制都是1,比如 2^4 -1= 15(1111),2^5-1 = 31(11111)。
因为 n-1 和 hash 进行与运算,只有 1 & 1 ,才为1。
因为 n-1永远是2的次幂-1,(n - 1) & hash的结果就是 hash的低位的值。

HashMap的hash()算法(面试)
h = key.hashCode() ^ (h >>> 16)意思是先获得key的哈希值h,然后 h 和 h右移十六位 做异或运算,运算结果再和 数组长度 - 1 进行 与 运算,计算出储存下标的位置


JDK(Java Development Kit)是针对Java开发员的产品,是整个Java的核⼼,包括了Java运⾏环境JRE、Java⼯具和Java基础类库。
Java Runtime Environment(JRE)是运⾏JAVA程序所必须的环境的集合,包含JVM标准实现及Java核⼼类库。
JVM是Java Virtual Machine(Java虚拟机)的缩写,是整个java实现跨平台的最核⼼的部分,能够运⾏以Java语⾔写作的软件程序。
简单来说就是JDK是Java的开发⼯具,JRE是Java程序运⾏所需的环境,JVM是Java虚拟机.它们之间的关系是JDK包含JRE和
JVM,JRE包含JVM

switch语句
1.表达式必须是int、byte、char、short、enmu、String类型
2、constN必须是常量或者finall变量,不能是范围
3、所有的case语句的值不能相同,否则编译会报错
4、default可要可不要
5、break用来执行完一个分支后使程序跳出switch语句块,否则会一直会执行下去。
      
在通过valueOf方法创建Integer对象的时候,如果数值在[-128,127]之间,便返
回指向IntegerCache.cache中已经存在的对象的引用;否则创建一个新的Integer对象。(只针对int,因为在某个范围内的整型数值的个数是有限的,而浮点数却不是)

接口只可以继承,且只能继承接口,可多继承
同时继承和实现的时候,先写继承再写实现

Java 静态变量和成员变量的区别。
成员变量存在于堆内存中。静态变量存在于方法区中。

成员变量与对象共存亡,随着对象创建而存在,随着对象被回收而释放。静态变量与类共存亡,随着类的加载而存在,随着类的消失而消失。

成员变量所属于对象,所以也称为实例变量。静态变量所属于类,所以也称为类变量。

成员变量只能被对象所调用 。静态变量可以被对象调用,也可以被类名调用。

String             长度不可变

StringBuffer   长度可变   线程安全        速度慢

StringBuilder  长度可变   线程不安全   速度快

final修饰的属性:全局变量:声明是必须初始化。局部变量:声明的时候可以不初始化。但都只能赋值一次


switch 是否能作⽤在 byte 上,是否能作⽤在 long 上,是否能作⽤在 String 上*
switch可以作⽤于char,byte,short,int及它们对应的包装类型,switch不可作⽤于long,double,float,boolean及他们的包装类型。在 JDK1.5之
后可以作⽤于枚举类型,在JDK1.7之后可作⽤于String类型。
finalize:Object 中的方法,在垃圾收集器将对象从内存中清除出去之前做必要的清理工作。finalize()方法仅作为了解即可,
在 Java 9 中该方法已经被标记为废弃,并添加新的 java.lang.ref.Cleaner,提供了更灵活和有效的方法来释放资源。这也侧面说明了,
这个方法的设计是失败的,因此更加不能去使用它。

Map(初始容量16,加载因子0.75)

        |--Hashtable:底层是哈希表数据结构,不可以存入null键null值。线程安全,该集合是线程同步的。JDK1.0,效率低。(语法没错,运行时错误)

        |--HashMap:底层是哈希表数据结构。允许使用null键null值,该集合是不同步的。JDK1.2,效率高。(语法和运行时都没错)  HashMap的默认长度为16,是为了降低hash碰撞的几率

        |--TreeMap:底层是二叉树数据结构。线程不同步。非线程安全,可以用于给Map集合中的键进行排序。 
        
         字节流                       字符流

输入流      InputStream  超类,抽象类         Reader 超类,抽象类

输出流      OutputStream 超类,抽象类       Write  超类,抽象类
ipv4:32位

ipv6:128位


重载和重写的区别?
重载: 发生在同一个类中,方法名必须相同,实质表现就是多个具有不同的参数个数或者类型的同名函数(返回值类型可随意,不能以返回类型作为重载函数的区分标准),返回值类型、访问修饰符可以不同,发生在编译时。  

重写: 发生在父子类中,方法名、参数列表必须相同,是父类与子类之间的多态性,实质是对父类的函数进行重新定义。返回值范围小于等于父类,抛出的异常范围小于等于父类,访问修饰符范围大于等于父类;如果父类方法访问修饰符为 private 则子类就不能重写该方法。


进程和线程的区别:

    进程是应用程序,线程是一条执行路径

    进程有独立的内存空间,崩溃不会影响其他程序,

    线程没有独立的空间,多个线程在同一个进程的空间,可能会影响其他线程

    一个进程中,至少有一个线程

多线程:run和start的区别

run没有开辟新的栈空间,没有新线程,都是主线程在执行

start开辟了新的栈空间,在新的栈空间启动run()方法、

反射的优点

    1、提高了java程序的灵活性和扩展性,降低了耦合性,提高了自适应的能力

    2、允许程序创建和控制任何类的对象,无需提前编码目标类

反射的缺点

    1、性能问题

    2、代码维护问题    

请求方式:

    get:

        1、可以缓存

        2、请求保留在浏览器的历史中

        3、可以收藏为书签

        4、处理敏感数据时不能用

        5、数据的长度有限制

        6、数据在URL中对所有人可见

        7、数据类型必须使用ASCII编码。

        8、安全性差

    post:

        1、不可以缓存

        2、请求不保留在浏览器的历史中

        3、不可以收藏为书签

        4、数据的长度无限制

        5、数据在URL中不可见

        6、数据类型无限制

        7、安全在好

说一下 session 的工作原理?
session 的工作原理是客户端登录完成之后,服务器会创建对应的 session,session 创建完之后,会把 session 的 id 发送给客户端,
客户端再存储到浏览器中。这样客户端每次访问服务器时,都会带着 sessionid,服务器拿到 sessionid 之后,在内存找到与之对应的
 session 这样就可以正常工作了。


在 Java 8 中,String 内部使用 char 数组存储数据。

在 Java 9 之后,String 类的实现改用 byte 数组存储字符串,同时使用 coder 来标识使用了哪种编码。

抽象类:用abstract修饰,抽象类不能创建实例对象。抽象方法必须在子类中实现,不能有抽象构造方法或者抽象静态方法。

接口:抽象类的一种特例,接口中的方法必须是抽象的。


两者的区别:

抽象类只能单继承,接口可以多实现。

抽象类可以有构造方法,接口中不能有构造方法。

抽象类中可以有成员变量,接口中没有成员变量,只能有常量(默认就是 public static final)

抽象类中可以包含非抽象的方法,在 Java 7 之前接口中的所有方法都是抽象的,在 Java 8 之后,接口支持非抽象方法:default 方法、静态方法等。
Java 9 支持私有方法、私有静态方法。


Socket和HTTP区别?
socket则是对TCP/IP协议的封装和应用(程序员层面上), Socket本身并不是协议,而是一个调用接口(API)。也可以说,TPC/IP协议是传输层协议,主要解决数据如何在网络中传输,而HTTP是应用层协议,主要解决如何包装数据。

总结:调用start方法方可启动线程,而run方法只是thread的一个普通方法调用,还是在主线程里执行。

在Intellij IDEA中默认所有 scope 为 provided 的依赖不会被加入到 classpath;

高版本的JDK中不包含javax.xml.bind包

compile
默认就是compile,什么都不配置也就是意味着compile。compile表示被依赖项目需要参与当前项目的编译,当然后续的测试,运行周期也参与其中,是一个比较强的依赖。打包的时候通常需要包含进去。

test
scope为test表示依赖项目仅仅参与测试相关的工作,包括测试代码的编译,执行。比较典型的如junit。

runntime
runntime表示被依赖项目无需参与项目的编译,不过后期的测试和运行周期需要其参与。与compile相比,跳过编译而已,说实话在终端的项目(非开源,企业内部系统)中,和compile区别不是很大。比较常见的如JSR×××的实现,对应的API jar是compile的,具体实现是runtime的,compile只需要知道接口就足够了。Oracle jdbc驱动架包就是一个很好的例子,一般scope为runntime。另外runntime的依赖通常和optional搭配使用,optional为true。我可以用A实现,也可以用B实现。

provided
provided意味着打包的时候可以不用包进去,别的设施(Web Container)会提供。事实上该依赖理论上可以参与编译,测试,运行等周期。相当于compile,但是在打包阶段做了exclude的动作。

system
从参与度来说,也provided相同,不过被依赖项不会从maven仓库抓,而是从本地文件系统拿,一定需要配合systemPath属性使用。

拦截器和过滤器区别:
拦截器是基于java的反射机制的,而过滤器是基于函数回调
拦截器不依赖于servlet容器,过滤器依赖与servlet容器
Filter 不能够使用 Spring 容器资源,拦截器是一个Spring的组件,归Spring管理,配置在Spring文件中,因此能使用Spring里的任何资源
Filter 定义在 web.xml 中,在action的生命周期中,拦截器可以多次被调用,而过滤器只能在容器初始化时被调用一次

SpringBootServletInitializer可以使用外部得Servlet容器,使用步骤:
1、必须创建war项目,创建好war项目得目录结构
2、嵌入式Tomcat依赖scope指定为provided
3、编写SpringBootServletInitializer类子类并重写configure()方法
4、启动服务器

@SpringBootApplication作用:
    主要包含:
    @Configuration(配置类,可加可不加)   
    @EnableAutoConfiguration(自动开启配置,必须加上,否则启动失败)
    @ComponentScan(必须加,表示扫描该类以下得包得所有注解,不加的话@Controller等失效)

@Import可以添加在@SpringBootApplication(启动类)、@Configuration(配置类)、@Component(组件类)对应的类上。
@Import引入ImportBeanDefinitionRegistrar的实现类。一般用来动态注册bean。最重要的一点是还可以对这些BeanDefinition进行额外的修改或增强。
凡是被spring管理的类,实现接口 EnvironmentAware 重写方法 setEnvironment 可以在工程启动时,获取到系统环境变量和application配置文件中的变量。
Spring的多数据源支持---AbstractRoutingDataSource,AbstractRoutingDataSource定义了抽象的determineCurrentLookupKey方法,子类实现此方法,来确定要使用的数据源
@EnableTransactionManagement表示开启事务支持,在springboot项目中一般配置在启动类上,效果等同于xml配置的<tx:annotation-driven />。开启事务支持后,然后在访问数据库的Service方法上添加注解 @Transactional 便可。
Mybatis中的mapper动态代理是不支持方法重载的Dao接口里的方法,因为是全类名+方法名的保存和寻找策略。


vue

@事件名称是v-on:事件名称的简写方式

REST(表现层状态转移):是一组架构约束条件和原则(网上找到一个比较通俗的说法是:URL定位资源,用HTTP动词(GET,POST,DELETE,PUSH等)描述操作)
基于REST构建的API就是Restful风格
@RestController = @Controller + ResponseBody   注解的合并


OSI七层模型的体系结构:(自下向上:物理层,数据链路层,网络层,传输层,会话层,表现层,应用层)
五层协议的体系结构:(物理层,数据链路层,网络层,运输层,应用层)
TCP/IP的体系结构:(数据链路层,网络层,传输层(TCP/UDP),应用层)

sql部分:
日志系统主要有redo log(重做日志)和binlog(归档日志)。redo log是InnoDB存储引擎层的日志,binlog是MySQL Server层记录的日志, 
两者都是记录了某些操作的日志(不是所有)自然有些重复(但两者记录的格式不同)。


char 固定长度,所以在处理速度上要比varchar快速很多,但是对费存储空间,所以对存储不大,但在速度上有要求的可以使用char类型。

数据库默认隔离级别是可重复读,最常用得是读已提交

【三范式】
1、原子性
2、所有非主键必须完全依赖于主键
3、所有非主键只依赖主键,不能出现依赖传递

一个表可尽量少用索引,索引虽然可以提高查询的效率,但是可以降低insert,update,delete的效率,因为在执行这些操作的时候会重建索引,一个表的
索引数量最好不超过6个。

sql优化:
1、少用in,连续值尽量用between in ;或者用连接
2、select * 会增加很多不必要的消耗(cpu,io,内存,网络带宽)
3、当只需要一条数据得时候使用limit 1
    为了使EXPLAIN中的type列达到const类型(const:表示通过索引一次就找到了)
4、如果排序字段没有用到索引,就尽量少排序
5、如果限制条件中其他字段没有索引,尽量少用or
    or两边如果有不是索引的,会造成查询不走索引(可用union代替)
6、尽量用union all代替union
    union:对两个结果集进行并集操作,不包括重复行,相当于distinct,同时进行默认规则的排序;
    union all:对两个结果集进行并集操作,包括重复行,即所有的结果全部显示,不管是不是重复。
7、不建议使用%作为模糊匹配的前缀,否则会导致索引失效,可以使用%当作后缀。
8、避免在where子句添加表达式操作
  例如where age * 2 = 36 ,应改为age = 36/2
9、避免隐式类型转换
10、对于联合查询来说,范围查询会使索引失效(between,>,<等)
11、尽量使用数字型字段,因为字符型会 降低查询和连接的效率。
12、尽量使用别名

导致索引失效的:
1、!=,<>
2、or
3、in和notin
4、使用%作为模糊匹配的前缀

关键词用法:
group by: 分组
distinct;去重
limit:限制结果数量
having:对where筛选出来的结果进行再次过滤
union:对两个结果集进行并集操作,不包括重复行,相当于distinct,同时进行默认规则的排序;
union all:对两个结果集进行并集操作,包括重复行,即所有的结果全部显示,不管是不是重复。
TRUNCATE:清空表

SpringMVC执行流程和原理 SpringMVC流程:
1、用户发送出请求到前端控制器DispatcherServlet。
2、DispatcherServlet收到请求调用HandlerMapping(处理器映射器)。
3、HandlerMapping找到具体的处理器(可查找xml配置或注解配置),生成处理器对象及处理器拦截器
(如果有),再一起返回给DispatcherServlet。
4、DispatcherServlet调用HandlerAdapter(处理器适配器)。
5、HandlerAdapter经过适配调用具体的处理器(Handler/Controller)。
6、Controller执行完成返回ModelAndView对象。
7、HandlerAdapter将Controller执行结果ModelAndView返回给DispatcherServlet。
8、DispatcherServlet将ModelAndView传给ViewReslover(视图解析器)。
9、ViewReslover解析后返回具体View(视图)。
10、DispatcherServlet根据View进行渲染视图(即将模型数据填充至视图中)。
11、DispatcherServlet响应用户。

Spring中AOP底层的实现其实是基于JDK的动态代理和cglib动态创建类进行动态代理来实现的:
默认的策略是如果目标类是接口,则使用JDK动态代理技术,否则使用Cglib来生成代理。

@Autowire和@Resource区别
对比项           @Autowire                   @Resource
注解来源         Spring注解                  JDK注解(JSR-250标准注解,属于J2EE)
装配方式         优先按类型                  优先按名称
属性             required                    name、type
作用范围         字段、setter方法、构造器    字段、setter方法

Spring事务的种类:
spring支持编程式事务管理和声明式事务管理两种方式:
①编程式事务管理使用TransactionTemplate。
②声明式事务管理建立在AOP之上的。其本质是通过AOP功能,对方法前后进行拦截,将事务处理的功
能编织到拦截的方法中,也就是在目标方法开始之前加入一个事务,在执行完目标方法之后根据执行情
况提交或者回滚事务。
声明式事务最大的优点就是不需要在业务逻辑代码中掺杂事务管理的代码,只需在配置文件中做相关的
事务规则声明或通过@Transactional注解的方式,便可以将事务规则应用到业务逻辑中。
声明式事务管理要优于编程式事务管理,这正是spring倡导的非侵入式的开发方式,使业务代码不受污
染,只要加上注解就可以获得完全的事务支持。唯一不足地方是,最细粒度只能作用到方法级别,无法
做到像编程式事务那样可以作用到代码块级别。

Spring中Bean的作用域有哪些?
singleton作用域
在默认情况下,spring的ApplicationContext容器在启动时,自动实例化所有singleton的Bean并缓存于容
器中.虽然启动时会花费一些时间,但带来两个好处:首先对Bean提前的实例化操作会及早发现一些潜在的
配置问题.其次Bean以缓存的方式保存,当运行时使用到该Bean时就无须再实例化了,加快了运行效率.如
果用户不希望在容器启动时提前实例化singleton的Bean,可以通过lazy-init属性进行控制.
prototype
在默认情况下,spring容器在启动时不实例化prototype的Bean.此外,spring容器将prototype的Bean交给
调用者后,就不再管理它的生命周期.
request作用域
每次HTTP请求都会创建一个新的Bean,HTTP请求处理完毕后,销毁这个Bean.该作用域仅适用于
webApplicationContext环境.
session作用域
同一个HTTP session共享一个Bean,不同HTTP session使用不同的Bean,当HTTP Session结束后,实例才
被销毁.该作用域仅适用于webApplicationContext环境
globalSession作用域
同一个全局session共享一个Bean,一般用于portlet应用环境,该作用域仅适用于webApplicationContext
环境.


#{}和${}的区别是什么?
#{} 是预编译处理
${} 是字符串替换。
Mybatis在处理#{}时,会将sql中的#{}替换为?号,调用PreparedStatement的set方法来赋值;
Mybatis在处理${}时,就是把${}替换成变量的值。
使用#{}可以有效的防止SQL注入,提高系统安全性。

#{ }可以防止Sql 注入,它会将所有传入的参数作为一个字符串来处理。
$ {} 则将传入的参数拼接到Sql上去执行,一般用于表名和字段名参数,$ 所对应的参数应该由服务器端提供,前端可以用参数进行选择,避免 Sql 注入的风险
sql中 ${tableName} 替换成了 tb_class ,#{id} 也已经变成了 占位符 ?

索引的原理:
MySQL数据库索引采用的是B+Tree结构

B+Tree结构:
非叶子节点不存储data数据,只存储索引值,这样便于存储更多的索引值
叶子节点包含了所有的索引值和data数据
叶子节点用指针连接,提高区间的访问性能
相比B树,B+树进行范围查找时,只需要查找定位两个节点的索引值,然后利用叶子节点的指针进行遍历即可。而B树需要遍历范围内所有的节点和数据,显然B+Tree效率高。

通常一个Xml映射文件,都会写一个Dao接口与之对应,请问,这个Dao接口的工作原理是什么?Dao接口里的方法,参数不同时,方法能重载吗?
Dao 接口里的方法可以重载,但是Mybatis的XML里面的ID不允许重复。
所以用的时候不可以重载,因为是全限名+方法名的保存和寻找策略。


Springboot 有哪些优点?
减少开发,测试时间和努力。
使用JavaConfig有助于避免使用XML。
避免大量的Maven导入和各种版本冲突。
提供意见发展方法。
通过提供默认值快速开始开发。
没有单独的Web服务器需要。这意味着你不再需要启动Tomcat,Glassfish或其他任何东西。
需要更少的配置 因为没有web.xml文件。只需添加用@ Configuration注释的类,然后添加用
@Bean注释的方法,Spring将自动加载对象并像以前一样对其进行管理。您甚至可以将
@Autowired添加到bean方法中,以使Spring自动装入需要的依赖关系中。
基于环境的配置 使用这些属性,您可以将您正在使用的环境传递到应用程序:-
Dspring.profiles.active = {enviornment}。在加载主应用程序属性文件后,Spring将在
(application{environment} .properties)中加载后续的应用程序属性文件。


Redis最大缓存可达512M。


分代回收器有两个分区:老生代和新生代,新生代默认的空间占比总空间的 1/3,老生代的默认占比是 2/3。
新生代使用的是复制算法,新生代里有 3 个分区:Eden、To Survivor、From Survivor,它们的默认占比是 8:1:1,
208.常用的 JVM 调优的参数都有哪些?
-Xms2g:初始化推大小为 2g;
-Xmx2g:堆最大内存为 2g;
-XX:NewRatio=4:设置年轻的和老年代的内存比例为 1:4;
-XX:SurvivorRatio=8:设置新生代 Eden 和 Survivor 比例为 8:2;
–XX:+UseParNewGC:指定使用 ParNew + Serial Old 垃圾回收器组合;
-XX:+UseParallelOldGC:指定使用 ParNew + ParNew Old 垃圾回收器组合;
-XX:+UseConcMarkSweepGC:指定使用 CMS + Serial Old 垃圾回收器组合;
-XX:+PrintGC:开启打印 gc 信息;
-XX:+PrintGCDetails:打印 gc 详细信息。

wait() 和 sleep() 方法的区别
来源不同:sleep() 来自 Thread 类,wait() 来自 Object 类。
对于同步锁的影响不同:sleep() 不会该表同步锁的行为,如果当前线程持有同步锁,那么 sleep 是不会让线程释放同步锁的。wait() 会释放同步锁,让其他线程进入 synchronized 代码块执行。
使用范围不同:sleep() 可以在任何地方使用。wait() 只能在同步控制方法或者同步控制块里面使用,否则会抛 IllegalMonitorStateException。
恢复方式不同:两者会暂停当前线程,但是在恢复上不太一样。sleep() 在时间到了之后会重新恢复;wait() 则需要其他线程调用同一对象的 notify()/nofityAll() 才能重新恢复。

如何检测死锁?
死锁的四个必要条件:
互斥条件:进程对所分配到的资源进行排他性控制,即在一段时间内某资源仅为一个进程所占有。此时若有其他进程请求该资源,则请求进程只能等待。
请求和保持条件:进程已经获得了至少一个资源,但又对其他资源发出请求,而该资源已被其他进程占有,此时该进程的请求被阻塞,但又对自己获得的资源保持不放。
不可剥夺条件:进程已获得的资源在未使用完毕之前,不可被其他进程强行剥夺,只能由自己释放。
环路等待条件:存在一种进程资源的循环等待链,链中每一个进程已获得的资源同时被 链中下一个进程所请求。即存在一个处于等待状态的进程集合{Pl, P2, …, pn},其中 Pi 等待的资源被 P(i+1) 占有(i=0, 1, …, n-1),Pn 等待的资源被 P0占 有,如下图所示。


怎么预防死锁?
预防死锁的方式就是打破四个必要条件中的任意一个即可。
打破互斥条件:在系统里取消互斥。若资源不被一个进程独占使用,那么死锁是肯定不会发生的。但一般来说在所列的四个条件中,“互斥”条件是无法破坏的。因此,在死锁预防里主要是破坏其他几个必要条件,而不去涉及破坏“互斥”条件。。
打破请求和保持条件:1)采用资源预先分配策略,即进程运行前申请全部资源,满足则运行,不然就等待。 2)每个进程提出新的资源申请前,必须先释放它先前所占有的资源。
打破不可剥夺条件:当进程占有某些资源后又进一步申请其他资源而无法满足,则该进程必须释放它原来占有的资源。
打破环路等待条件:实现资源有序分配策略,将系统的所有资源统一编号,所有进程只能采用按序号递增的形式申请资源。

死锁的解决
资源剥夺法: 挂起(暂时放到外存上)某些死锁进程,并抢占它的资源,将这样资源分配给其他的死锁进程。但是应该防止被挂起的进程长时间得不到资源而饥饿。
撤销进程法(或终止进程法):强制撤销部分、甚至全部死锁进程,并剥夺这些进程的资源。这种方式的优点是实现简单,但所付出的代价可能会很大。如果有的进程已经运行了很长时间了,被撤销,还得从新执行。
进程回退法: 让一个或多个死锁进程回退到足以避免死锁的地步。这就要求系统要记录进程的历史信息,设置还原点。

4.为什么使用synchronized替换ReentrantLock锁呢?
① 减少内存开销。假设使用可重入锁来获得同步支持,那么每个节点都需要通过继承AQS(队列同步器)来获得同步支持。但并不是每个节点都需要获得同步支持的,只有链表的头节点(红黑树的根节点)需要同步,这无疑带来了巨大内存浪费。
② 获得JVM的支持。可重入锁毕竟是API这个级别的,后续的性能优化空间很小。 synchronized则是JVM直接支持的,JVM能够在运行时作出相应的优化措施:锁粗化、锁消除、锁自旋等等。这就使得synchronized能够随着JDK版本的升级而不改动代码的前提下获得性能上的提升。
③在 JDK1.6 中,对 synchronized 锁的实现引入了大量的优化,并且 synchronized 有多种锁状态,会从无锁 -> 偏向锁 -> 轻量级锁 -> 重量级锁一步步转换。

CAS锁升级
针对 synchronized 获取锁的方式,JVM 使用了锁升级的优化方式:
先使用偏向锁优先同一线程,然后再次获取锁
如果失败,就升级为 CAS 轻量级锁
如果失败就会短暂自旋,防止线程被系统挂起
最后如果以上都失败就升级为重量级锁
锁是一步步升级上去的,最初是通过很多轻量级的方式锁定的。


锁升级方式:就是先使用偏向锁优先同一线程然后再次获取锁,如果失败,就升级为CAS(compare and swap 原子操作) 轻量级锁,如果失败就会短暂自旋(不停的判断比较,看能否将值交换),防止线程被系统挂起。最后如果以上都失败就升级为重量级锁。
无锁:正常执行
偏向锁:一个线程执行同步代码时升级成偏向锁
轻量级锁:两个线程竞争时升级为轻量级锁
重量级锁:多个线程竞争时,自旋10次都失败时,升级为重量级锁
    

偏向锁:减少无竞争且只有一个线程使用锁的情况下,使用轻量级锁产生的性能消耗。轻量级锁每次申请、释放锁都至少需要一次CAS,但偏向锁只有初始化时需要一次CAS。
轻量级锁:当有两个线程,竞争的时候就会升级为轻量级锁。轻量级锁的目标是,减少无实际竞争情况下,使用重量级锁产生的性能消耗,包括系统调用引起的内核态与用户态切换、线程阻塞造成的线程切换等。
重量级锁:大多数情况下,在同一时间点,常常有多个线程竞争同一把锁,悲观锁的方式,竞争失败的线程会不停的在阻塞及被唤醒态之间切换,代价比较大。

MQ问题及解决方案
1.消息重复消费问题:当消息被重复消费时,可能会导致一些严重的问题,例如数据错误或重复处理等。解决方案是使用消息队列中提供的消息去重机制,例如使用消息id或消息唯一标识符来避免重复消费。
2.消息丢失问题:消息丢失是指当消息在传输过程中丢失或因某些原因未能正确发送时的问题。解决方案是使用持久化机制,将消息写入消息队列的磁盘中,以避免消息丢失。
3.消息堆积问题:当消息队列无法及时处理消费者发送的消息时,可能会导致消息堆积。解决方案是使用消费者组、分区等机制,将消息分摊到多个消费者上,从而提高消息的处理能力。
4.消息处理失败问题:当消费者无法正确处理消息时,可能会导致消息处理失败。解决方案是使用重试机制、消息补偿机制等,重新发送或处理消息。
5.消息队列性能问题:当消息队列处理能力不足时,可能会导致消息处理延迟或消息堆积。解决方案是使用水平扩展或垂直扩展等方法,提高消息队列的处理能力。
6.消息队列的安全问题:当消息队列面临攻击或未授权访问时,可能会导致数据泄露或消息被篡改。解决方案是使用身份认证、授权等机制,限制消息队列的访问权限,保护数据的安全性。
7.消息队列的可靠性问题:当消息队列系统出现故障时,可能会导致消息丢失或消息堆积。解决方案是使用高可用架构,如主备模式、集群模式等,保证消息队列系统的可靠性。
8.消息队列的监控问题:当消息队列出现异常时,需要及时发现并进行处理。解决方案是使用监控系统,对消息队列的性能、状态、异常进行实时监控和预警。


在创建索引时,必须考虑在哪些字段上创建索引和创建什么类型的索引,有7大原则:
1.选择唯一性索引
2.为经常需要排序、分组和联合操作的字段建立引索
3.为常作为查询条件的字段建立索引
4.限制索引的数目
5.尽量使用数据量少的索引
6.尽量使用前缀来索引
7.删除不再使用或者很少使用的索引
8. 经常更新修改的字段不要建立索引(针对mysql说,因为字段更改同时索引就要重新建立,排序,而Orcale好像是有这样的机制字段值更改了,它不立刻建立索引,排序索引,而是根据更改个数,时间段去做平衡索引这件事的)
9、不推荐在同一列建多个索引


spring用到了那些设计模式
工厂模式: beanFactory就用到了简单工厂模式。
单例模式: Bean默认为单例模式。
代理模式: AOP用到了JDK的动态代理模式。
模板模式: 减少代码冗余,Jdbc模板等。
观察者模式: 定义对象间的一对多的关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并自动更新。spring监听器的实现就用了观察者模式。

Nacos和Eureka的区别
共同点
①都支持服务的注册和拉取。
②都支持服务提供者以心跳检测来判断是否健康(临时实例)。

不同点
①nacos支持注册中心主动询问服务提供者的状态(非临时实例)。
②nacos支持注册中心消息变更主动推送。
③心跳不正常会被剔除(临时实例)。

Ribbon和nginx的区别
nginx: 反向代理实现负载均衡,相当于从nginx服务器进行请求转发。
Ribbon: 客户端负载均衡,全程都是客户端操作。


说一下什么是Eureka的自我保护机制
如果Eureka服务端在一定时间内没有接收到某个微服务的心跳(默认90s),Eureka服务端会进入自我保护模式,在该模式下Eureka服务端会保护服务注册表中的信息,不在删除注册表中的数据,当网络故障恢复后,Eureka服务端节点会自动退出自我保护模式。

        
        

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值