1

输入URL到页面显示的流程2

 1.浏览器根据输入的url用dns解析出ip地址2.浏览器根据ip地址和端口号与服务器进行tcp连接。3.建立完连接之后浏览器根据请求信息发送http请求给服务器。4.服务器处理完信息之后响应信息和html代码给浏览器。5.浏览器解析html代码,并请求html代码中的资源。6.浏览器对页面进行渲染给用户。

TCP/UDP协议

tcp协议是Transmission Control Protocol,传输控制协议。是一种面向连接的协议。
主要有三次握手协议和四次挥手。

三次握手:

  1.客户端向服务器端发送syn=1标识 seq=x,比如x=1。2.服务器收到客户端的标识信息之后,将标识信息syn=1,和ack=x+1,seq=y发送给客户端。3.客户端在收到自己的syn信息之后,已经之后我发的信息服务器已经收到,又收到了服务器端发的ack信息,然后将ack=y+1,seq=z发送给服务器端。4.服务器端收到自己发送的确认信息ack之后,知道客户端也收到了自己发送的信息,然后就可以进行传输信息了。

四次挥手:

(1)主动方发送一个FIN=1,ack=z,seq=x,用来关闭A到服务器B的数据传送。(2)被动方收到这个FIN=1,它发回一个ACK=x+1,seq=z。(3)被动方没有数据发送给主动方时,也是发送一个FIN=1,ack=x,seq=y。(4)主动方收到这个fin之后,发送ack=y+1,seq=x。

1.为什么建立连接协议是三次握手,而关闭连接却是四次握手呢?

这是因为服务端的listen监听到socket连接之后,它可以把ack和syn一起发送,
ack起应答,syn起同步作用。而关闭连接时,fin和ack不能一起发送。在收到fin时,
仅代表对方没有数据发送给你,并不代表我们完全把数据发送给对方,所以不能立
马去关闭,再发送fin给对方的时候才代表你同意关闭连接,所以这里ack和fin是分开发送的。

2.为什么TIME_WAIT状态还需要等2MSL后才能返回到CLOSED状态?

TIME_WAIT状态由两个存在的理由。
(1)可靠的实现TCP全双工链接的终止。

按理双发都同意关闭连接了,这个时候就可以关闭了就到了CLOSED状态,
但是我们要考虑到最坏情况,你无法保证你最后的ack一定会被对方收到,
因此对方处于last_ack状态下的socket,可能因为超时未收到ack报文,
而重发fin报文,所以这个time_wait状态的作用就是用来重发可能丢失的ack报文。
  1. 为什么不能用两次握手进行连接?

     这是因为三次握手主要完成两项工作,数据准备和序列号进行协商。我们假设使用两次握手,可能会发生死锁问题。客户端发送连接请求到服务器,服务器收到请求之后,发送答分组,认为已经成功建立连接。而服务器发送给客户端的应答报文丢失了。客户端会认为自己发送的连接请求没有收到应答,会忽略服务器发送的任何数据分组。只等待确认应答分组,而s认为已经连接成功了,就发送数据分组了,就造成了死锁。
    

udp协议是User Data Protocol,用户数据报协议,是一种无连接的协议。

Spring的AOP和Ioc

    aop面向切面编程,系统中有各个功能,使用aop相当于把各个功能分割开来,降低耦合度,提高重用性,同时提高开发效率。通俗方式就是在不修改,源代码的情况下,增加新的功能。IOC控制反转,就是把对象的创建的权利不再交给调用者,而是交给spring容器进行管理,spring容器会负责控制程序之间的关系,而不是由程序调用者进行处理,这样控制权就由应用程序代码交给spring容器,控制权就发生了转变,这就是控制反转。DI 依赖注入,从spring容器的角度看,spring容器负责将被依赖对象赋值给调用者的成员 变量,这就相当于调用者注入了它的依赖的成员,这就是spring的依赖注入。

Spring中Bean的生命周期(BeanProcessBefore和BeanProcessAfter)

    1.实例化bean(加载spring的配置文件,只有bean的作用域scop为singleton时,才会加载到内存)2.设置属性值 (调用bean的set方法进行赋值,前提是要用对应的set方法)3.调用BeanNameAware 的setBeanName() 方法。而采用BeanFactory 加载的配置文件只会加载spring容器,只有获取bean的时候才会实例化一个bean。4.调用BeanFactoryAware 的setBeanFactory方法5.调用ApplicationContextAware的setApplicationContext方法6.调用BeanPostProcessor的postProcessBeforeInitialization 方法7.调用InitializingBean的afterPropertiesSet方法8.调用自己实现的init方法9.调用BeanPostProcessor 的postProcessAfterInitialization10.调用自己bean所用到的方法。11.调用销毁方法。

数据库事务

    事务是数据库中的一组操作序列,要么都成功,要么都失败。

数据库的ACID特性

   atomic 原子性 一个事务要么都执行,要么都失败,不能只执行其中的一部分,这就是事务的原子性。consistency 一致性: 一个事务在执行前和执行后数据库状态都应该保持一致性状态。如果数据库在运行过程中发生故障,有些事务被迫中断了,一部分修改的已经写入数据库中,这就是不一致的状态。isolation 隔离性: 是指事务与事务之间相互隔离不互相影响。durability 持久性: 是指事务一旦执行成功,对数据库的修改就是永久的,即使遇到故障时也不会丢失。 

事务传播特性

    1.required 如果已经存在一个事务,则就加到这个事务中,如果当前没有事务,就新建一个事务,这就是默认事务传播设置。2.supports 代表如果已经存在一个事务,就加到这个事务中,否则就以非事务的方式运行。3.mandatory 如果存在一个事务,就加入到这个事务中,否则刨出一个异常。4.requireds_new 如果存在一个事务,就把这个事务挂起。5.not_supports 如果存在这个事务,就把这个事务挂起,以非事务方式运行。6.never 如果存在这个事务,就抛出异常,如果当前没有事务就已非事务方式运行。7.nested 代表创建当前事务的子事务。

MySQL数据引擎

