Java基础
1、Hashcode()和 equals()和==区别?
1、hashcode()方法跟 equals()在 java 中都是判断两个对象是否相等
2、两个对象相同,则 hashcode 值一定要相同,即对象相同 >成员变量相同---->hashcode 值一定相同
3、两个对象的 hashcode 值相同,对象不一定相等。总结:equals 相等则 hashcode 一定相等,hashcode 相等,equals 不一定相等。
4、==比较的是两个引用在内存中指向的是不是同一对象(即同一内存空间)。
2、String 为什么要设计成不可变的?
1、字符串常量池需要 String 不可变。
因为 String 设计成不可变,当创建一个 String 对象时,若此字符串值已经存在于常量池中,则不会创建一个新的对象,而是引用已经存在的对象。如果字符串变量允许必变,会导致各种逻辑错误,如改变一个对象会影响到另一个独立对象。
2、String 对象可以缓存 hashCode。字符串的不可变性保证了 hash 码的唯一性, 因此可以缓存 String 的 hashCode,这样不用每次去重新计算哈希码。在进行字符串比较时,可以直接比较 hashCode,提高了比较性能;
3、安全性。String 被许多 java 类用来当作参数,如 url 地址,文件 path 路径, 反射机制所需的 Strign 参数等,若 String 可变,将会引起各种安全隐患。
3、String / StringBuffer / StringBuilder 区 别
String: String 的值是不可变的,这就导致每次对 String 的操作都会生成新的 String 对象, 不仅效率低下,而且浪费大量优先的内存空间
StringBuffer: StringBuffer 是可变类,线程安全的,任何对它指向的字符串的操作都不会产生新的对象。每个 StringBuffer 对象都有一定的缓冲区容量,当字符串大小没有超过容量时,不会分配新的容量,当字符串大小超过容量时,会自动增加容量
StringBuilder: 可变类,速度更快,线程不安全。
4、ArrayList 和 LinkedList 区别?
ArrayList:底层是数据结构,然后数组查找数据是直接根据下标就能定位,所以查询和修改是非常快的。
Linkedlist:底层是链表结构,链表插入数据是根据尾插法进行插入的,所以进行新增和删除比较快
相同点就是这两个都是不同步的,也就是说都不保证线程安全。
5、HashMap 的底层数据结构是什么?
在 JDK1.7 中和 JDK1.8 中有所区别:
在 JDK1.7 中,由”数组+链表“组成,数组是 HashMap 的主体,链表则是主要为了解决哈希冲突而存在的。
在 JDK1.8 中,有“数组+链表+红黑树”组成。当链表过长,则会严重影响 HashMap 的性能, 红黑树搜索时间复杂度是 O(logn),而链表是 O(n)。因此,JDK1.8 对数据结构做了进一步的优化,引入了红黑树,链表和红黑树在达到一定条件会进行转换:
当链表超过 8 且数组长度(数据总量)超过 64 才会转为红黑树
将链表转换成红黑树前会判断,如果当前数组的长度小于 64,那么会选择先进行数组扩容,而不是转换为红黑树,以减少搜索时间。
6、说一下 HashMap 的特点
1、hashmap 存取是无序的
2、键和值位置都可以是 null,但是键位置只能是一个 null
3、键位置是唯一的,底层的数据结构是控制键的
4、jdk1.8 前数据结构是:链表+数组 jdk1.8 之后是:数组+链表+红黑树
5、阈值(边界值)>8 并且数组长度大于 64,才将链表转换成红黑树,变成红黑树的目的是提高搜索速度,高效查询。
7、解决 hash 冲突的办法有哪些?HashMap 用的哪种?
解决 Hash 冲突方法有:开放定址法、再哈希法、链地址法(HashMap 中常见的拉链法)、简历公共溢出区。HashMap 中采用的是链地址法。
开放定址法也称为再散列法:基本思想就是,如果 p=H(key)出现冲突时,则以 p 为基础,再次 hash,p1=H(p),如果 p1 再次出现冲突,则以 p1 为基础,以此类推,直到找到一个不冲突的哈希地址 pi。因此开放定址法所需要的 hash 表的长度要大于等于所需要存放的元素,而且因为存在再次 hash,所以只能在删除的节点上做标记,而不能真正删除节点
再哈希法(双重散列,多重散列):提供多个不同的 hash 函数,R1=H1(key1)发生冲突时,再计算 R2=H2(key1),直到没有冲突为止。这样做虽然不易产生堆集,但增加了计算的时间。
链地址法(拉链法):将哈希值相同的元素构成一个同义词的单链表,并将单链表的头指针存放在哈希表的第 i 个单元中,查找、插入和删除主要在同义词链表中进行,链表法适用于经常进行插入和删除的情况。
建立公共溢出区:将哈希表分为公共表和溢出表,当溢出发生时,将所有溢出数 据统一放到溢出区。
注意开放定址法和再哈希法的区别是 开放定址法只能使用同一种hash 函数进行再次hash, 再哈希法可以调用多种不同的 hash 函数进行再次 hash。
8、synchronized和lock的区别?
1、synchronized是关键字,Lock是接口;
2、synchronized可以作用于方法上,lock只能作用于方法块;
3、synchronized在发生异常和同步块结束的时候,会自动释放锁。而Lock必须手动释放, 所以如果忘记了释放锁,一样会造成死锁。
9、list,set,map区别?
1、list:有序的,可重复;
1、set:无序,不可重复的集合,重复元素会被覆盖掉;
1、map:键值对,键唯一,值不唯一;
10、aop的实现原理?
主要分为两种方式实现:
JDK动态代理:
原理说明——JDK动态管理通过反射接收被代理的类,该代理的类必须实现接口,核心是InvocationHandler 和 Proxy类
Cglib动态代理:
原理说明——Cglib通过继承方式实现动态代理,若该类是可以在 运行时动态生成某个类(具体我们要使用的类)的子类。
MySQL
1、知道mysql事务的隔离级别吗?
mysql事务:事务就是一次对数据库操作的若干单元的一条或多条sql的管理 ,事务管理的目标就是完整性,要么全部执行,要么全不执行。
1、读未提交(Read Uncommitted)
指所有事务都可以看到其他未提交事务的执行结果。读取未提交事务的结果也数据脏读,所以一般很少用于实践中。
2、读已提交(Read Committed)
指事务只能读取到已经提交的结果,也是大部分数据库的默认隔离级别(mysql不是),这种级别也支持不可重复读(Nonrepeatable Read),因为同一事务的其他实例在该实例处理其间可能会有新的commit,导致两次读取结果不一致。
3、可重读(Repeatable Read)
这个是mysql默认的隔离级别,它确保同一个事务的多个实例在并发读取数据时,会看到相同的数据。不过这样有可能会导致出现幻读(Phantom Read)的情况,及在当前读取到某一范围数据时,另一个事务又在这个范围内插入了新的数据,当用户再去读取的时候就会出现新的数据。解决方法:InnoDB存储引擎通过MVCC(多版本并发控制)解决幻读,具体原理为:每次数据变更的时候都会在MVCC的版本链中记录,select可以去版本链中获取记录,这就实现了读写,写读的并发执行。
4、可串行化(Serializable)
这是最高的隔离级别,它通过强事务排序,使之不可能出现相互冲突,从而解决幻读。也就是说它在每个读的数据上都会加上一个共享锁。在这个级别上可能会导致大量的超时现象和锁竞争。
注:
脏读(Drity Read):某个事务已更新一份数据,另一个事务在此时读取了同一份数据,由于某些原因,前一个RollBack了操作,则后一个事务所读取的数据就会是不正确的。
不可重复读(Non-repeatable read):在一个事务的两次查询之中数据不一致,这可能是两次查询过程中间插入了一个事务更新的原有的数据。
幻读(Phantom Read):在一个事务的两次查询中数据笔数不一致,例如有一个事务查询了几列(Row)数据,而另一个事务却在此时插入了新的几列数据,先前的事务在接下来的查询中,就会发现有几列数据是它先前所没有的。
2、mysql和oracle数据库的区别?
1、本质区别:oracle数据库是收费的,mysql是免费的;
2、安全性:oracle的安全性比mysql高,因为mysql使用三个参数来验证用户(地址,用户名,密码),而oracle则使用了很多安全功能(用户名,密码,配置文件,本地身份验证,外部身份验证,高级安全增强功能等);
3、事务提交:mysql默认是自动提交事务的,而oracle是需要手动提交的;
4、语法:mysql分页是用limit关键字,而oracle是用rownum关键字;
5、内存:与oracle相比,mysql没有表空间,角色管理,快照,同义词和包以及自动存储管理;
3、如何进行数据库优化?
1、在表中创建索引,优先选用where和group by 使用的字段;
2、尽量避免使用selecr*,只返回需要的字段即可,无用的字段只会拖累查询效率;
3、尽量避免使用 not in ,not exists,这样会导致数据库引擎放弃索引进行全表扫描;
4、尽量避免使用or,这样也会导致数据库引擎放弃索引进行全表扫描;
5、避免在字段开头使用模糊搜索;
4、你知道mysql都有哪些索引吗?
1、主键索引(PRIMARY KEY)
主键索引其实也是唯一索引的一种,不允许有控空值。一般在建表的时候同时创建主键索引,一个表只能有一个主键。
2、唯一索引(UNIQUE)
值必须唯一,但允许有空值。如果是用做组合索引,那么组合列必须唯一。
3、普通索引(INDEX)
最基本的索引类型,没有什么限制。
4、组合索引(INDEX)
即一个索引包含多个列,多用于避免回表查询。
5、全文索引(FULLTEXT)
也称为全文检索,是目前搜索引擎使用的一种关键技术。
5、delete与truncate删除表中数据的区别?
1、都可以用作删除表中的数据;
2、delete删除数据后,新入库数据的数据索引会接着之前的,而truncate则会从初识大小开始;
3、delete在执行后会将删除操作事务记录到日志中,这样如果发现有问题可以进行事务回滚,而truncate不可以进行事务回滚;
6、事务的四大特性?
1、原子性
事务内包含的所有操作要么全部执行成功,要么全部失败会滚;实现原理:所有的操作都会写入日志中,当系统崩溃,断电等原因造成事务中部分更新操作完成,部分未执行,则通过回溯日志,将所有操作回滚,使系统保证原子性和一致性;
2、隔离性
多个并发的事务的操作,在同一时间只能有一个事务执行(及串行的执行);
3、一致性
不管任何时间有多少个并发的事务,系统也必须保持一致;
4、持久性
事务处理结束后,对数据的修改就是永久的,即便系统故障也不会丢失;
7、聚集索引与非聚集索引的区别?
区别:
1.聚集索引一个表只能有一个,而非聚集索引一个表可以存在多个
2.聚集索引存储记录是物理上连续存在,而非聚集索引是逻辑上的连续,物理存储并不连续
3.聚集索引:物理存储按照索引排序;聚集索引是一种索引组织形式,索引的键值逻辑顺序决定了表数据行的物理存储顺序。
4.非聚集索引:物理存储不按照索引排序;非聚集索引则就是普通索引了,仅仅只是对数据列创建相应的索引,不影响整个表的物理存储顺序。
5.索引是通过二叉树的数据结构来描述的,我们可以这么理解聚簇索引:索引的叶节点就是数据节点。而非聚簇索引的叶节点仍然是索引节点,只不过有一个指针指向对应的数据块。优势与缺点:
聚集索引插入数据时速度要慢(时间花费在“物理存储的排序”上,也就是首先要找到位置然后插入),查询数据比非聚集数据的速度快。8、MySQL常见的存储引擎InnoDB、MyISAM的区别?
1、事务:MyISAM不支持,InnoDB支持
2、锁级别:MyISAM 表级锁,InnoDB 行级锁及外键约束
3、存储:MyISAM存储表的总行数;InnoDB不存储总行数
4、MyISAM采用非聚集索引,B+树叶子存储指向数据文件的指针。InnoDB主键索引采用聚集索引,B+树叶子存储数据
适用场景:
MyISAM适合:插入不频繁,查询非常频繁,如果执行大量的SELECT,MyISAM是更好的选择, 没有事务
InnoDB适合:可靠性要求比较高,或者要求事务;表更新和查询都相当的频繁, 大量的INSERT或UPDATE
9、数据库悲观锁和乐观锁的原理和应用场景?
悲观锁:先获取锁,再进行业务操作,一般都是用select for updata 语句,对数据加锁,避免其他事务意外修改数据。
当数据库执行
select … for update
时会获取被select中的数据行的行锁,select for update
获取的行锁会在当前事务结束时自动释放,因此必须在事务中使用。乐观锁:先进行业务操作,只在最后实际更新数据时进行检查数据是否被更新过。主要是利用CAS机制,并不会对数据加锁,而是通过对比数据的时间戳或者版本号,来实现乐观锁需要的版本判断。
场景:
乐观锁 适合 读操作多 的场景,相对来说写的操作比较少。它的优点在于 程序实现 , 不存在死锁 问题,不过适用场景也会相对乐观,因为它阻止不了除了程序以外的数据库操作。
悲观锁 适合 写操作多 的场景,因为写的操作具有 排它性 。采用悲观锁的方式,可以在数据库层面阻止其他事务对该数据的操作权限,防止 读 - 写 和 写 - 写 的冲突。
10、索引是什么?MySQL为什么使用B+树,而不是使用其他?B+树的特点?
索引:帮助mysql高效获取数据的数据结构,是排好序的快速查找数据结构!索引会影响where后面的查找,和order by 后面的排序。
数据库索引采用B+树而不是B树的主要原因:B+树只要遍历叶子节点就可以实现整棵树的遍历,而且在数据库中基于范围的查询是非常频繁的,而B树只能中序遍历所有节点,效率太低。
B+树的特点:
1、所有关键字都出现在叶子结点的链表中(稠密索引),且链表中的关键字恰好是有序的;
2、不可能在非叶子结点命中;
3、非叶子结点相当于是叶子结点的索引(稀疏索引),叶子结点相当于是存储(关键字)数据的数据层;
11、什么叫视图?游标是什么?
视图:是一种虚拟的表,通常是有一个表或多个表的行或列的子集,具有和物理表一样的功能;
游标:游标是对查询出来的结果集作为一个单元来有效的处理。一般不使用游标,但是需要逐条处理数据的时候,游标显得十分重要;
12、什么情况下索引会失效?
1、用or的时候,其中一个字段没有索引就会导致索引失效;
2、使用like模糊搜索的时候索引也会失效;
3、数据类型不匹配的时候也会索引失效;
4、查询的列上有运算或者函数的也会失效;
Redis
1、什么是redis?
redis是开源免费的,遵守BSD协议,是一个高性能的key-value非关系型数据库。redis还支持数据的持久化,可以将内存中的数据保存到磁盘中,重启的时候可以再次加载进行使用。同时redis不仅仅支持简单key-value类型数据,同时还提供list、set、zset、hash类型数据结构的存储;
2、redis与其他key-value数据库有什么区别?
1、redis有着更为复杂的数据结构并且提供对他们的原子性操作,这是一个不同于其他数据库的进化路径
2、redis数据是保存在内存中的,所以速度相对来说更快;
3、redis支持事务,它的操作都是原子性的;
3、redis有哪些好处?
1、速度快,因为数据存在内存中,类似于HashMap,HashMap的优势就是查找和操作的时间复杂度都是O1;
2、支持丰富数据类型,支持string,list,set,Zset,hash等;
3、支持事务,操作都是原子性;
4、丰富的特性:可用于缓存,消息,按key设置过期时间,过期后将会自动删除;
4、Redis相比Memcached有哪些优势?
1、Memcached所有的值均是简单的字符串,redis作为其替代者,支持更为丰富的数据类;
2、Redis的速度比Memcached快很;
3、Redis可以持久化其数据;
5、Memcache与Redis的区别都有哪些
1、存储方式Memecache把数据全部存在内存之中,断电后会挂掉,数据不能超过内存大小。 Redis有部份存在硬盘上,这样能保证数据的持久性;
2、数据支持类型Memcache对数据类型支持相对简单。 Redis有复杂的数据类型;
3、使用底层模型不同 它们之间底层实现方式 以及与客户端之间通信的应用协议不一样。 Redis直接自己构建了VM机制 ,因为一般的系统调用系统函数的话,会浪费一定的时间去移动和请求。
6、Redis是单进程单线程的?
Redis是单进程单线程的,redis利用队列技术将并发访问变为串行访问,消除了传统数据库串行控制的开销。
7、Redis持久化机制?
Redis是一个支持持久化的内存数据库,通过持久化机制把内存中的数据同步到硬盘文件来保证数据持久化。当Redis重启后通过把硬盘文件重新加载到内存,就能达到恢复数据的目的;
Redis的持久化机制有两种:RDB和AOF;
RDB:是Redis默认的持久化机制。实现:单独创建一个fork()的一个子线程,将当前父进程中的数据复制到子进程的内存中。然后由子进程写入临时文件中,持久化过程结束后,再用这个临时文件替换上次的快照文件,然后子进程退出,内存释放。
优点:只有一个rdb文件,持久化比较方便。
缺点:安全性较低,因为是五秒执行一次,在此期间有可能会造成数据丢失
AOF:Redis会将每一个收到的写命令都通过write函数追加到文件最后,类似于
Mysql的binlog。当Redis重启的时候会重新执行文件中保存的写命令来在内存中重建 整个数据内容。
当两种方式都开启时,数据恢复会优先选择AOF恢复,因为AOF的数据比RDB的数据更完整。
8、缓存雪崩、缓存穿透、缓存预热、缓存更新、缓存降级
缓存雪崩:指原有缓存过期了,新缓存未更新,导致所有请求都指向数据库,对数据库压力CPU和内存造成比较大的压力导致宕机,造成系统崩溃(比如缓存设置了相同的过期时间,同一时刻大批量缓存过期)。
解决方法:常用的是加锁或者是队列的方式来保证不会有大量的线程去对数据库一次性进行读写,避免当缓存失效时大量的并发请求落到底层存储系统上。还有一种简单的方法是设置不同的过期时间,使其过期时间分散开来。
缓存穿透:指当用户查询数据,在数据库没有,缓存中肯定也没有。这样就导致用户在查询的时候,在缓存中找不到,每次都要去数据库再查询一遍,然后返回空,两次无用的查询,这样就直接绕开了缓存直接查询数据库,这也是经常说的缓存命中率问题。
解决方法:简单的办法就是,如果取到的空,我们仍然把这个数据进行缓存,但设置少点的过期时间,这样下次请求的时候就可以再缓存中拿到了,而不会再去请求数据库。还有一种方法就是通过布隆过滤器来实现,就是把所有可能存在的数据哈希在一个比较大的bitmap中,一个一定不存在的数据就会被bitmap拦截掉,避免了对存储系统的查询压力。
缓存预热:就是系统上线后将一些相关的数据直接加载在缓存系统,这样就避免
了用户在请求的时候先去访问数据库再去缓存数据的问题。
解决方法:1、如果数据量不大的情况就可以在项目启动的时候直接将数据加载到缓存中;2、直接写个手动刷新的页面,系统上线后,手动执行一下;3、写个定时刷新缓存的功能;
缓存更新:
1、定时去清理过期缓存;
2、当用户请求过来时判断缓存是否过期,过期的话就去底层存储系统查询数据并更新缓存;
缓存降级:指在缓存失效或者服务器挂掉的时候,不去访问数据库,直接返回默认数据,降级一般是有损操作,所以尽量要防止降级对业务的影响;
9、Redis的删除策略
Redis是根据定时删除+惰性删除实现的
定时删除是在指定时间去随机塞选key判断是否过期然后删除,这个时候会有很多key没被筛选掉,这时候就是惰性删除派上用场了,也就是说当需要使用到这个key的时候,redis会去检查一下是否过期,如果过期了直接进行删除.
采用定期删除+惰性删除就没其他问题了么?
不是的,如果定期删除没删除key。然后你也没即时去请求key,也就是说惰性删除也没生效。这样,redis的内存会越来越高。那么就应该采用内存淘汰机制。在redis.conf中有一行配置(具体百度)。
10、Redis同步机制
redis可以使用主从同步,从从同步。第一次同步时,主节点做了一次bgsave,并将后续修改操作记录到内存的buffer中,待完成后将rdp文件全量同步到复制节点,复制节点加载完后将rdp加载到内存。加载完成后再通知主节点将期间修改的操作记录同步给复制节点进行重放就完成了同步工作。
11、如何保证redis缓存与数据库一致
1、先更新缓存,再更新数据库;
2、先更新数据库,再更新缓存;
3、先删除缓存,再更新数据库;
4、先更新数据库,再删除缓存;
前几种如果期间有部分异常还是会导致数据不一致
推荐:先删除缓存再更新数据库,休眠一秒左右再删除缓存(双删)
12、使用过redis异步队列吗?
一般使用list结构作为队列,rpush生产消息,lpop消费消息,当lpop没有消息的时候适当的sleep一会。
可不可以不用sleep?
redis里还有一个叫做blpop的指令,在没有消息的时候,它会阻塞住直到消息的到来。
能不能生产一条消息消费多次?
使用pub/sub 主体订阅模式,可以实现1对N的消息队列
缺点:当消费者下线时会造成数据丢失,建议使用专业的消息队列如RabbitMQ;
13、使用过redis分布式锁吗?
主要是先拿setnx来争抢锁,抢到之后,再用expire给锁加一个过期时间防止锁忘记了释放。
如果是再setnx之后expire之前进程意外死掉了或者重启怎么办?
可以将setnx和exire合成一条命令来使用
分布式锁还有其他实现方法吗?
1、通过数据库的增删的方式实现;
2、通过数据库的排他锁实现;
3、基于zk(Zookeeper)实现;
Nginx
1、什么是nginx?
Nginx是一个轻量级/高性能的反向代理web服务器,他实现了非常高效的反向代理,负载均衡,他可以处理2到3万的并发连接数,官方测试在5万左右的并发。而且nginx是跨平台的、配置简单、内存消耗小,它在处理静态资源方面效率很高。接收用户请求是异步的。
2、为什么nginx效率比较高?
因为它的处理方式是:异步非阻塞事件处理机制。运用了一个epoll模型,提供了一个队列,排队解决的。
3、nginx是怎么处理一个请求的?
首先ngixn接收到请求后小,先通过listen和server_name判断匹配到server模块,再通过server模块里的localhost匹配地址。
4、什么是正向代理/反向代理?
正向代理就是当一个用户发送请求后,直接请求到目标服务器;
反向代理就是当一个用户发送请求后,通过nginx接受,然后根据一定的规则分给后端业务处理器进行处理;
5、使用反向代理的优点是什么?
可以隐藏源服务器的存在和特征,它相当于互联网和web服务器之间的中间层,安全性比较高;
6、限流怎么做?
限制并发连接数
限制访问频率(正常、突发)
7、nginx怎么做的动静分离?
只需要在nginx配置文件中server模块的localhst去指定目录地址就可以了;
8、负载均衡是怎么实现的?
通过轮询(默认)、权重(weight)、ip_hash(IP绑定),还有俩第三方插件(fair,url_hash);
RabbitMQ
1、什么是MQ
MQ就是消息队列。是软件和软件进行通信的中间件产品
2、MQ的优点
1、异步处理 - 相比于传统的串行、并行方式,提高了系统吞吐量。
2、应用解耦 - 系统间通过消息通信,不用关心其他系统的处理。
3、流量削锋 - 可以通过消息队列长度控制请求量;可以缓解短时间内的高并发请求。
4、日志处理 - 解决大量日志传输。
5、消息通讯 - 消息队列一般都内置了高效的通信机制,因此也可以用在纯的消息通讯。比如实现点对点消息队列,或者聊天室等。
3、解耦、异步、削峰是什么?
1、解耦:A 系统发送数据到 BCD 三个系统,通过接口调用发送。如果 E 系统也要这个数据呢?那如
果 C 系统现在不需要了呢?A 系统负责人几乎崩溃…A 系统跟其它各种乱七八糟的系统严重耦合,
A 系统产生一条比较关键的数据,很多系统都需要 A 系统将这个数据发送过来。如果使用 MQ,A
系统产生一条数据,发送到 MQ 里面去,哪个系统需要数据自己去 MQ 里面消费。如果新系统需
要数据,直接从 MQ 里消费即可;如果某个系统不需要这条数据了,就取消对 MQ 消息的消费即
可。这样下来,A 系统压根儿不需要去考虑要给谁发送数据,不需要维护这个代码,也不需要考虑
人家是否调用成功、失败超时等情况。就是一个系统或者一个模块,调用了多个系统或者模块,互相之间的调用很复杂,维护起来很麻烦。但是其实这个调用是不需要直接同步调用接口的,如果用 MQ 给它异步化解耦。2、异步:A 系统接收一个请求,需要在自己本地写库,还需要在 BCD 三个系统写库,自己本地写库
要 3ms,BCD 三个系统分别写库要 300ms、450ms、200ms。最终请求总延时是 3 + 300 + 450
+ 200 = 953ms,接近 1s,用户感觉搞个什么东西,慢死了慢死了。用户通过浏览器发起请求。
如果使用 MQ,那么 A 系统连续发送 3 条消息到 MQ 队列中,假如耗时 5ms,A 系统从接受一个
请求到返回响应给用户,总时长是 3 + 5 = 8ms。3、削峰:减少高峰时期对服务器压力。
4、消息队列有什么缺点?
1、系统可用性降低
本来系统运行好好的,现在你非要加入个消息队列进去,那消息队列挂了,你的系统不是呵呵了。因此,系统可用性会降低;2、系统复杂度提高
加入了消息队列,要多考虑很多方面的问题,比如:一致性问题、如何保证消息不被重复消费、如何保证消息可靠性传输等。因此,需要考虑的东西更多,复杂性增大。3、一致性问题
A 系统处理完了直接返回成功了,人都以为你这个请求就成功了;但是问题是,要是 BCD 三个系统那里,BD 两个系统写库成功了,结果 C 系统写库失败了,咋整?你这数据就不一致了。5、MQ 有哪些常见问题?如何解决这些问题?
1、消息的顺序问题
解决方法:
1、拆分成多个queue(队列)与消费者是一对一对一的关系;
缺点: 1)、并行度就会成为消息系统的瓶颈(吞吐量不够)
2)、只要消费端出现问题,就会导致整个处理流程阻塞,我们不得不花费更多的精力来解决阻塞的问题
2、通过合理的设计或者将问题分解来规避。
3、队列无序并不意味着消息无序 所以从业务层面来保证消息的顺序而不仅仅是依赖于消息系统,是一种更合理的方式。
2、消息的重复问题
解决方法:
1、可以通过给消息的某一些属性设置唯一约束,比如增加唯一uuid,添加的时候查询是否存对应的uuid,存在不操作,不存在则添加,那样对于相同的uuid只会存在一条数据;
2、把RabbitMQ的消息自动确认机制改为手动确认,然后每当有一条消息消费成功了,就把该消息的唯一ID记录在Redis 上,然后每次发送消息时,都先去 Redis 上查看是否有该消息的 ID,如果有,表示该消息已经消费过了,不再处理,否则再去处理;
6、RabbitMQ的使用场景?
(1)服务间异步通信
(2)顺序消费
(3)定时任务
(4)请求削峰7、消息如何分发?
若该队列至少有一个消费者订阅,消息将以循环(round-robin)的方式发送给消费者。每条消息只会分发给一个订阅的消费者(前提是消费者能够正常处理消息并进行确认)。通过路由可实现多消费的功能。
8、如何确保消息正确地发送至 RabbitMQ? 如何确保消息接收方消费了消息?
发送方确认模式
1、将信道设置成 confirm 模式(发送方确认模式),则所有在信道上发布的消息都会被指派一个唯一的 ID。
2、一旦消息被投递到目的队列后,或者消息被写入磁盘后(可持久化的消息),信道会发送一个确认给生产者(包含消息唯一 ID)。
3、如果 RabbitMQ 发生内部错误从而导致消息丢失,会发送一条 nack(notacknowledged,未确认)消息。
4、发送方确认模式是异步的,生产者应用程序在等待确认的同时,可以继续发送消息。当确认消息到达生产者应用程序,生产者应用程序的回调方法就会被触发来处理确认消息。
接收方确认机制
1、消费者接收每一条消息后都必须进行确认(消息接收和消息确认是两个不同操作)。只有消费者确认了消息,RabbitMQ 才能安全地把消息从队列中删除。
2、这里并没有用到超时机制,RabbitMQ 仅通过 Consumer 的连接中断来确认是否需要重新发送消息。也就是说,只要连接不中断,RabbitMQ 给了 Consumer 足够长的时间来处理消息。保证数据的最终一致性;
SpringCloud
1、什么是微服务架构?
微服务架构就是将多个应用程序拆分为多个应用程序,这多个应用程序就成为微服务,每个微服务运行在自己的进程中,并使用轻量级的机制通信。这些应用程序可以通过业务来划分,每个服务只负责某一块业务,便于管理维护,可以独立部署。
2、SpringCloud是什么?
是一个一系列框架的有序集合。它利用SpringBoot的开发便捷巧妙的简化了分布式系统基础设施的开发。如服务发现注册、配置中心、负载均衡、数据监控等等都可以使用SpringBoot的开发风格做到一键启动和部署;
Spring Cloud不是重复制造轮子,它只是将各家公司开发的比较成熟的,经得起考验的服务器框架整合起来,通过SpringBoot的风格简化了那些复杂的配置和实现原理,最终给开发者留下一套简单易懂、易部署、易维护的分布式系统开发工具包。
3、SpringCloud的优缺点?
优点:
1.耦合度比较低。不会影响其他模块的开发。
2.减轻团队的成本,可以并行开发,不用关注其他人怎么开发,先关注自己的开发。
3.配置比较简单,基本用注解就能实现,不用使用过多的配置文件。
4.微服务跨平台的,可以用任何一种语言开发。
5.每个微服务可以有自己的独立的数据库也有用公共的数据库。
6.直接写后端的代码,不用关注前端怎么开发,直接写自己的后端代码即可,然后暴露接口,通过组件进行服务通信。缺点:
1.部署比较麻烦,给运维工程师带来一定的麻烦。
2.针对数据的管理比麻烦,因为微服务可以每个微服务使用一个数据库。
3.系统集成测试比较麻烦
4.性能的监控比较麻烦。【最好开发一个大屏监控系统】4、SpringBoot和SpringCloud的区别?
1、SpringBoot专注于快速方便的开发单个个体微服务,Spring Cloud关注全局的服务治理框架。
2、SpringBoot可以离开SpringCloud独立开发,而SpringCloud却离不开SpringBoot,属于依赖关系;
5、SpringCloud由什么组成?
大概分为以下几种
1、Spring Cloud Eureka:服务注册与发现
2、Spring Cloud Zuul:服务网关
3、Spring Cloud Ribbon:客户端负载均衡
4、Spring Cloud Feign:声明性的Web服务客户端
5、Spring Cloud Hystrix:断路器
6、Spring Cloud Config:分布式统一配置管理
等等。。。。。。
10、 Spring Cloud 和 dubbo区别?
1、注册中心:dubbo的注册中心是zk,SpringCloud是eureka也可以是zk;
2、服务调用方式:dubbo是RPC,dubbo是rest API;
11、Spring Cloud Gateway的理解?
Spring cloud gateway是spring官方基于Spring 5.0、Spring Boot2.0和Project Reactor等技术开发的网关,Spring Cloud Gateway指在为微服务架构提供简单、有效和统一的API路由管理方式,Spring Cloud Gateway作为Spring Cloud生态系统中的网关,目标是替代Netflix Zuul,其不仅提供统一的路由方式,并且还基于Filer链的方式提供了网关基本的功能,例如:安全、监控/埋点、限流等。
12、Spring Cloud OpenFeign的理解
Feign是一个声明性的Web服务客户端。它使编写Web服务客户端变得更容易。要使用Feign,我们可以将调用的服务方法定义成抽象方法保存在本地添加一点点注解就可以了,不需要自己构建Http请求了,直接调用接口就行了,不过要注意,调用方法要和本地抽象方法的签名完全一致。
13、Spring Cloud Security的理解
安全工具包
1)、对Zuul代理中的负载均衡从前端到后端服务中获取SSO令牌
2)、资源服务器之间的中继令牌3)、使Feign客户端表现得像 OAuth2RestTemplate (获取令牌等)的拦截器
4)、在Zuul代理中配置下游身份验证
主要是实现一些安全验证及安全授权的工作,常用来实现如单点登录,令牌中继和令牌交换。
SpringBoot
1、什么是 Spring Boot?
Spring Boot 是 Spring 开源组织下的子项目,是 Spring 组件一站式解决方案,主要是简化了使用Spring 的难度,简省了繁重的配置,提供了各种启动器,使开发者能快速上手。
2、为什么要用SpringBoot?
快速开发,快速整合,配置简化、内嵌服务容器
3、Spring Boot 有哪些优点?
1、容易上手,提升开发效率,为 Spring 开发提供一个更快、更简单的开发框架。
2、开箱即用,远离繁琐的配置。
3、提供了一系列大型项目通用的非业务性功能,例如:内嵌服务器、安全管理、运行数据监控、运行状况检查和外部化配置等。
4、SpringBoot总结就是使编码变简单、配置变简单、部署变简单、监控变简单等等。4. Spring Boot 的核心注解是哪个?它主要由哪几个注解组成的?
启动类上面的注解是@SpringBootApplication,它也是 Spring Boot 的核心注解,主要组合包含了以下 3 个注解:
@SpringBootConfiguration:组合了 @Configuration 注解,实现配置文件的功能。
@EnableAutoConfiguration:打开自动配置的功能,也可以关闭某个自动配置的选项, 例如: java 如关闭数据源自动配置功能: @SpringBootApplication(exclude = { DataSourceAutoConfiguration.class })。
@ComponentScan:Spring组件扫描。5、SpringBoot的自动配置原理是什么?
主要是Spring Boot的启动类上的核心注解SpringBootApplication注解主配置类,有了这个主配置类启动时就会为SpringBoot开启一个@EnableAutoConfiguration注解自动配置功能。有了这个EnableAutoConfiguration的话就会:
1、从配置文件META_INF/Spring.factories加载可能用到的自动配置类
2、去重,并将exclude和excludeName属性携带的类排除
3、过滤,将满足条件(@Conditional)的自动配置类返回
SpringMVC
1、谈谈你对SpringMVC的理解?
Spring MVC是一个实现了MVC设计模式的轻量级Web框架,其核心是Model,View,Controller,把复杂的web应用分层,简化开发。
2、SpringMVC执行流程是什么?
(1)用户发送请求至前端控制器DispatcherServlet。
(2)前端控制器收到请求调用处理器映射器HandlerMapping。
(3)处理器映射器找到具体的处理器,生成处理器对象及处理器拦截器并返回给前端控制器。
(4)前端控制器调用处理器适配器HandlerAdapter。
(5)处理器适配器经过适配调用具体的处理器Controller。
(6)处理器执行完成返回执行结果ModelAndView。
(7)处理器适配器将执行结果返回给前端控制器。
(8)前端控制器将执行结果传给视图解析器ViewReslover。
(9)视图解析器解析后返回具体View。
(10)前端控制器根据View进行渲染视图
(11)前端控制器响应用户3、SpringMVC怎么样重定向和转发的?
(1)转发
在返回值前面加"forward:",如"forward:user.do?name=hello"
(2)重定向
在返回值前面加"redirect:",如"redirect:http://www.baidu.com"
Mybatis
1、什么是Mybatis?
1. Mybatis是一个半orm(对象映射)框架,它内部封装了JDBC,开发时只需要关注SQL的本身,不需要 加载驱动、创建连接、写statement的过程,程序员直接编写原生的sql,灵活性高。
2. Mybatis可以使用XML 或注解来配置和映射原生信息,将POJO映射成数据库的记录(对象的属性字段),避免了所有JDBC代码和手动设置参数以及获取结果集。
2、Mybatis的优缺点?
优点:
1. 基于SQL编程,不会对数据库的现有设计和java应用程序造成任何影响,SQL写在XML文件里,解除了SQL与应用程序代码的耦合,方便统一管理; 提供XML标签(结果map),支持动态编写SQL语句,并可重用。
2. 与JDBC相比,减少了代码的冗余量,减少了50%的代码量,不需要手动开关连接。
3. 很好与各种数据库兼容(因为Mybatis使用JDBC连接数据库,所以只要支持JDBC连接数据库的都支持Mybatis)。
4. 能够与spring集成。
5. 提供映射标签,支持对象与数据库的ORM字段关系映射;提供对象关系映射标签,支持对象关系组件维护。
缺点:
1. SQL语句的编写工作量较大,尤其是字段多的时候,对开发人员的编写SQL语句的功底有一定要求。
2. SQL 依赖于数据库,导致数据库移植性差,SQL语句依赖于数据库。
3、#{}与${}的区别是什么?
#{} 是预编译处理,${}是字符串替换
1. Mybatis处理#{}时,会将sql#{}转换为?(占位符),然后使用PreparedStatement的set方法来赋值。
2. 使用#{}能有效的预防SQL注入,提高系统的安全性。
4、Mybatis 是如何进行分页的?分页插件的原理是什么?
Mybatis 使用 RowBounds 对象进行分页,它是针对 ResultSet 结果集执行的内存分页,而非物理分页。可以在 sql 内直接书写带有物理分页的参数来完成物理分页功能,也可以使用分页插件来完成物理分页。 分页插件的基本原理是使用 Mybatis 提供的插件接口,实现自定义插件,在插件 的拦截方法内拦截待执行的 sql,然后重写 sql,根据 dialect 方言,添加对应的物理分页语句和物理分页参数。
5、Mybatis是如何将SQL执行结果封装成目标对象并返回的,都有哪些映射形式?
1. ResultMap形式。 将SQL执行结果用<ResultMap>标签映射成目标对象。
2. 使用SQL列的别名,将查询结果用as转换为列的别名书写成对象属性名。
6、Mybatis 实现一对多的方式有哪几种? 具体是怎么操作的?
有2种方式: 联合查询和嵌套查询。 联合查询是只查询一次,通过在resultMap里配置collection节点配置一对多的类就可以完成。嵌套查询是先查 一个表,根据这个表里面的 结果的外键 id,去再另外一个表里面查询数据,也是通过 配置 collection,但另外一个表的查询通过 select 节点配置。
设计模式
1、什么是设计模式?
是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。使用设计
模式是为了可重用代码、让代码更容易被他人理解、保证代码可靠性、程序的重用性。2、设计模式分类
3、什么是单例模式?
保证一个类只有一个实例,并且提供一个访问该全局访问点
4、单例的优缺点?
优点:
1、在单例模式中,活动的单例只有一个实例,对单例类的所有实例化得到的都是相同的一个实例。这样就防止其它对象对自己的实例化,确保所有的对象都访问一个实例;
2、单例模式具有一定的伸缩性,类自己来控制实例化进程,类就在改变实例化进程上有相应的伸缩性。
3、提供了对唯一实例的受控访问。4、由于在系统内存中只存在一个对象,因此可以节约系统资源,当需要频繁创建和销毁的对象时单例模式无疑可以提高系统的性能。
5、允许可变数目的实例。
6、避免对共享资源的多重占用。
缺点:1、不适用于变化的对象,如果同一类型的对象总是要在不同的用例场景发生变化,单例就会引起数据的错误,不能保存彼此的状态。
2、由于单利模式中没有抽象层,因此单例类的扩展有很大的困难。
3、单例类的职责过重,在一定程度上违背了“单一职责原则”。
4、滥用单例将带来一些负面问题,如为了节省资源将数据库连接池对象设计为的单例类,可能会导致共享连接池对象的程序过多而出现连接池溢出;如果实例化的对象长时间不被利用,系统会认为是垃圾而被回收,这将导致对象状态的丢失。5、单例创建方式
主要是饿汉和懒汉
1、饿汉式:类初始化时,会立即加载该对象,线程天生安全,调用效率高
2、懒汉式:类初始化时,会立即加载该对象,线程天生安全,调用效率高
3、静态内部方式:结合了懒汉式和饿汉式各自的优点,真正需要对象的时候才会加载,加载类是线程安全的。
7、什么是工厂模式
它提供了一种创建对象的最佳方式。在工厂模式中,我们在创建对象时不会对客户端暴露创建逻辑,并且是通过使用一个共同的接口来指向新创建的对象。实现了创建者和调用者分离,工厂模式分为简单工厂、工厂方法、抽象工厂模式(抽象工厂简单地说是工厂的工厂,抽象工厂可以创建具体工厂,由具体工厂来产生具体产品)
8、策略模式
1、定义了一系列的算法 或 逻辑 或 相同意义的操作,并将每一个算法、逻辑、操作封装起来,而且使它们还可以相互替换。(其实策略模式Java中用的非常非常广泛)
2、我觉得主要是为了 简化 if…else 所带来的复杂和难以维护。
优点: 1、算法可以自由切换。 2、避免使用多重条件判断。 3、扩展性非常良好。
缺点: 1、策略类会增多。 2、所有策略类都需要对外暴露。
多线程
1、使用多线程有什么好处?
1、能够更充分地利用cpu。在单线程中cpu大部分处于空闲状态,如果使用多线程就能保证cp的高速运转状态,不会有某些部分空闲下来;
2、提升效率。比如数据量比较大的时候使用单线程就不太合理了,因为这样只会让下面的步骤处于阻塞状态,因为数据比较多,执行效果就没没那么快了,这时候就可以使用多线程去将这块数据分为多个线程去处理这样就能有效的提升执行效率。
2、线程和进程的区别?
这么解释吧,就比如我们手机上的微信,当我们打开微信的时候,这个动作就好比是一个进程,而微信里的朋友圈、会话列表、发现、服务什么的就可以看成是线程。这样就可以看出一个进程里可以包含多个线程。
比较官方的解释就是:进程就是一个操作系统资源分配的基本单位,而线程是任务调度和执行的基本单位;
3、Java实现线程有哪些方案?
1、可以继承Thrend类;
2、实现Runnable接口;
3、使用 ExecutorService、Callable、Future 实现有返回结果的多线程;
4、启动线程方法 start()和 run()有什么区别?
其实start()方法中也有run()方法,不过它是启动了一个新的线程然后再进行run()的,
而如果直接调用run()的话,其实还是在当前线程中启动了,这样就不是多线程了。
5、怎么终止一个线程?如何优雅地终止线程?
1、直接使用stop()终止,不过这个方法已经废弃了,不推荐;
2、可以使用标识的方法,使线程正常退出,也就是run方法完成后退出;
3、使用interrupt()方法中断线程。
6、线程中的 wait()和 sleep()方法有什么区别?
1、sleep() 方法是 Thread 类中的方法,而 wait() 方法是 Object 类中的方法。
2、sleep() 方法不会释放 lock,但是 wait() 方法会释放,而且会加入到等待队列中。
3、sleep() 方法不依赖于同步器 synchronized(),但是 wait() 方法 需要依赖 synchronized 关键字。
7、volatile 关键字的作用?
volatile关键字是用于保证有序性和可见性。当一个共享变量被volatile修饰后,它会保证被修改后的值立即被更新到主存,当有其他线程需要读取的时候,它会去内存中读取到新的值;
可见性:指当多个线程访问同一个变量时,一个线程修改了这个变量的值,其他线程能够立即看得到修改的值。
有序性:即程序执行的顺序按照代码的先后顺序执行;
8、一个线程生命周期有哪几种状态?它们之间如何流转的?
六种状态:
1、New(新创建)
创建一个线程就是新建状态;
2、Runnable(可运行)
调用start方法后,获取到CPU时间片的线程处于running状态,没有获取到时间片处于Ready状态,这两种状态统称为Runnable;
3、Blocked(被阻塞)
调用start方法后线程没有获取cpu时间片或者在阻塞等待获取锁对象会进入阻塞状态;
4、Waiting(等待)
线程调用了wait方法进入等待状态;sleep方法不会释放锁资源;
5、Timed Waiting(计时等待)
调用了sleep(long),wait(long)等方法;
6、Terminated(被终止)
线程run方法执行结束进入销亡状态;
9、线程池是什么,为什么使用线程池,以及线程池的原理?
线程池是运用场景最多的并发框架,几乎所有需要一步或者并发执行任务的程序都可以使用线程池。使用线程池一般有以下三个好处
1、降低资源的消耗:通过重复利用已经创建的线程降低线程创建和销毁造成的消耗。
2、提高相应的速度:当任务到达的时候,任务可以不需要等到线程创建就能立刻执行。
3、提高线程的可管理性:线程是稀缺资源,使用线程池可以统一的分配、调优和监控;
原理:
简单来说就是,当提交一个任务到线程池后,线程池会判断里面的核心线程是否都在工作,如果都在工作的话就会创建一个新的线程来执行任务,然后再判断队列是否满了,如果队列没满则会将该线程放到队列里,如果满了就会继续判断线程池是否满了,如果满了则交给饱和策略来处理,也就是拒绝策略;
JVM
1、什么是JVM?
JVM也叫做Java虚拟机,它主要有两个作用;
1、运行并管理Java源文件所生成的.class文件;
2、在不同的操作系统上安装不同的JVM,从而实现跨平台的保障;
2、JVM的内存结构?
JVM的内部体系结构分为三部分
1、类加载器;
从类被加载到虚拟机内存中开始,到释放内存总共有7个步骤:加载,验证,准备,解析,初始化,使用,卸载。其中验证,准备,解析三个部分统称为连接
2、运行时数据区;
Java 虚拟机在执行 Java 程序的过程中会把它所管理的内存区域划分为若干个不同的数据区域。这些区域都有各自的用途,以及创建和销毁的时间,有些区域随着虚拟机进程的启动而存在,有些区域则是依赖线程的启动和结束而建立和销毁。Java 虚拟机所管理的内存被划分为如下几个区域:
1)、方法区;
用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译后的代码等数据。
2)、虚拟机栈;
每个方法在执行的同时都会在Java 虚拟机栈中创建一个栈帧(Stack Frame)用于存储局部变量表、操作数栈、动态链接、方法出口等信息;
栈帧就是Java虚拟机栈中的下一个单位
3)、本地方法栈;
与虚拟机栈的作用是一样的,只不过虚拟机栈是服务 Java方法的,而本地方法栈是为虚拟机调用 Native 方法服务的;
Native 关键字修饰的方法是看不到的,Native 方法的源码大部分都是 C和C++ 的代码
4)、Java堆;
Java 虚拟机中内存最大的一块,是被所有线程共享的,几乎所有的对象实
例都在这里分配内存;5)、程序计数器;
当前线程所执行的字节码的行号指示器,字节码解析器的工作是通过改变这个计数器的值,来选取下一条需要执行的字节码指令,分支、循环、跳转、异常处理、线程恢复等基础功能,都需要依赖这个计数器来完成;
为什么要线程计数器?因为线程是不具备记忆功能
3、执行引擎
虚拟机核心的组件就是执行引擎,它负责执行虚拟机的字节码,一般户先进行编译成机器码后执行。“虚拟机”是一个相对于“物理机”的概念,虚拟机的字节码是不能直接在物理机上运行的,需要JVM字节码执行引擎- 编译成机器码后才可在物理机上执行。
3、JVM如何调优的?
JVM调优涉及到两个很重要的概念:一个是吞吐量一个是响应时间。JVM调优主要是针对于这两个进行调优,达到一个理想的目标。根据业务确认目标是吞吐量优先还是响应优先。
调优步骤:
1、熟悉业务场景,了解当前业务系统的要求,是吞吐量优先还是响应时间优先;
2、CPU选择,再预算允许的情况下,性能越高越好;
3、选择合适的垃圾回收器组合,如果是吞吐量优先则选择PS+PO组合;如果是响应时间优先,在1.8以后选择G1,在之前选择ParNew+CMS组合;
调优常用参数:
通用GC参数
-Xmn:年轻代大小 -Xms:堆初始大小 -Xmx:堆最大大小 -Xss:栈大小-XX:+UseTlab:使用tlab,默认打开,涉及到对象分配问题
-XX:+PrintTlab:打印tlab使用情况
-XX:+TlabSize:设置Tlab大小
-XX:+DisabledExplictGC:java代码中的System.gc()不再生效,防止代码中误写,导致频繁触动GC,默认不起用。
-XX:+PrintGC(+PrintGCDetails/+PrintGCTimeStamps)打印GC信息(打印GC详细信息/打印GC执行时间)
-XX:+PrintHeapAtGC打印GC时的堆信息
-XX:+PrintGCApplicationConcurrentTime 打印应用程序的时间
-XX:+PrintGCApplicationStopedTime 打印应用程序暂停时间
-XX:+PrintReferenceGC 打印回收多少种引用类型的引用
-verboss:class 类加载详细过程
-XX:+PrintVMOptions 打印JVM运行参数
-XX:+PrintFlagsFinal(+PrintFlagsInitial) -version | grep 查找想要了解的命令,很重要
-X:loggc:/opt/gc/log/path 输出gc信息到文件
-XX:MaxTenuringThreshold 设置gc升到年龄,最大值为15
parallel常用参数
-XX:PreTenureSizeThreshold 多大的对象判定为大对象,直接晋升老年代-XX:+ParallelGCThreads 用于并发垃圾回收的线程
-XX:+UseAdaptiveSizePolicy 自动选择各区比例
CMS常用参数
-XX:+UseConcMarkSweepGC 使用CMS垃圾回收器-XX:parallelCMSThreads CMS线程数量
-XX:CMSInitiatingOccupancyFraction 占用多少比例的老年代时开始CMS回收,默认值68%,如果频繁发生serial old,适当调小该比例,降低FGC频率
-XX:+UseCMSCompactAtFullCollection 进行压缩整理
-XX:CMSFullGCBeforeCompaction 多少次FGC以后进行压缩整理
-XX:+CMSClassUnloadingEnabled 回收永久代
-XX:+CMSInitiatingPermOccupancyFraction 达到什么比例时进行永久代回收
GCTimeTatio 设置GC时间占用程序运行时间的百分比,该参数只能是尽量达到该百分比,不是肯定达到
-XX:MaxGCPauseMills GCt停顿时间,该参数也是尽量达到,而不是肯定达到
G1常用参数
-XX:+UseG1 使用G1垃圾回收器-XX:MaxGCPauseMills GCt停顿时间,该参数也是尽量达到,G1会调整yong区的块数来达到这个值
-XX:+G1HeapRegionSize 分区大小,范围为1M~32M,必须是2的n次幂,size越大,GC回收间隔越大,但是GC所用时间越长
G1NewSizePercent 新生代所占最小比例,默认5%
G1MaxNewSizePercent 新生代所占最大比例,默认60%
GCTimeRatio GC时间比例,此值为建议值,G1会调整堆大小来尽量达到这个值
ConcGCThreads GC线程数量
InitiatingHeapOccupancyPercent 启动G1的堆空间占用比例
4、GC是干嘛的?
GC就是一个垃圾回收机制,他的目的呢就是解决运行过程中产生的垃圾对象:因为程序运行过程中会产生许多垃圾对象,持续占用内存,堆积的多了就会照成内存泄漏,最终导致内存溢出,迫使系统停止运行。
内存泄漏:
是指程序在申请内存后,无法释放已申请的内存,导致系统无法及时回收内存分配给其他进程使用。通常少次数的内存无法及时回收并不会到程序造成什么影响,但是如果在内存本身就比较少获取多次导致内存无法正常回收时,就会导致内存不够用,最终导致内存溢出。
内存溢出:
是指程序在申请内存时,没有足够的内存供申请者使用,导致数据无法正常存储到内存内。也就是说给你个int类型的存储数据大小的空间,但是却存储一个long类型的数据,这样就会导致内存溢出。
5、说说GC算法?
1、 Mark-Sweep(标记清除)标记清除算法分为“标记”和“清除”两个阶段:首先标记出所有需要回收的对象,在标记完成后统一回收所有被标记的对象。
缺点:
效率问题:标记和清除过程的效率都不高;
空间问题:标记清除之后会产生大量不连续的内存碎片,空间碎片太多可能会导致,当程序在以后的运行过程中需要分配较大对象时无法找到足够的连续内存而不得不提前触发另一次垃圾收集动作。
2、Copying(复制)
复制算法就是将内存空间按容量分成两块。当这一块内存用完的时候,就将还存活着的对象复制到另外一块上面,然后把已经使用过的这一块一次清理掉。这样使得每次都是对半块内存进行内存回收。内存分配时就不用考虑内存碎片等复杂情况,只要移动堆顶的指针,按顺序分配内存即可,实现简单,运行高效。
缺点:
复制算法弥补了标记清除算法中,内存布局混乱的缺点,不过与此同时,它的缺点也是相当明显的。它浪费了一半的内容,这太要命了。如果对象的存活率很高,我们可以极端一点,假设是100%存活,那么我们需要将所有对象都复制一遍,并将所有引用地址重复一遍,复制这一工作所花费的时间,在对象存活率达到一定程度时,将会变的不可忽视,所以从以上描述不难看出,复制算法要想使用,最起码对象的存活率要非常低才行,而且最重要的是,我们必须要克服50%内存的浪费。
3、Mark-Compact(标记整理)
标记整理算法,标记过程仍然与“标记-清除”算法一样,但后续步骤不是直接对可回收对象进行清理,而是让所有存活的对象都向一端移动,然后直接清理掉端边界以外的内存。
特点:
1、消除了标记-清除算法当中,内存区域分散的缺点,我们需要给新对象分配内存时,JVM 只需要持有一个内存的起始地址即可。
2、 消除了复制算法当中,内存减半的高额代价。
缺点:
标记整理算法唯一的缺点就是效率不高,不仅要标记所有的存活对象,还要整理所有存活对象引用的地址,从效率上来说,标记整理算法低于复制算法。
6、GC算法总结
内存效率:复制算法>标记清除算法>标记整理算法(此处的效率只是简单的对比时间复杂度,实际情况不一定如此)。
内存整齐度:复制算法=标记整理算法>标记清楚算法
内存利用率:标记整理算法=标记清除算法>复制算法
7、常见的垃圾收集器
收集器 收集对象和算法 收集器类型 说明 适用场景 Serial 新生代,复制算法 单线程 简单高效,适合内存不大的情况 ParNew 新生代,复制算法 并行的多线程收集器 ParNew垃圾收集器是Serial收集器的多线程版本 搭配CMS垃圾回收器的首选 Parallel Scavenge 新生代,复制算法 并行的多线程收集器 类似ParNew,更加关注吞吐量,达到一个可控制的吞吐量 本身是Server级别多CPU机器上的默认GC方式,主要适合后台运算不太需要太多交互的任务 Serial Old 老年代,标记整理算法 单线程 Client模式下虚拟机使用 Parallel Old 老年代,标记整理算法 并行的多线程收集器 Parallel Scavenge收集器的老年代版本,为了配置Parallel Scavenge的面向吞吐量的特性而开发的对应组合 在注重吞吐量以及CPU资源敏感的场合采用 CMS 老年代,标记清除算法 并行的多线程收集器 尽可能的缩短垃圾收集时用户线程停止时间;缺点在于,1.内存碎片,2.需要更多的CPU资源,3.浮动垃圾问题,需要更大的堆空间 重视服务的响应速度,系统停顿时间和用户体验的互联网或者B/S架构系统。互联网后端目前CMS是主流的垃圾回收器 G1 跨新生代和老年代;标记整理+化整为零 并行与并发收集器 JDK1.7才正式引入,采用分区回收的思维,基本不牺牲吞吐量的前提下完成低停顿的内存回收;可预测的停顿是其最大的优势
网关(Gateway)
1、Gateway怎么实现鉴权校验的?
实现
GlobalFilter, Ordered接口,重写filter方法,获取请求头上的token,如果获取不到就直接返回指定提示信息,否则就解析,如果解析出错就表示是伪造的令牌直接返回,否则就放行。
2、oauth2.0有几种授权模式?
1、授权码认证
1、
用户访问客户端,后者将前者导向认证服务器。2、用户选择是否给予客户端授权。
3、假设用户给予授权,认证服务器将用户导向客户端事先指定的"重定向URI"(redirection URI),同时附上一个授权码。
4、客户端收到授权码,附上早先的"重定向URI",向认证服务器申请令牌。这一步是在客户端的后台的服务器上完成的,对用户不可见。
5、认证服务器核对了授权码和重定向URI,确认无误后,向客户端发送访问令牌(access token)和更新令牌(refresh token)。
2、密码式
1、
用户向第三方客户端提供,其在服务提供商那里注册的账户名和密码2、客户端将用户名和密码发给认证服务器,向后者请求令牌access_token
3、授权认证服务器确认身份无误后,向客户端提供访问令牌access_token
3、隐藏式
1、
用户访问客户端,需要使用服务提供商(微信)的数据,触发客户端相关事件后,客户端拉起或重定向到服务提供商的页面或APP2、用户选择是否给予第三方客户端授权访问服务提供商(微信)数据的权限
3、用户同意授权,授权认证服务器将访问令牌access_token返回给客户端,并且会拉起应用或重定(redirect_uri)向到第三方网站
4、第三方客户端向资源服务器发出请求资源的请求;
5、服务提供商的资源服务器返回数据给客户端服务器,然后再回传给客户端使用;
4、客户端凭证
1、
客户端向授权认证服务器进行身份认证,并申请访问临牌2、授权认证服务器验证通过后,向客户端提供访问令牌