1、 存储结构
MyISAM:每个MyISAM在磁盘上存储成三个文件
> .frm(文件存储表定义)
> MYD(MYData,存储数据文件)
> MYI(MYIndex,存储索引文件)
InnoDB:InnoDB表的大小只受限于操作系统文件的大小,一般为2GB。一般为.ibd
2、 存储空间
MyISAM:可被压缩,存储空间较小。
InnoDB:需要更多的内存和存储。
3、 可移植性、备份及恢复
MyISAM:数据是以文件的形式存储,所以在跨平台的数据转移中会很方便。在备份和恢复时可单独针对某个表进行操作。
InnoDB:可以是拷贝数据文件、备份 binlog,或者用 mysqldump。
4、 事务支持
MyISAM:强调的是性能,每次查询具有原子性,其执行速度比InnoDB类型更快,但是不提供事务支持。
InnoDB:提供事务支持事务,外键等高级数据库功能。 具有事务(commit)、回滚(rollback)和崩溃修复能力(crash recovery capabilities)的事务安全(transaction-safe (ACID compliant))型表。
5、 联合索引
MyISAM:可以和其他字段一起建立联合索引。引擎的自动增长列必须是索引,如果是组合索引,自动增长可以不是第一列,他可以根据前面几列进行排序后递增。
InnoDB:InnoDB中必须包含只有该字段的索引。引擎的自动增长列必须是索引,如果是组合索引,自动增长也必须是组合索引的第一列。
6、 表锁差异
MyISAM:只支持表级锁,用户在操作MyISAM表时,select,update,delete,insert语句都会给表自动加锁,如果加锁以后的表满足insert并发的情况下,可以在表的尾部插入新的数据。
InnoDB:支持表锁和行级锁,是InnoDB的最大特色。行锁大幅度提高了多用户并发操作的新能。但是InnoDB的行锁,只是在Where的条件是索引是有效的,非索引的WHERE都会锁全表的。
“innodb默认是行锁,前提条件是建立在索引之上的。如果筛选条件没有建立索引,会降级到表锁。即如果where条件中的字段都加了索引,则加的是行锁;否则加的是表锁。下面我们从几个方面对比下行锁和表锁”
7、 全文索引
MyISAM:支持 FULLTEXT类型的全文索引
InnoDB: 都支持。
8、 表主键
MyISAM:允许没有任何索引和主键的表存在,索引都是保存行的地址。
InnoDB:如果没有设定主键或者非空唯一索引,就会自动生成一个6字节的主键(用户不可见),数据是主索引的一部分,附加索引保存的是主索引的值。
9、 表的具体行数
MyISAM:保存有表的总行数,如果select count(*) from table;会直接取出出该值。
InnoDB:没有保存表的总行数,如果使用select count(*) from table;就会遍历整个表,消耗相当大,但是在加了where条件后,MyISAM和InnoDB处理的方式都一样。
10、 CURD操作
MyISAM:如果执行大量的SELECT,MyISAM是更好的选择。
InnoDB:如果你的数据执行大量的INSERT或UPDATE,出于性能方面的考虑,应该使用InnoDB表。DELETE 从性能上InnoDB更优,但DELETE FROM table时,InnoDB不会重新建立表,而是一行一行的删除,在innodb上如果要清空保存有大量数据的表,最好使用truncate table这个命令。
11、 外键
MyISAM:不支持
InnoDB:支持通过上述的分析,基本上可以考虑使用InnoDB来替代MyISAM引擎了,原因是InnoDB自身很多良好的特点,比如事务支持、存储过程、视图、行级锁定等等,在并发很多的情况下,相信InnoDB的表现肯定要比MyISAM强很多。另外,任何一种表都不是万能的,只用恰当的针对业务类型来选择合适的表类型,才能最大的发挥MySQL的性能优势。如果不是很复杂的Web应用,非关键应用,还是可以继续考虑MyISAM的,这个具体情况可以自己斟酌。

事务的隔离级别

脏读:当一个事务更新一个数据的时候,没有提交事务,而另一个事务读到了我更新的数据。 读未提交的数据。不可重复读:当一个事务查询了多次,第一次查询到的数据和第二次查询到的数不一致是因为中间的过程中有人把他改调了,导致的。 读不回去。幻读: 一个事务多次查询发现,查询出原来没有的记录,是因为中间有事务做了insert语句。-------------------------------1--读未提交 可能会造成脏读2--读已提交  就避免了脏读,但是可能会造成幻读,和不可重复读。4--可以重复读  避免了脏读和不可重复读,但是可能会造成幻读。8--串行话  所有的问题都可以避免。默认级别是读可重复读。

mysql的索引

1.普通索引唯一的任务就是是加快对数据的访问速度(由关键字KEY或INDEX定义的索引),
因此应该只为那些最经常出现的条件中创建。允许索引列的值重复。2.唯一索引:不允许重复的索引列,如果重复的话,不允许插入,人们创建唯一索引的目的往往不是为了提高访问速度,
而只是为了避免数据出现重复。3.主索引:主索引与唯一索引的唯一区别是:前者在定义时使用的关键字是parmart而不是UNIQUE。4.外键索引:如果为某个外键字段定义了一个外键约束条件,MySQL就会定义一个内部索引来
帮助自己以最有效率的方式去管理和使用外键约束条件。5.复合索引:索引可以覆盖多个列,从左到右依次匹配。6.全文索引:主要用于检索单词中构成的较大字段中是否包含这些单词。 有了全文索引,就可以用SELECT查询命令去检索那些包含着一个或多个给定单
词的数据记录了。下面是这类查询命令的基本语法:SELECT * FROM tablenameWHERE match(column1, column2) against ('word1', 'word2', 'word3')上面这条命令将把column1和column2字段里有word1、word2和word3的数据记录全部查询出来。

索引字段的要求(最多5个)

1.最左前缀匹配原则,非常重要的原则,mysql会一直向右匹配直到遇到范围查询(>、<、between、like)就停止匹配,比如a = 1 and b = 2 and c > 3 and d = 4 如果建立(a,b,c,d)顺序的索引,d是用不到索引的,如果建立(a,b,d,c)的索引则都可以用到,a,b,d的顺序可以任意调整。2.=和in可以乱序,比如a = 1 and b = 2 and c = 3 建立(a,b,c)索引可以任意顺序,mysql的查询优化器会帮你优化成索引可以识别的形式。3.尽量选择区分度高的列作为索引,区分度的公式是count(distinct col)/count(*),表示字段不重复的比例,比例越大我们扫描的记录数越少,唯一键的区分度是1,而一些状态、性别字段可能在大数据面前区分度就是0,那可能有人会问,这个比例有什么经验值吗?使用场景不同,这个值也很难确定,一般需要join的字段我们都要求是0.1以上,即平均1条扫描10条记录。4.索引列不能参与计算,保持列“干净”,比如from_unixtime(create_time) = ’2014-05-29’就不能使用到索引,原因很简单,b+树中存的都是数据表中的字段值,但进行检索时,需要把所有元素都应用函数才能比较,显然成本太大。所以语句应该写成create_time = unix_timestamp(’2014-05-29’)。5.尽量的扩展索引,不要新建索引。比如表中已经有a的索引,现在要加(a,b)的索引,那么只需要修改原来的索引即可。

慢查询优化基本步骤

0.先运行看看是否真的很慢,注意设置SQL_NO_CACHE1.where条件单表查,锁定最小返回记录表。这句话的意思是把查询语句的where都应用到表中返回的记录数最小的表开始查起,单表每个字段分别查询,看哪个字段的区分度最高2.explain查看执行计划,是否与1预期一致(从锁定记录较少的表开始查询)3.order by limit 形式的sql语句让排序的表优先查4.了解业务方使用场景5.加索引时参照建索引的几大原则6.观察结果,不符合预期继续从0分析

JVM的内存模型

    从线程方向来说可以分为共享区和独占区:线程共享的主要有方法区,堆区。方法区:主要用于存储类的一些信息,字段信息,方法信息,静态变量等,字符串量池,jdk1.7是在方法区,jdk1.8在元空间中。堆区:分为年轻代,老年代和元空间(1.8),之前的是永久代。线程独占的:虚拟机栈和本地方法栈,和pc。虚拟机栈:主要用于存储一个个栈帧,一个栈帧就是一个方法。栈帧中主要存储,局部变量表,操作数栈,动态链接,方法返回地址和一些附加信息。栈帧的作用有存储数据,部分过程结果,处理动态链接,方法返回值和异常分派。本地方法栈: 和虚拟机栈差不多,只不过都是本地方法。pc:指令寄存器,主要用于存储下一条指令的地址。

避免堆内存溢出/堆溢出怎么解决

1.看下是否是真的内存空间不足,另一个原因可能程序中有死循环。
2.可以通过调整堆的大小,来避免堆内存溢出,xms初始堆大小,xmx最大堆大小,一般设置一样。
3.优化程序设计。

ArrayList原理

动态可扩容的数组,底层使用的还是Object数组。不是线程安全的,适合查找,可以随机遍历。不适合插入和删除,不是线程安全的。
在add()方法中主要完成了三件事:首先确保能够将添加到集合中的元素能够添加到集合中,即确保ArrayList的容量(判断是否需要扩容);然后将元素添加到elementData数组的指定位置;最后将集合中实际的元素个数加1。
可以自动扩容,每次扩容为当前长度的1.5倍,第一次扩容是10。用的是add和get方法,get方法首先会检查索引大于数组长度的。

HashMap中Put的原理

部分成员变量如下:
//初始值,为16,必须为2的次幂
static final int DEFAULT_INITIAL_CAPACITY = 1 << 4;
//当容量被占满0.75时就需要reSize扩容
static final float DEFAULT_LOAD_FACTOR = 0.75f;
//链表长度到8,就转为红黑树
static final int TREEIFY_THRESHOLD = 8;
// 树大小为6,就转回链表
static final int UNTREEIFY_THRESHOLD = 6;
// 参数onlyIfAbsent表示是否替换原值
// 参数evict我们可以忽略它,它主要用来区别通过put添加还是创建时初始化数据的
final V putVal(int hash, K key, V value, boolean onlyIfAbsent,boolean evict) {Node<K,V>[] tab; Node<K,V> p; int n, i;// 空表,需要初始化if ((tab = table) == null || (n = tab.length) == 0)// resize()不仅用来调整大小,还用来进行初始化配置n = (tab = resize()).length;// (n - 1) & hash这种方式也熟悉了吧?都在分析ArrayDeque中有体现//这里就是看下在hash位置有没有元素,实际位置是hash % (length-1)if ((p = tab[i = (n - 1) & hash]) == null)// 将元素直接插进去tab[i] = newNode(hash, key, value, null);else {//这时就需要链表或红黑树了// e是用来查看是不是待插入的元素已经有了,有就替换Node<K,V> e; K k;// p是存储在当前位置的元素if (p.hash == hash &&((k = p.key) == key || (key != null && key.equals(k))))e = p; //要插入的元素就是p,这说明目的是修改值// p是一个树节点else if (p instanceof TreeNode)// 把节点添加到树中e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);else {// 这时候就是链表结构了,要把待插入元素挂在链尾for (int binCount = 0; ; ++binCount) {//向后循环if ((e = p.next) == null) {p.next = newNode(hash, key, value, null);// 链表比较长,需要树化,// 由于初始即为p.next,所以当插入第8个元素才会树化if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1sttreeifyBin(tab, hash);break;}// 找到了对应元素,就可以停止了if (e.hash == hash &&((k = e.key) == key || (key != null && key.equals(k))))break;// 继续向后p = e;}}// e就是被替换出来的元素,这时候就是修改元素值if (e != null) { // existing mapping for keyV oldValue = e.value;if (!onlyIfAbsent || oldValue == null)e.value = value;// 默认为空实现,允许我们修改完成后做一些操作afterNodeAccess(e);return oldValue;}}++modCount;// size太大,达到了capacity的0.75,需要扩容if (++size > threshold)resize();// 默认也是空实现,允许我们插入完成后做一些操作afterNodeInsertion(evict);return null;
}
1.对 key 的 hashCode()做 hash,然后再计算 index;2.如果没碰撞直接放到 bucket 里;3.如果碰撞了,以链表的形式存在 buckets 后;4.如果碰撞导致链表过长(大于等于 TREEIFY_THRESHOLD),就把链表转换成红黑树;5.如果节点已经存在就替换 old value(保证 key 的唯一性)6.如果 bucket 满了(超过 load factor * current capacity),就要 resize。
1.首先,会将key值进行散列掉,将hashcode码进行高16位和低16位进行异或运算,主要是用来减少碰撞,进一步降低hash冲突的几率。为什么要异或运算?如果不这样做,而是直接做&运算那么高十六位所代表的部分特征就可能被丢失,而采用异或运算的话,高十六位和低十六位的特征可以被保留下来。如果采用&运算计算出来的值会向1靠拢,采用|运算计算出来的值会向0靠拢。

为什么扩容两倍

HashMap计算添加元素的位置时,使用的位运算(n-1)&hash
n是map的容量,这是特别高效的运算;另外,HashMap的
初始容量是2的4次幂,扩容也是2倍的形式进行扩容,是因为容量是2的n次幂,可以使得添
加的元素均匀分布在HashMap中的数组上,减少hash碰撞,避免形成链表的结构,使得查询效率降低!

B树

1.一个m阶的B树最多有m颗子树。
2.根节点不是叶子节点的,最少有两个子树。
3.每个非终端节点最少有m/2个字树。
4.每个非终端节点最多有m-1个关键字。
5.所有叶子节点都在同一层。b树的优点是多路,平衡。

concurrentHashMap的原理

之前是分段锁的思想,通过采用分段锁Segment减少热点域来提高并发效率。
1.8利用CAS+Synchronized来保证并发更新的安全,底层采用数组+链表+红黑树的存储结构。
1.  key与value都不能为null
2. spread计算key的hash值。(h ^ (h >>> 16)) & HASH_BITS;//0x7fffffff;
保证了hash >= 0.
3.循环+cas,循环cas是Java相较于synchronized的另一种锁实现,之前文章介绍过。如果tab == null执行initTable操作,上面介绍过。利用tabAt取出i处头节点赋给f,若为null则利用casTabAt设置头节点。若f的hash == MOVED,说明有线程在i处正在执行扩容操作,执行helpTransfer,该线程帮助执行扩容任务,之后再新数组中再添加值。以上情况都不是,利用synchronized 锁住头节点f确保线程安全,区分是链表还是树,执行插入操作;如果是链表,那么在遍历过程中++binCount,最后如果binCount > 8,调用treeifyBin树化
4.在成功插入了一个新的元素后,addCount会被调用,这个方法一共做了两件事,增加个数,扩容。
关于插入的线程安全:插入位置为空则利用CAS来将新Node赋给table
[ i ],否则synchronized锁住头节点对象,后序对该位置链/树的更改由锁保护。concurrentHashMap与HashTable 相比,hashTable是通过synchronized 进行加锁,锁住的是整个map,而concurrentHashMap是通过锁分离,分段锁进行

synchronized和ReentrantLock

悲观锁:顾明思意,当这个线程去访问资源的时候,它总是会担心这个数据会被修改,所以在访问之前会加一把锁。
乐观锁:也是顾明思义,总是持有乐观的态度,总是认为这个数据不会被修改,所以不会
加锁,当时在更新的时候会判断一下在此期间别人又没有更新数据。
synchronized是非公平锁。

synchronized有三种应用方式:

作用于实例方法,当前实例加锁,进入同步代码前要获得当前实例的锁;作用于静态方法,当前类加锁,进去同步代码前要获得当前类对象的锁;作用于代码块,对括号里配置的对象加锁。2.实现原理
Synchronized进过编译,会在同步块的前后分别形成monitorenter和monitorexit这个两个
字节码指令。在执行monitorenter指令时,首先要尝试获取对象锁。如果这个对象没被
锁定,或者当前线程已经拥有了那个对象锁,把锁的计算器加1,相应的,在执行monitore
xit指令时会将锁计算器就减1,当计算器为0时,锁就被释放了。如果获取对象锁失败,那
当前线程就要阻塞,直到对象锁被另一个线程释放为止。
reentrantlock默认是非公平锁,设置为true的时候是公平锁。公平锁效率有点低。公平锁: 是指在多个线程按照申请锁的顺序来获取锁,类似排队,先来后到。
非公平锁: 是指在多个线程获取锁的顺序并不是按照申请锁的顺序,有可能后申请的先
执行,在高并发情况下,有可能会造成优先级反转,或者饥饿现象 。可重入锁(也叫做递归锁): 指的是同一个线程外层函数获得锁之后,内层递归函数仍然能
获得锁,在同一个线程在外层方法获取锁的时候,在进入内层方法会自动获得锁。
也就是说,线程可以进入任何一个它已经拥有的锁的方法中。自旋锁(spinlock): 是指尝试获取锁的线程不会立即阻塞,而是通过采用循环的方式尝试获取锁,这样的好处是减少线程上的消耗,缺点是会循环损耗cpu。
public class SpinLock {private AtomicReference<Thread> cas = new AtomicReference<Thread>();public void lock() {Thread current = Thread.currentThread();// 利用CASwhile (!cas.compareAndSet(null, current)) {// DO nothing}}public void unlock() {Thread current = Thread.currentThread();cas.compareAndSet(current, null);}
}
独占锁:是指该锁一次只能被一个线程所持有,对reentrantlock和synchronized而言都是独占锁。共享锁:是指可以被多个线程所持有。
对reentrantreadwritelock起读锁是共享的,写锁是独占的。
读锁的共享锁可保证并发读是非常高效的,读写 ,写读,谢谢的过程是互斥的。reentrantReadWriteLock,主要有4种情况,读读,能够共存,读写,不能共存,写读也不能共存,写写也不能共存。
写操作: 独占+原子 整个过程中,必须是一个完整的统一体,中间不许被分割,被打断。CountDownLatch 通过构造器进行传值,主要用来做减法,通过countDownLatch.countDown()等值到答0的时候,countDownLatch.await方法才能往下走。CyclicBarrier构造函数是传一个int的值,和一个runable接口,cyclicBarrier阻塞的
次数达到给的数值时,才会执行cyclicBarrier传的线程的run方法。Sempaphore 是信号量机制,多个线程竞争多个资源。也是非公平锁,可以在构造方法中传
资源数量,让其他线程进行阻塞。

sync锁升级过程

无锁状态、偏向锁状态、轻量级锁状态和重量级锁状态锁只能升级不能降级。1.偏向锁偏向锁就是顾名思义,偏向于第一个访问的线程,如果在运行过程中,同步锁只有一个线程访问,不存在竞争资源的情况,则线程是不需要触发同步的,减少加锁/解锁的一些操作,这种情况下就会给线程加一个偏向锁。如果,遇到其他线程抢占的情况下,偏向锁挂起,恢复起轻量级锁。当一个线程访问同步块并获取锁时,会在对象头和栈帧的锁记录里记录存储偏向的线程id,以后该线程在进入和退出同步代码块时不需要进行CAS操作来进行加锁和解锁,只需要看Mark Word里线程id是否是当前线程就可以了,如果测试成功就获得了锁,如果测试失败就需要判断偏向锁的标识了,如果标识为0是无锁状态,则使用cas设置为1,表示偏向锁,然后尝试使用cas将对象的头的偏向锁指向当前线程,触发偏向锁的撤销。偏向锁只有在竞争锁的时候才会释放锁。当其他线程竞争偏向锁时,程序到达安全点后(没有执行的代码),它会查看java对象头的记录的线程又没有存活,如果没有存活,则锁对象被重置为无锁,其他线程可以竞争。如果存活,那么会查看该线程的栈帧信息,如果还是需要继续持有这个锁的对象,那么暂停当前线程,撤销偏向锁,升级为轻量级锁。如果线程1不再使用该锁对象,那么会将该锁设置为无锁,重现偏向新的线程。2.轻量级锁由轻量锁切换到重量锁,是发生在轻量锁释放锁的期间,之前在获取锁的时候它拷贝了锁对象头的markword,在释放锁的时候如果它发现在它持有锁的期间有其他线程来尝试获取锁了,并且该线程对markword做了修改,两者比对发现不一致,则切换到重量锁。线程执行同步块之前,jvm会先在当前线程的栈帧中创建用于存储记录的空间,并将对象头的markword复制到锁的记录中。然后尝试获取使用cas将对象头中的markword替换为记录的指针。如果成功,当前线程获得锁。如果失败,表示其他线程在竞争锁,当前线程会通过自旋来获取锁。当自旋达到一定次数之后,锁升级为重量级锁。轻量级锁解锁时,会使用cas操作将displaced mark word 替换回到对象头,如果成功表示没有竞争,如果 失败,表示当前锁存在竞争,锁已经被升级为重量级锁 ,则会释放并唤醒等待的线程。

线程池(扩容过程,核心线程数达到最大,阻塞队列最大,才会创建线程)

使用线程池的好处 ,方便管理线程,避免了资源的消耗。

(1)降低资源的消耗。通过重复利用已经创建的线程降低线程创建和销毁造成的消耗。

(2)提高响应速度。当任务到达时,任务可以不需要等线程创建就能立即执行。

(3)提高线程可管理性。线程是稀缺资源,如果无限制的创建,不仅会消耗系统资源,还会降低系统的稳定性,使用线程池可以进行统一的分配,调优和监控。

public ThreadPoolExecutor(int corePoolSize,  int maximumPoolSize,  long keepAliveTime,  TimeUnit unit,  BlockingQueue<Runnable> workQueue,  ThreadFactory threadFactory,  RejectedExecutionHandler handler)
corePoolSize 核心线程数,是在线程没有用到的时候也不会回收。maximumPoolSize 最大线程数,包含核心线程数,剩下的是非线程核心数。keepAliveTime 就是非核心线程数最长保存时间,因为在线程池中,除了核心线程数,
其他线程在没有使用的时候会被清除,意思就是非核心线程数的最大空闲时间。TimeUnit 时间单位BlockingQueue 工作队列,
任务可以被存储在队列中等待被执行,按照先来先服务的原则。ThreadFactory 线程工厂,创建线程的工厂。RejectedExecutionHandler 拒绝策略,可以在任务满的时候,执行拒绝策略。线程池的执行流程:提供者提供任务-》线程池1.查看核心线程池是否已满,如果未满,创建线程执行任务。否则查看工作队列是否已满。如果未满,就放入到工作队列中,等待执行,如果满了,查看最大线程数是否已满。如果未满,创建线程执行任务。如果满了,就执行拒绝策略。

线程池拒绝策略handler的拒绝策略:

        有四种:第一种AbortPolicy:不执行新任务,直接抛出异常,提示线程池已满第二种DisCardPolicy:不执行新任务,也不抛出异常第三种DisCardOldSetPolicy:将消息队列中的第一个任务替换为当前新进来的任务执行第四种CallerRunsPolicy:直接调用execute来执行当前任务

面向对象的特性

封装:就是把一个类的属性和实现的细节隐藏起来,仅对外提供可访问的接口,进行访问。
继承:就是子类继承父类的功能和特性,使得子类的实例能够拥有父类的属性和方法,
具有相同的行为,如果父类是私有的则不能拥有。还可以对父类的功能进行扩展。
多态:指的是运行过程中,不同对象对同一消息所做出的不同响应,多态的必要条件:
继承,重写,实现。
抽象:就是对具有相同特征和行为方法的抽取。

抽象类和接口区别

1.抽象类用abstract关键字声明,接口用interface。
2.抽象类可以有抽象方法和普通方法也可以有普通属性,抽象类不可以实例化,只能被
继承。而接口也可以有默认实现方法。
3.抽象类一般用于模板和普通的java类没有什么区别,只是不能实例化,而接口都是抽
象方法的集合一般用于定义,默认接口的修饰符是public。

设计模式原则

1.单一职责原则:对类来说,即一个类应该保持一项职责。
2.接口隔离原则:客户端不应该依赖它不需要的接口上,即一个类对另一个类的依赖应该
建立最小的接口上。
3.依赖倒转原则:1.高层模块不应该依赖底层模块,二者都应该依赖其抽象。2.抽象不依赖于细节,应该细节依赖于抽象。3.依赖倒转的中心思想是面向接口编程4.依赖倒转原则是基于这样的设计理念:相对于细节的多变性,抽象的东西要稳定的多,以抽象为基础搭建起来的框架,比实现搭建起来的框架要稳定的多。在java中抽象就是指抽象类和接口,而细节指实现类。
4.里氏替换原则:简单说就是子类能够替换父类存在的地方 ,并且不会影响。
5.迪米特法则:1.一个对象应该对其他对象保持最少的了解。2.类与类的关系越密切, 耦合度越高。3.迪米特法则又叫最少知道原则,即一个类对自己依赖的类知道的越少越好,也就是说对于被依赖的类不管逻辑多复杂。都封装在类的内部,对外仅提供可以访问的方法和接口。4.迪米特法则还有个简单的定义:只与直接朋友进行通信。直接朋友:就是只要两个对象之间有耦合关系,我们就说这两个对象之间是朋友关系。
6.开闭原则:对扩展开放,对修改关闭。不允许修改的是抽象类和接口,对实现类可以扩展。
7.合成复用原则:代码复用时,要尽量先使用组合或者聚合等关联关系来实现,其次才考虑使用继承关系来实现

单例模式

分为懒汉式,饿汉式。
饿汉式:顾名思义,先创建后使用,线程安全,占用内存。
懒汉式:用的时候才创建,线程不安全,加锁会影响效率。资源利用率高了,但是,每次调用getInstance()方法都要同步,并发效率较低。
静态内部类方式:也即饿汉式和懒汉式的组合,调用getInstance()方法时才创建,
达到了类似懒汉式的效果,同时又是线程安全的。
/*** 使用静态内部类方式实现单例模式* @author cui_yonghua  https://blog.csdn.net/cui_yonghua/article/details/90512943*/
public class ClassC {//1.私有化构造方法,使得在类的外部不能调用此方法,限制产生多个对象private ClassC(){ }//2.在类的内部创建一个类的实例private static class Holder{private static ClassC instance = new ClassC();}//3.对外部提供调用方法:将创建的对象返回,只能通过类来调用public static ClassC  getInstance(){return Holder.instance;}
}

快排算法思想(基准点的选取)

通过一趟排序将待排序序列分割成独立的两部分,其中一部分的关键字比另一部分的关
键字小,则可分别对这两部分记录继续进行排序,已达到整体序列有序。
import java.util.Arrays;public class Solution {public static void main(String[] args) {quickSort(new int[]{39,28,55,87,66,3,17,39});}public static void quickSort(int[] arr){quickSort(arr,0,arr.length-1);System.out.println(Arrays.toString(arr));}public static void quickSort(int[] arr,int left,int right){int middle;if(left < right){middle = partition(arr,left,right);quickSort(arr,left,middle-1);quickSort(arr,middle+1,right);}}public static int partition(int[] arr,int left,int right){int pivot = arr[left];while(left < right){while(left<right && arr[right] >= pivot)right--;arr[left] = arr[right];while(left < right && arr[left]<= pivot)left++;arr[right] = arr[left];}arr[left] = pivot;return left;}
}

Redis的ZSet底层数据结构

zset的底层数据结构包括两个ziplist和skiplist使用ziplist作为数据结构的时候要满足两种情况:1.有序集合保存的元素个数要小于128个。2.有序集合保存的所有元素长度要小于64字节。[link]( https://www.jianshu.com/p/fb7547369655)

2

一面

页面置换算法

最佳适应算法opt,设计一下

现实中不存在的一种算法,最佳置换算法,从主内存中移除不再需要的页面,如果没有
这样的页面,则将最长时间内不适用的页置换出去。

先进先出页面置换算法(FIFO):

是最简单的页面置换算法,这种算法的思想是:当需要淘汰一个页面时,将最先进来的页
面进行置换出去。理由是:最先进来的页面不再使用的可能性最大。FIFO算法还会产生当所分配的物理块数增大而页故障数不减反增的异常现象,称为Belady异常

最近最久未使用算法(LRU)

    这种算法的思想是局部思想,根据最近一个作业的执行过程中过去的页面访问历史,来推测未来的一些行为。它认为在过去一段时间里不曾访问过的,未来也不会访问。当选择置换页的时候总是选择在最近的一段时间内最久不用的页面予以淘汰。

时钟置换算法:

LRU的性能接近于opt,但是实现起来困难,开销比较大,FIFO实现起来简单,但是性能
比较差,所以操作系统的设计者尝试了很多算法,试图用比较小的开销接近于lru的性能,
这类算法都称为clock算法。简单的clock的算法是给每一帧关联一个附加位,称为使用位。当某一页首次装入时,该
帧的使用位设置为1,当该页随后再被访问时,它的使用位也被置为一,对于页替换算法,
用于替换的候选帧集合看做一个循环缓冲区,并且有一个指针与之相关联,当某一页被替换时,该指针被设置成指向缓冲区中的下一帧,当需要置换时,则扫描使用位为0的位置。
每当遇到一个使用位为1的帧时,操作系统就将该位重新置为0;如果在这个过程开始时,
缓冲区中所有帧的使用位均为0,则选择遇到的第一个帧替换;如果所有帧的使用位均为1,
则指针在缓冲区中完整地循环一周,把所有使用位都置为0,并且停留在最初的位置上,替
换该帧中的页。由于该算法循环地检查各页面的情况,故称为CLOCK算法,又称为最近未用(Not Recently Used, NRU)算法。

细聊多态

多态:指的是运行过程中,指的是不同对象对同一消息所作出的不同响应。
多态的必要条件:继承,实现二选一重写向上转型:也称为父类引用指向子类对象,首先会查看父类中是否有该方法,如果没有则编译报错,如果有子类也有,指向子类对象的方法。向下转型:向下转型的必须要先向上转型,才能向下转型,不然会报类型转换异常。[link](https://blog.csdn.net/Ricardo18/article/details/109046496?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-2.control&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-2.control)

SELECT * 会导致索引失效吗?,为什么要少用SELECT *

其实会不会导致索引失效跟select*没有什么关系。索引失效最主要的是看where条件后
面是不是遇到了非索引字段或者遇到了范围查询。
因为用select* 会导致额外的io开销。

聚簇索引和非聚簇索引

聚簇索引就是根据主键创建的一个B+树,叶子节点中存放的就是该表中的记录数据。
一般建表会用一个自增主键来创建聚簇索引,如果没有的话,mysql会帮我们默认创建。
innobd中的主键索引是一种聚簇索引,非聚簇索引都是辅助索引,像复合索引、前缀索引、唯一索引。Innodb通过主键聚集数据,如果没有定义主键,innodb会选择非空的唯一索引代替。如果没有这样的索引,innodb会隐式的定义一个主键来作为聚簇索引。聚簇索引的优缺点优点:1.数据访问更快,因为聚簇索引将索引和数据保存在同一个B+树中,因此从聚簇索引中获取数据比非聚簇索引更快2.聚簇索引对于主键的排序查找和范围查找速度非常快缺点:1.插入速度严重依赖于插入顺序,按照主键的顺序插入是最快的方式,否则将会出现页分裂,严重影响性能。因此,对于InnoDB表,我们一般都会定义一个自增的ID列为主键2.更新主键的代价很高,因为将会导致被更新的行移动。因此,对于InnoDB表,我们一般定义主键为不可更新。3.二级索引访问需要两次索引查找,第一次找到主键值,第二次根据主键值找到行数据。辅助索引(非聚簇索引)在聚簇索引之上创建的索引称之为辅助索引,辅助索引访问数据总是需要二次查找。辅助索引叶子节点存储的不再是行的物理位置,而是主键值。通过辅助索引首先找到的是主键值,再通过主键值找到数据行的数据页,再通过数据页中的Page Directory找到数据行。

假设大表,如果使用Delete语句删除数据库一条记录,执行速度怎么样,为什么

使用delete操作会写入大量日志文件,导致删除数据时性能下降。建议使用tuncate,
但是使用tuncate不记录日志,无法回滚,没有办法恢复数据。

Redis 怎样实现分布式锁,发生死锁了怎么办?

可以通过redis的setnx命令设置分布式锁,在java中是通过redisTemplate.opsForValue().setIfAbsent(key, value);来获取锁。
『避免死锁』,就是给锁加了一个过期时间,如果锁超时了,就返回true,解开之前的那个死锁。

HTTP 状态码

200 成功的状态
404 服务器找不到请求的网页
500 服务器错误

503错误是为什么,怎么解决

是服务器目前无法使用,可能由于超载或停机维护。通常这是暂时的错误。
重启网站应用程序池

进程和线程的区别

进程是操作系统的基本单位,一个进程代表了一个应用程序,一个进程包含多个线程。
线程是程序执行的最小单位。多个线程共享进程的资源。

进程间通信,Socket具体实现

 先从服务器端说起。服务器端先初始化Socket,然后与端口绑定(bind),对端口进行监听(listen),调用accept阻塞,等待客户端连接。在这时如果有个客户端初始化一个Socket,然后连接服务器(connect),如果连接成功,这时客户端与服务器端的连接就建立了。客户端发送数据请求,服务器端接收请求并处理请求,然后把回应数据发送给客户端,客户端读取数据,最后关闭连接,一次交互结束。

线程间通信

1.线程上下文
2.共享内存
3.套接字

简单算法:括号匹配

如果是左括号就入栈,如果是右括号就出栈。

二面

项目具体

JVM内存模型

设计模式(单例、工厂、原型、观察者)

算法,IP地址和范围,让你查找IP存在不存在所给的IP空间里面

三面

1-10000,A+B=奇数,判断有多少种可能性。
有5000*5000

HTTP与webSocket的区别
websocket是基于一种新的网络协议。它实现了浏览器与服务器的全双工通信。

联系:
1.都是建立在tcp之上,通过tcp协议来传输数据。
2.都是应用层的协议
3.在连接的建立过程中对错误的处理方式相同,在这个阶段ws可能返回相同的返回码。
不同点:
1.ws的连接不能通过中间人来转发,它必须是一个直连接。
2.ws建立完连接之后,通信双发任何时候都可以向另一方发送数据。
3.ws连接建立之后,数据的传输使用帧进行传输,不再需要使用request。

Redis,单线程,为什么快,I/O多路复用技术

redis指的是网络请求模块使用了一个线程,是一个线程处理了所有网络请求,其它模块
仍使用了多线程的。因为redis使用的是内存存储数据,所以速度比较快。数据结构简单,对数据操作也方便。采用单线程避免了线程上下文的切换。多路复用io,非阻塞io。Linux下的select、poll和epoll就是干这个的。将用户socket对应的fd注册进epoll,然
后epoll帮你监听哪些socket上有消息到达,这样就避免了大量的无用操作。此时的socke
t应该采用非阻塞模式。这样,整个过程只在调用select、poll、epoll这些调用的时候才会阻塞,收发客户消息是不会阻塞的,整个进程或者线程就被充分利用起来,这就是事件驱动,所谓的reactor模式。

TCP滑动窗格

滑动窗口主要有发送窗口和接受窗口。在进行三次握手的时候就已经,接收方和发送就会
知道接收方的窗口大小。他们都有一个发送缓存池和接受缓存池中,滑动窗口就是在这
里。发送窗口主要是包含p1和p2之间的是已发送但没有收到确认的,p2到p3之间是可发送
窗口的大小。只有p1和p2之间收到确认信息之后,窗口才会向右进行移动。这样可以有效的进行流量控制,避免无节制的发送,造成网络拥塞。如果接收方,没有可
接受窗口的大小了,回告诉发送方,大小为0停止发送,等接收方好了,会通知发送方。
如果通知的消息丢失了,发送方会发送定时消息去进行试探。

3

  1. 线程池(超详细),为什么要用线程池?,核心线程可以回收吗?怎么回收。源码有。

    主要是避免资源的浪费,我们知道线程的创建销毁是极大浪费资源的,我们有了线程池就
    避免了重复创建线程造成的消耗,也便于统一管理。重复使用。

    线程池一共有7大参数:
    corepoolsize核心线程数,也就是常驻内存的线程。
    maxmumpoolsize 线程池允许创建的最大线程数
    keepalivetime 多余线程空闲时间
    TimeUnit 时间单位
    threadfactory 创建线程的工厂方法,用于创建线程
    workqueue 用于传输和等待的阻塞队列
    handler 拒绝策略
    主要有四大拒绝策略
    直接返回错误
    abortpoliy丢弃,直接抛出一个异常
    discardpolicy 直接丢弃,不抛出异常
    discardoldsetpolicy 丢弃队列中最前面的一个请求,然后重试该请求
    CallerRunsPolicy 有调用线程处理

    在ThreadPoolExecutor类中有个allowCoreThreadTimeOut(boolean value)方法,该方法用来设置是否回收在保活时间后依然没没有任务执行核心线程。
    设置为true可以回收

  2. synchronized理解,锁升级过程

    synchronized是java的关键字,是jvm层面的锁,是可重入锁,非公平锁,主要有无锁,偏向锁,轻量级锁
    重量级锁。
    无锁状态就是没有对资源进行锁定,所有线程都可以访问,但是只能有一个可以修改。
    偏向锁,顾名思义就是偏向于访问的第一个线程,偏向锁性能很高,会修改锁的标志位,
    第二个线程访问的时候会先判断是否是自己,如果是的话继续执行,如果不是的话,重新加锁。如果发生竞争的话,就升级为轻量级锁。轻量级锁就是通过自旋的方式获取锁,
    线程不会阻塞,从而提高性能。重量级锁,是轻量级锁自旋达到上限,竞争比较激烈的时候
    就会升级为重量级锁。重量级锁,是只有一个线程可以访问,其他线程进行阻塞。

  3. ReentrantLock详细,对比sync

    1.rentrantlock 是api层面的,是java的lock的一个实现类。而sync是java的关键字是jvm层面的。
    2.sync执行完,或者执行过程中抛出异常会释放锁,而reen不会,它只有在finally中释放。
    3.sync可以作用在方法上,代码块中,而reentrantlock只能在代码中。
    4.sync拿不到锁会一直等待,而reentrantlock可以设置超时时间。
    5.sync无法得知获取锁成功,而reentrantlock可以在trycatch中得知又没有加锁成功。
    6.sync是可重入锁,非公平锁,不可中断,而reentrantlock也是可重入锁,可中断,非公平/公平锁。并可以细分锁的粒度。

  4. Java整个类加载过程,运行时数据区,对象扭转过程。对象一定是15岁进入老年代嘛?不是,源码有。
    加载-连接-初始化-使用-卸载
    加载阶段就是将类编译成字节码文件,通过全类名的二进制流加载到虚拟机中。
    然后转化成方法区的运行时数据结构。生成一个代表类的Class对象。用于创建实例。
    连接阶段 主要有验证-尊卑-解析
    验证主要是验证是否Class的字节流是否符合jvm的规范。
    准备阶段 主要是为类定义的变量的静态变量和分配内存和变量初始值。
    解析 是java虚拟机将常量池内的符号引用替换为直接直接引用的过程。

    初始化 类的初始化阶段是类加载过程的最后一个阶段,会根据程序员附的值进行赋值吧。
    运行时数据区线程共享的有方法区,堆区,独占的有虚拟机栈,本地方法栈,程序计数器
    可以通过修改虚拟机的参数进行配置。

  5. 自己写的String类会被加载吗?如果想要加载怎么办
    不会。报名不以java开头就可以被加载。

  6. MySQL事务,ACID,隔离级别及引发问题,MVCC,读视图,对比read

    mvcc多版本的并发控制协议,它最大的有点就是读不加锁,因此读写不冲突,并发性能好。innodb实现mvcc,多个版本的数据可以共存,主要是基于以下技术及数据结构:
    1.隐藏列,每行数据都有隐藏列,包含事务id,undolog的指针等。
    2.基于undolog的版本链,都会指向更早版本的指针,形成指针链。
    3.readview通过隐藏列和版本链,可以恢复到指定版本的。所谓readview是指,事务在
    某一时候系统的定时快照。

  7. commit,实际举例加锁过程,涉及间隙锁
    间隙锁锁定的是一个范围,但是不包含记录的本身。它的作用就是为了阻止多个事务
    将记录插入到同一范围内,这就会导致幻读的问题产生。

  8. 读提交和可重复读性能区别,结合例子阐述

  9. webSocket原理

  10. 介绍网易实习工作经历及遇到的问题

  11. 导致索引失效场景

  12. MySQL与Redis数据一致性问题,延迟双删,原理。还有其他方式嘛?

  13. Spring中IOC

4

  1. 反向代理,死扣,结合网络来说(DNS)
  2. Redis持久化机制
  3. MySQL事务隔离级别详细讲及MVCC
  4. MySQL优化经验,SQL预计相关,索引相关
  5. Linux命令,根据文件第二列做统计,每个部门员工数量。awk,seed。不会。
  6. 给出一个有序数组,找到差值为x的所有组合。没写对。我傻了

5

  1. Redis 数据一直性问题

  2. MySQL 熟悉的客户端。同步/异步,是否会阻塞,会阻塞多久。不会。

  3. 线程池相关

  4. Reids不可用问题怎么解决。不会

  5. JVM运行时数据区

  6. 垃圾收集器

  7. 死锁及手撕死锁

  8. 算法:一条文本消息仅包含大写字母A-Z。对消息按下列方式编码:A编码为数字1,B编码为数字2,……,Y编码为数字2和5,Z编码为数字2和6。先给定编码后的数字序列,则能编码为该序列的消息可能有多少条?

    样例输入:226

    样例输出:3

    解释:可以编码为序列226的消息有3条:BZ(2,26)、VF(22,6)、BBF(2,2,6)

6

  1. 单台Redis压力大怎么解决。集群,分布式。如果就是单台呢?额。。。
  2. Redis集群实现的原理
  3. 类加载原理
  4. 对象可能直接进老年代嘛?什么情况下会
  5. 网易公司MySQL参数有了解过吗?木
  6. 聚集索引非聚集索引区别。出了个题,ABC索引问 AC和BC能不能走到索引
  7. 有没有用过Linux命令解决线上问题,木。但是给他扯了一点
  8. OOM的种类,原因

7

  1. 设计一个扫码登陆的解决方案
  2. 写一个普通的树的dfs和bfs
  3. MySQL服务是怎么处理死锁的
  4. Spring Boot相比其他有什么优点?依靠什么实现的?

8

OOM的排查过程

Linux系统进程的日志文件

使用分析工具(mat等)能精确定位到某一行代码错误?

JVM参数(栈、堆、GC)

垃圾回收器

细讲CMS和G1

场景题:实时性要求高的情况下用什么,为什么

HashMap jdk1.7与1.8

线程概念及实际使用到的,举例

线程池的参数

线程池submit后的过程

MySQL5.6与5.7的区别

MySQL各种索引及区别

MySQL存储引擎

场景:条件后有 a b c 三个条件,建什么索引,为什么

9

  1. 自我介绍
  2. Spring使用到的设计模式
  3. JVM内存模型
  4. 类加载过程
  5. GC ROOT根
  6. MySQL执行过程
  7. B-TREE索引
  8. 电脑CPU满了,怎么排查
  9. 洗牌算法(手写),等概率出现数组
  10. 数字中二进制1的个数(手写)
  11. 链表删除倒出第N个节点(手写),实现创建、打印、删除函数

10

MySQL

ajax轮询和websocket的区别

    Ajax轮询
ajax轮询十分简单,让浏览器每隔几秒就发送请求,询问服务器是否有新的信息。也就是
说,客户端发起连接后,如果没消息,就一直不返回Response给客户端。直到有消息才返
回,返回完之后,客户端再次建立连接,周而复始。(太过被动。服务器不能主动联系客
户端,只能由客户端发起)WebSocket
当服务器完成协议升级后(HTTP->Websocket),服务端就可以主动推送信息给客户端啦
。只需要经过一次HTTP请求,就可以做到源源不断的信息传送了。这样的协议解决了上面
同步有延迟,而且还非常消耗资源的这种情况。

MySQL存储引擎

索引

事务

隔离级别

MVCC

http状态码

Linux常用命令

SQL。两表关联查询。

算法:一个两个台阶问题

算法:树的最大深度

11

Redis和Mysql数据一致性问题,解决方案

读取缓存步骤一般没有什么问题,但是一旦涉及到数据更新:数据库和缓存更新,就容
易出现缓存(Redis)和数据库(MySQL)间的数据一致性问题。不管是先写MySQL数据库,再删除Redis缓存;还是先删除缓存,再写库,都有可能出现数据不一致的情况。举一个例子:
1.如果删除了缓存Redis,还没有来得及写库MySQL,另一个线程就来读取,发现缓存为空,则去数据库中读取数据写入缓存,此时缓存中为脏数据。2.如果先写了库,在删除缓存前,写库的线程宕机了,没有删除掉缓存,则也会出现数据不一致情况。因为写和读是并发的,没法保证顺序,就会出现缓存和数据库的数据不一致的问题。如来解决?这里给出两个解决方案,先易后难,结合业务和技术代价选择使用。1.第一种方案:采用延时双删策略
在写库前后都进行redis.del(key)操作,并且设定合理的超时时间。2.具体的步骤就是:1)先删除缓存2)再写数据库3)休眠500毫秒4)再次删除缓存从理论上来说,给缓存设置过期时间,是保证最终一致性的解决方案。所有的写操作以
数据库为准,只要到达缓存过期时间,则后面的读请求自然会从数据库中读取新值然后回填缓存。4.该方案的弊端结合双删策略+缓存超时设置,这样最差的情况就是在超时时间内数据存在不一致,而且又增加了写请求的耗时。2、第二种方案:异步更新缓存(基于订阅binlog的同步机制)1.技术整体思路:MySQL binlog增量订阅消费+消息队列+增量数据更新到redis1)读Redis:热数据基本都在Redis2)写MySQL:增删改都是操作MySQL3)更新Redis数据:MySQ的数据操作binlog,来更新到Redis2.Redis更新1)数据操作主要分为两大块:一个是全量(将全部数据一次写入到redis)一个是增量(实时更新)这里说的是增量,指的是mysql的update、insert、delate变更数据。2)读取binlog后分析 ,利用消息队列,推送更新各台的redis缓存数据。这样一旦MySQL中产生了新的写入、更新、删除等操作,就可以把binlog相关的消息推
送至Redis,Redis再根据binlog中的记录,对Redis进行更新。其实这种机制,很类似MySQL的主从备份机制,因为MySQL的主备也是通过binlog来实现
的数据一致性。这里可以结合使用canal(阿里的一款开源框架),通过该框架可以对MySQL的binlog进行
订阅,而canal正是模仿了mysql的slave数据库的备份请求,使得Redis的数据更新达到
了相同的效果。当然,这里的消息推送工具你也可以采用别的第三方:kafka、rabbitMQ等来实现推送
更新Redis。

Spring中scope数据取值及特点

sington spring容器只允许有一个实例对象,是spring默认的配置,每次获取值都是同一个对象。
prototype 每次调用都会产生一个对象的实例。
request 给每个http请求都会产生一个bean实例
session 给每一个httpsession 对象创建一个实例。
GlobalSession 这个只在portal应用中有用,给每一个global http session新建一个Bean实例。

ThreadLocal

可以通过ThreadLocal类来实现线程本地存储的功能。每一个线程的Thread对象中都有一
个 ThreadLocalMap对象,这个对象存储了一组以ThreadLocal.threadLocalHashCode为键
,以本 地线程变量为值的K-V值对,ThreadLocal对象就是当前线程的ThreadLocalMap的
访问入口,每 一个ThreadLocal对象都包含了一个独一无二的threadLocalHashCode值,
使用这个值就可以在 线程K-V值对中找回对应的本地线程变量。

Java中IO的种类及特点

    1. File(文件特征与管理):用于文件或者目录的描述信息,例如生成新目录,修改文件名,删除文件,判断文件所在路径等。2. InputStream(二进制格式操作):抽象类,基于字节的输入操作,是所有输入流的父类。定义了所有输入流都具有的共同特征。3. OutputStream(二进制格式操作):抽象类。基于字节的输出操作。是所有输出流的父类。定义了所有输出流都具有的共同特征。4.Reader(文件格式操作):抽象类,基于字符的输入操作。5. Writer(文件格式操作):抽象类,基于字符的输出操作。6. RandomAccessFile(随机文件操作):一个独立的类,直接继承至Object.它的功能丰富,可以从文件的任意位置进行存取(输入输出)操作。

重写和重载的区别
重写是发生在父类和子类之间,子类重写父类方法。方法名和参数要和父类保持一致,
访问修饰符要不比父类的权限小。
重载是发生在一个类中,是通过方法参数不同,参数顺序不同进行方法的重载。对权限没
有特别要求。

new Integer(1) 和 Integer.valueOf(1)的区别

new Integer(1) 是新建一个对象 而valueof是使用的缓存池中的数据,大小是-128 到127会返回同一个对象。

Spring bean的声明周期

final修饰符

修饰变量称为常量
修饰方法 表示改方法不可被重写
修饰类代表为终类,不可被继承
final修饰对象时,不可以再指向其它的对象,但是对象的内容是可以修改的。
final修饰传入方法的参数时,该参数只读,不可以修改。

String为什么是final修饰的类

之所以要把String类设计为不可变类,主要是出于安全和性能的考虑。
由于 String 天然 的不可变,当一个线程”修改“了字符串的值,只会产生一个新的字符串
对象,不会对其他线程的访问产生副作用,访问的都是同样的字符串数据,不需要任何同步操作。

因为要保证String类的不可变,那么将这个类定义为final的就很容易理解了。如果没有fi
nal修饰,那么 就会存在String的子类,这些子类可以重写String类的方法,强行改变字
符串的值,这便违背了String类 设计的初衷。

春招,秋招面试题总结相关推荐

  1. 春招/秋招面试前必看一文

    春节过完,不管是大三/研二.还是大四/研三,就要投入到最激烈的春招当中去了,各大公司将会正式招聘,由元旦期间拉开序幕(1 - 2 月),到彻底的进入白热化阶段(3 - 4 月),竞争是相当的激烈,谁做 ...

  2. Java开发工程师应届生春招秋招总结

    Java开发工程师应届生春招秋招总结 本人是本科双非应届生,在秋招的过程有一些小小的心得(包括部分面试题和面试时需要注意的问题),想分享给大家,大佬们勿喷. JAVA开发面试总结 1.首先是穿着,如果 ...

  3. 【java后台面经】春招秋招求职大佬面试经验分享

    java后台面试经验分享 根据春招秋招的亲身经历细心总结 包括各大公司面试题目和面试小贴士 携程 jvm线程和操作系统线程区别 jvm栈和堆分别放什么 oom可能出现的情况 如何排查oom 项目中未登 ...

  4. 【备战春招/秋招系列】初出茅庐的程序员该如何准备面试?

    备战春招/秋招系列文章回顾: [备战春招/秋招系列]程序员的简历就该这样写 这是[备战春招/秋招系列]的第二篇文章,主要是简单地介绍如何去准备面试.该文已加入开源文档:JavaGuide(一份涵盖大部 ...

  5. 春招/秋招面试前必看一文。如何找到 BAT 的实习机会。找实习中的一些困惑,如何解决?。浅谈秋招。

    春招/秋招面试前必看一文 春节过完,不管是大三/研二.还是大四/研三,就要投入到最激烈的春招当中去了,各大公司将会正式招聘,由元旦期间拉开序幕(1 - 2 月),到彻底的进入白热化阶段(3 - 4 月 ...

  6. 关于春招 秋招面试的一些经验

    2019 年第 24 篇,总 48 篇文章 本文大约 5000 字,阅读大约需要 15 分钟 周末了,就不写技术了,来聊聊关于春招/秋招面试的事情,刚好最近也是逐渐开始春招找实习或者找工作的时候了,我 ...

  7. 【备战春招/秋招系列】美团Java面经总结进阶篇 (附详解答案)

    <!-- MarkdownTOC --> 一 消息队列MQ的套路 1.1 介绍一下消息队列MQ的应用场景/使用消息队列的好处 ①.通过异步处理提高系统性能 ②.降低系统耦合性 1.2 那么 ...

  8. 【备战春招/秋招系列】美团Java面经总结终结篇 (附详解答案)

    该文已加入开源项目:JavaGuide(一份涵盖大部分Java程序员所需要掌握的核心知识的文档类项目,Star 数接近 14 k).地址:https://github.com/Snailclimb.. ...

  9. [干货][互联网]备战春招秋招的经验分享

    作为一个经历过仓促的春招,拿到了腾讯实习:仓促的秋招,拿到了腾讯.美团.拼多多等厂offer的过来人,在此写下一篇回忆贴,希望对正在准备春招or秋招的你有些帮助 文章目录 基本信息 招聘时间 招聘渠道 ...

  10. 春招秋招笔试面试时间(2020年)

    春招面试笔试时间 序号 公司 投简历时间 春招笔试面试时间 1 腾讯 2020.3.10 3.17一面(微信) 3.20一面(网盘) 4.7 PCG的研发部 4.12光子侧开一面 4.18光子侧开二面 ...

最新文章

  1. Linux那些事儿 之 戏说USB(28)设备的生命线(十一)
  2. Spring中的这些坑,99%的程序员都踩过
  3. 吴恩达机器学习笔记 —— 18 大规模机器学习
  4. C# 创建、部署和调用WebService的示例
  5. java语言基础及集合基础大总结
  6. 回归素材(part6)--机器学习系统设计
  7. sql 插入text字段包含特殊字符_Kettle(PDI)转换中输出之插入/更新详解
  8. 局域网中设备的管理之StackCluster
  9. hibernate reverse engineering 中没有java src folder
  10. 视觉slam学习笔记以及课后习题《第三讲李群李代数》
  11. vue单页面应用中node做反向代理的原理
  12. creo5.0安装教程(图文详解)
  13. 咸宁php培训,PHP培训
  14. 程序猿12个“人艰不拆”的真相
  15. 深度linux打不开了,深度社区严重打不开
  16. Web前端系列技术之移动端CSDN会员页面复刻(动态完整版)
  17. 荣耀v40pro和华为nova8pro哪个好?
  18. stl文件怎么用Java读取_vtk对stl文件进行下采样
  19. 无法识别的USB设备跟这台计算机连接的前一个USB设备工作不正常,Windows无法识别它
  20. vim vimdiff diff 使用及命令

热门文章

  1. 成都精灵云-C++开发工程师-技术面经(30min左右)
  2. 10个谈话技巧让你平步青云
  3. 阿里云mysql价格_阿里云超级计算mysql价格
  4. C#取得DataTable最大值、最小值
  5. 关于无法进入XP系统的解决方法
  6. UC浏览器怎样收藏视频?UC浏览器收藏视频的方法
  7. 学计算机的怎样提升打字速度,想提高打字速度吗?
  8. MySQL8.0 之SQL(DQL)单表、多表查询(详细回顾篇)
  9. html5游戏防止作弊,html5 canvas模拟的小球躲避小游戏
  10. Thinkcmf QQ邮箱配置