1:hashmap的原理:https://blog.csdn.net/abcdad/article/details/64123291
HashMap是基于hashing的原理,我们使用put(key, value)存储对象到HashMap中,使用get(key)从HashMap中获取对象。当我们给put()方法传递键和值时,我们先对键调用hashCode()方法,返回的hashCode用于找到bucket位置来储存Entry对象。”这里关键点在于指出,HashMap是在bucket中储存键对象和值对象,作为Map.Entry。
当hashcode相同时:
回答“因为hashcode相同,所以它们的bucket位置相同,‘碰撞’会发生。因为HashMap使用链表存储对象,这个Entry(包含有键值对的Map.Entry对象)会存储在链表中。”这个答案非常的合理,虽然有很多种处理碰撞的方法,这种方法是最简单的,也正是HashMap的处理方法。
为什么默认初始化桶数组大小为16,为什么加载因子的大小为0.75,这两个值的选取有什么特点。
通过看上面的代码我们可以知道这两个值主要影响的threshold的大小,这个值的数值是当前桶数组需不需要扩容的边界大小, threshold=initialCapacity*loadFactor,桶中的键值对超过这个界限就把桶的容量变大。
我们都知道桶数组如果扩容,会申请内存空间,然后把原桶中的元素复制进新的桶数组中,这是一个比较耗时的过程。既然这样,那为何不把这两个值都设置大一些呢,threshold是两个数的乘积,设置大一些就不那么容易会进行扩容了啊。
原因是这样的,如果桶初始化桶数组设置太大,就会浪费内存空间,16是一个折中的大小,既不会像1,2,3那样放几个元素就扩容,也不会像几千几万那样可以只会利用一点点空间从而造成大量的浪费。
加载因子设置为0.75而不是1,是因为设置过大,桶中键值对碰撞的几率就会越大,同一个桶位置可能会存放好几个value值,这样就会增加搜索的时间,性能下降,设置过小也不合适,如果是0.1,那么10个桶,threshold为1,你放两个键值对就要扩容,太浪费空间了。
在扩容的时候, 也是直接乘以2进行扩容, 保证还是2的n次方 .
扩容时,当hashmap的长度为length = 2^n时,不同的hash值发生碰撞的概率比较小,这样就会使得数据在table数组中分布较均匀,查询速度也较快。
因为相同位数数字与11111111111进行与运算都不同。
我们回到indexFor方法,该方法仅有一条语句:h&(length - 1),因为求在hashmap中的位置时就是hashcode%length 而 h & (length - 1) == h % length”这句话除了上面的取模运算外还有一个非常重要的责任:均匀分布table数据和充分利用空间。
这里我们假设length为16(2^n)和15,h为5、6、7。
(这里的h表示的根据key算的hash值,这个indexFor方法是要在数组上给当前数据找个落脚点,好存放当前数据。)
当length=15时,6和7的结果一样,这样表示他们在table存储的位置是相同的,也就是产生了碰撞,6、7就会在一个位置形成链表,这样就会导致查询速度降低。诚然这里只分析三个数字不是很多,那么我们就看0-15。
从上面的图表中我们看到总共发生了8次碰撞,同时发现浪费的空间非常大,有1、3、5、7、9、11、13、15处没有记录,也就是没有存放数据。这是因为他们在与14进行&运算时,得到的结果最后一位永远都是0,即0001、0011、0101、0111、1001、1011、1101、1111位置处是不可能存储数据的,空间减少,进一步增加碰撞几率,这样就会导致查询速度慢。而当length = 16时,length – 1 = 15 即1111,那么进行低位&运算时,值总是与原来hash值相同,而进行高位运算时,其值等于其低位值。
所以说当length = 2^n时,不同的hash值发生碰撞的概率比较小,这样就会使得数据在table数组中分布较均匀,查询速度也较快。
为什么hashmap最大设置为2^31,因为考虑到32为操作系统内存最大为2^32,当对2^31进行扩容时,首先要创建一个更大的map出来,内存不够用了
4GB= 2^32 Byte啊
ConcurrentHashMap 使用锁分段技术, 分成16个段,修改哪个段,就获取哪个段的锁。
2:从浏览器输入url到加载出页面,都经历了什么,例如输入www.baidu.com https://segmentfault.com/a/1190000003925803
假设自己的主机已经联网,省略了广播到dhcp确定本机ip和本地dns服务器ip的步骤
输入url, 首先要解析域名为对应的ip地址,如果2.2失败就进行2.3....
2.1:查询浏览器dns缓存
2.2: 查询操作系统的dns缓存
2.3:搜索操作系统的hosts文件,维护了一张域名与ip的对应表
2.4:向本地dns服务器发出请求,查询本地dns服务器缓存,成功率为80%
2.5 向跟dns服务器查询, 跟dns服务器返回返com 域的顶级域名服务器的地址。
2.6 向com域的顶级域名服务器发出查询请求,返回baidu.com的dns服务器地址
2.7:向baidu.com发送查询请求,返回www.baidu.com 的ip地址
知道了服务器的 IP 地址,下面便开始与服务器建立连接了
2.8 与服务器 简历tcp连接,三次握手,可靠数据连接 (检验和,定时,序号,窗口流水线,肯定确认,否定确认)
2.8.1 客户端向服务器发起请求连接信号,带有标致为SYN=1,客户端序号
2.8.2 服务器接收到信号,向客户端返回确认信号, 标致位SYN=1 ,服务端确认号=客户端序号+1, 服务端序号
2.8.3 客户端接收到服务器的确认信号, 向服务器发送确认信号,可以带有数据,标致位改变,SYN=0 客户端确认号=服务端序号+1, 客户端序号=服务端确认号
当服务器与主机建立了连接之后,下面主机便与服务器进行通信。网页请求是一个单向请求的过程,即是一个主机向服务器请求数据,服务器返回相应的数据的过程。
2.9浏览器根据 URL 内容生成 HTTP 请求,请求中包含请求文件的位置、请求文件的方式等等;
2.10服务器接到请求后,会根据 HTTP 请求中的内容来决定如何获取相应的 HTML 文件;
2.11服务器将得到的 HTML 文件发送给浏览器;
2.12在浏览器还没有完全接收 HTML 文件时便开始渲染、显示网页;
2.13在执行 HTML 中代码时,根据需要,浏览器会继续请求图片、CSS、JavsScript等文件,过程同请求 HTML ;
2.14 断开连接--四次挥手
2.14.1主机向服务器发送一个断开连接的请求(不早了,我该走了);
2.14.2服务器接到请求后发送确认收到请求的信号(知道了);还没有断开连接
2.14.3服务器向主机发送断开通知(我也该走了);
2.14.4主机接到断开通知后断开连接并反馈一个确认信号(嗯,好的),服务器收到确认信号后断开连接;
经历的协议过程:dhcp>dns>tcp连接>http>tcp断开
3:Rpc远程调用 https://www.cnblogs.com/codingexperience/p/5930752.html
Rpc服务器提供一个接口,让客户端调用,服务器的具体实现类方法可以修改。 比较灵活
4:设计模式 http://www.cnblogs.com/foryang/p/5849402.html
4.1: 责任链,一个接口handle, 为每一个handle的实现类设置后继,当没有后继时,就结束
4.2:建造者: 一个统领, 将构建产品的步骤分步进行。 统领者指导建造者一步一步构建产品对象。
4.3:分成产品族,当一个对象中的部件相互依赖时,例如 宝马的轮胎和宝马的轮廓才能适配,使用奔驰的轮廓就不行,那么宝马分为一个产品族。这个工厂专门生产宝马。
5:spring aop 和ioc https://www.cnblogs.com/ITtangtang/p/3978349.html
http://jinnianshilongnian.iteye.com/blog/1413846
https://blog.csdn.net/bestone0213/article/details/47424255
5.1 :spring ioc 是一个容器,管理各个bean对象。管理的时候是通过描述创建对象,通过配置管理,修改对象。
5.2 最主要是完成了对象的创建和依赖的管理注入等等
5.3 SpringIOC容器管理了我们定义的各种Bean对象及其相互的关系
5.4 IoC容器的初始化包括BeanDefinition的Resource定位、载入和注册这三个基本的过程。
//向IoC容器注册BeanDefinition registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition()); //将解析xml过后的bean对象注册近容器
//如果解析的BeanDefinition有别名,向容器为其注册别名 String[] aliases = definitionHolder.getAliases(); if (aliases != null) { for (String aliase : aliases) { registry.registerAlias(beanName, aliase); } }
最后,Bean定义资源文件中配置的Bean被解析过后,已经注册到IoC容器中,被容器管理起来,真正完成了IoC容器初始化所做的全部工作。现 在IoC容器中已经建立了整个Bean的配置信息,这些BeanDefinition信息已经可以使用,并且可以被检索,IoC容器的作用就是对这些注册的Bean定义信息进行处理和维护。这些的注册的Bean定义信息是IoC容器控制反转的基础,正是有了这些注册的数据,容器才可以进行依赖注入。Spring Bean是单例的:https://www.cnblogs.com/doit8791/p/4093808.html
5.5:控制反转是一种通过描述(在java中可以是XML或者注解)并通过第三方去产生或获取特定对象的方式。
潜意识里觉得对象需要自己创建,事实上这并不是你真正的需要,因为也许你对某一领域并不精通,这个时候可以把创建对象的主动权交给别人,这就是控制反转
Spring Ioc容器可以容纳我们所开发的各种Bean, 并且我们可以从中获取各种发布在Spring Ioc容器里的Bean, 并且通过描述可以得到它。
例子:假如现在是共产主义社会,自己是以为蛋糕师,那么社会上的各种东西我们都可以获得, 这些东西就作为Bean注入到了Spring Ioc容器中, 自己生产的各种蛋糕Bean也注入到了Spring Ioc容器中 , 如果我们想要一辆奔驰车, 我们只需要通过描述想要的奔驰车配置(例如四个轮,2.0T),就可以得到一辆奔驰车,我们并不需要关注制造奔驰车的细节(例如螺丝怎么拧的)。同样,别人也可以通过描述拿到自己做的蛋糕bean
IOC和DI 就是讲对象的创建,控制,依赖管理交给IOC容器。
5.2:spring aop 管理切面上某些对象之间的协作, 当多个对象,在某一点相互影响时,需要定义一个切面,来协调这几个对象在这一点的操作。
AOP 1: 对多个对象产生影响的行为进行封装成一个切面(很多方法(切入点)),2: 对方法进行增强
https://www.cnblogs.com/zhaozihan/p/5953063.html
https://www.cnblogs.com/liuruowang/p/5711563.html
Spring AOP 常用于数据库事务的编程
spring aop 将业务代码(一个方法,service层,包含多个对象的相互协作)通过动态代理 织入到相应的位置 ,动态代理中invoke方法中 method.invoke(obj, objects)处; 业务前后的逻辑由拦截器(或固定的实现,例如数据库连接,异常处理)实现。 https://github.com/1367356/GradleTestUseSubModule/tree/master/SpringAOPTheory/src/main/java/com/li
6: innodb和imysam数据库引擎
Innodb引擎
Innodb引擎提供了对数据库ACID事务的支持,并且实现了SQL标准的四种隔离级别。该引擎还提供了行级锁和外键约束,它的设计目标是处理大容量数据库系统,它本身其实就是基于MySQL后台的完整数据库系统,MySQL运行时Innodb会在内存中建立缓冲池,用于缓冲数据和索引。但是该引擎不支持FULLTEXT类型的索引,而且它没有保存表的行数,当SELECT COUNT(*) FROM TABLE时需要扫描全表。当需要使用数据库事务时,该引擎当然是首选。由于锁的粒度更小,写操作不会锁定全表,所以在并发较高时,使用Innodb引擎会提升效率。但是使用行级锁也不是绝对的,如果在执行一个SQL语句时MySQL不能确定要扫描的范围,InnoDB表同样会锁全表。
MyIASM引擎
MyIASM是MySQL默认的引擎,但是它没有提供对数据库事务的支持,也不支持行级锁和外键,因此当INSERT(插入)或UPDATE(更新)数据时即写操作需要锁定整个表,效率便会低一些。不过和Innodb不同,MyIASM中存储了表的行数,于是SELECT COUNT(*) FROM TABLE时只需要直接读取已经保存好的值而不需要进行全表扫描。如果表的读操作远远多于写操作且不需要数据库事务的支持,那么MyIASM也是很好的选择。
主要区别:
1、MyIASM是非事务安全的,而InnoDB是事务安全的
2、MyIASM锁的粒度是表级的,而InnoDB支持行级锁
3、MyIASM支持全文类型索引,而InnoDB不支持全文索引
4、MyIASM相对简单,效率上要优于InnoDB,小型应用可以考虑使用MyIASM
5、MyIASM表保存成文件形式,跨平台使用更加方便
应用场景:
UserMapper mapper = sqlSession.getMapper(UserMapper.class); //创建UserMapper的代理对象
//创建过程中判断UserMapper是不是一个类,如果不是,需要用MapperMethod.excute(SqlSession sqlsession,Object[] obj) 去创建动态代理对象。
//创建过程中将sqlSession的方法加入到了invoke中。
//那么调用代理对象mapper方法的时候,就调用sqlSession中的方法,也就是sql语句。 SqlSession相当于一个UserMapper的实现类,用户自己去写sqlSession(sql语句)里面的业务
乐观锁:假设不会发生并发冲突,只在提交操作时检查是否违反数据完整性。[1] 乐观锁不能解决脏读的问题。
一,数据库的备份与导入
1),数据库的备份
1.导出整个数据库
mysqldump -u 用户名 -p 数据库名 > 导出的文件名
例:mysqldump -u dbadmin -p myblog > /home/zhangy/blog/database_bak/myblog.sql
2.导出一个表
mysqldump -u 用户名 -p 数据库名 表名> 导出的文件名
例:mysqldump -u dbadmin -p myblog wp_users> /home/zhangy/blog/database_bak/blog_users.sql
3.导出一个数据库结构
mysqldump -u dbadmin -p -d --add-drop-table myblog > /home/zhangy/blog/database_bak/blog_struc.sql
说明:-d 没有数据 --add-drop-table 在每个create语句之前增加一个drop table
4.导出数据库一个表结构
mysqldump -u dbadmin -p -d --add-drop-table myblog wp_users> /home/zhangy/blog/database_bak/blog_users_struc.sql
说明:-d 没有数据 --add-drop-table 在每个create语句之前增加一个drop table
2),数据库的导入
1,用 mysqldump 备份出来的文件是一个可以直接倒入的 SQL 脚本,有两种方法可以将数据导入。
例如:
#/usr/local/mysql/bin/mysql -u root -p ***** myblog < /home/zhangy/blog/database_bak/myblog.sql
这种方法,我以前经常现在很少用了,因为很容易产生乱码,因为:
a,导出数据库时,你如果忘了设置导出字符集的话,在导入的时候,就有可能会出问题.
b,假如,你导出时设置导出时设置了utf8的编码,但是你又把你的数据库现在的字符集改成了gb2312的.这样又会乱码。
2,用 source 语句
例如:
mysql -u dbadmin -p
use myblog;
set names utf8; #这里的字符集根你的将要导入的数据库的字符集一至。
source /home/zhangy/blog/database_bak/myblog.sql;
11: socket编程
两个程序(进程)运行时,它们通过从套接字读出和写入数据彼此之间进行通信。
网络应用程序,通过socket进行通信。 socket将发送方的数据通过socket通信(指定IP, 端口,协议)传递到接收方。
网络层的“ip地址”可以唯一标识网络中的主机,而传输层的“协议+端口”可以唯一标识主机中的应用程序(进程)。这样利用三元组(ip地址,协议,端口)就可以标识网络的进程了,网络中的进程通信就可以利用这个标志与其它进程进行交互。
网络中的进程是通过socket来通信的
https://blog.csdn.net/m0_37947204/article/details/80489431
https://blog.csdn.net/alpha_love/article/details/62043077
https://www.cnblogs.com/wangcq/p/3520400.html
12:为什么有进程了,还要有线程
因为进程是系统分配资源的最小单位,进程切换开销大。
线程允许在同一个进程中同时存在多个程序控制流,线程会共享进程范围内的资源。
原因: 线程是比进程更轻量级的调度执行单位。线程的引入,可以把一个进程的资源分配和执行调度分开,各个线程即可以共享进程资源(内存地址,文件I/O等),又可以独立调度(线程是CPU调度的基本单位)。
13:多路复用和多路分解
多路复用:将多个进程的套接字的数据取出,为各个数据添加上协议(ip,端口号), 组成分组,发送出去。
多路分解: 将套接字中的数据分解,发给各个进程,叫做多路分解。
IO多路复用:就是多个客户端线程发送过来IO请求,来的都放进来,而不是每个连接为其开启一个服务端进程。服务端将其放到一个队列中,然后服务端一个线程对这个队列进行处理。处理完返回。相当于一个事件循环Event loop.
后台就一个线程,避免了线程切换和后天线程抢夺资源, 可能单cpu
14:校验和
一个十六进制数,
0x8732ACD87
前4为和后四位化成二进制,相加得到一个和,如果最高位有进位,就和的最后+1。 然后取反
15: 建立两个列的索引,复合查询 。符合索引的有效索引为最长前缀匹配。 例如 index(A,B,C) 那么有效索引为:(A),(A,B),(A,B,C)
16:String intern的用法
https://www.cnblogs.com/Kidezyq/p/8040338.html
上面是jdk源码中对intern方法的详细解释。简单来说就是intern用来返回常量池中的某字符串,如果常量池中已经存在该字符串,则直接返回常量池中该对象的引用。否则,在常量池中加入该对象,然后 返回引用。下面的一个例子详细的解释了intern的作用过程:
例如: jdk 1.7之后,将会在堆上创建对象,在常量池中保存符号引用, String.intern()返回字符串的首次出现的实例引用。
String st2=new StringBuilder("计算机").append("软件").toString(); System.out.println(st2.intern()==st2); String st3=new StringBuilder("计算机").append("软件").toString(); System.out.println(st3.intern()==st3); System.out.println(st3.intern()==st2); /**结果 true false true */
st3.intern()是首次计算机软件出现的实例引用(在常量池中)。
17:String 的equals 和==的区别
==是对象引用的比较
equals是逻辑一致性比较,对象覆盖了该方法,将会按照对象设定的比较方式进行比较。
String 覆盖了equals方法
public final class String implements Serializable, Comparable<String>, CharSequence { public boolean equals(Object var1) { if (this == var1) { return true; } else { if (var1 instanceof String) { String var2 = (String)var1; int var3 = this.value.length; if (var3 == var2.value.length) { char[] var4 = this.value; char[] var5 = var2.value; for(int var6 = 0; var3-- != 0; ++var6) { if (var4[var6] != var5[var6]) { return false; } } return true; } } return false; } } }
String s1 = new String("abc"); String s2 = new String("abc"); System.out.println(s1 == s2); System.out.println(s1.equals(s2)); /**结果 false true */
18:Java 中的编译期常量是什么?使用它又什么风险?
风险:使用了一个其它Jar包的编译器常量,jar包的发布者有可能会改变它的值。而你不知道,还在使用,解决方法,当更新Jar依赖时,要重新编译。
公共静态不可变(public static final )变量也就是我们所说的编译期常量,这里的 public 可选的。实际上这些变量在编译时会被替换掉,因为编译器知道这些变量的值,并且知道这些变量在运行时不能改变。这种方式存在的一个问题是你使用了一个内部的或第三方库中的公有编译时常量,但是这个值后面被其他人改变了,但是你的客户端仍然在使用老的值,甚至你已经部署了一个新的jar。为了避免这种情况,当你在更新依赖 JAR 文件时,确保重新编译你的程序。
19:运行时常量池
运行时常量池是方法区的一部分,存放编译器生成的各种字面量和符号引用, 字面量和符号引用 是Class文件的一部分。
方法区用于存放类信息,常量,静态变量,编译后的代码。
20: BIO,NIO,AIO. Selector
https://blog.csdn.net/skiof007/article/details/52873421
https://www.cnblogs.com/restart30/p/8252109.html
BIO同步阻塞:BIO 每个连接需要服务器创建一个线程。
NIO 同步非阻塞:NIO的最重要的地方是当一个连接创建后,不需要对应一个线程,这个连接会被注册到多路复用器上面,所以所有的连接只需要一个线程就可以搞定,当这个线程中的多路复用器进行轮询的时候,发现连接上有请求的话,才开启一个线程进行处理,也就是一个请求一个线程模式。
非阻塞:需要while轮询
AIO 异步阻塞:通过read,write异步操作来完成,
与NIO不同,当进行读写操作时,只须直接调用API的read或write方法即可。这两种方法均为异步的,对于读操作而言,当有流可读取时,操作系统会将可读的流传入read方法的缓冲区,并通知应用程序;对于写操作而言,当操作系统将write方法传递的流写入完毕时,操作系统主动通知应用程序。 即可以理解为,read/write方法都是异步的,完成后会主动调用回调函数。
同步和异步:
同步和异步是针对应用程序和内核的交互而言的,同步指的是用户进程触发IO操作并等待或者轮询的去查看IO操作是否就绪,而异步是指用户进程触发IO操作以后便开始做自己的事情,而当IO操作已经完成的时候会得到IO完成的通知。
Selector 是一个选择器,轮询器。 用于NIO同步非阻塞。
http://www.importnew.com/26258.html
select将会采用轮询的方式对队列中的所有连接进行查询,获取有效的连接。但是,当连接特别多时,例如1000000个连接,但是有效请求特别少时,例如100个,那么将会造成极大的浪费。
epoll将活跃连接保存在一个红黑树中,每次只查询活跃连接。 已经取代了select/poll.
// // Source code recreated from a .class file by IntelliJ IDEA // (powered by Fernflower decompiler) // package java.nio.channels; import java.io.Closeable; import java.io.IOException; import java.nio.channels.spi.SelectorProvider; import java.util.Set; public abstract class Selector implements Closeable { protected Selector() { } public static Selector open() throws IOException { return SelectorProvider.provider().openSelector(); } public abstract boolean isOpen(); public abstract SelectorProvider provider(); public abstract Set<SelectionKey> keys(); public abstract Set<SelectionKey> selectedKeys(); public abstract int selectNow() throws IOException; public abstract int select(long var1) throws IOException; public abstract int select() throws IOException; public abstract Selector wakeup(); public abstract void close() throws IOException; }
21: 了解的设计模式
a:工厂模式
http://www.cnblogs.com/java-my-life/archive/2012/03/28/2418836.html
http://www.cnblogs.com/java-my-life/archive/2012/04/07/2433939.html
c: 适配器模式:
http://www.cnblogs.com/java-my-life/archive/2012/04/13/2442795.html
d: 观察者模式
http://www.cnblogs.com/java-my-life/archive/2012/05/16/2502279.html
e: 策略模式
http://www.cnblogs.com/java-my-life/archive/2012/05/10/2491891.html
f: 代理模式
http://www.cnblogs.com/java-my-life/archive/2012/04/23/2466712.html
解释:
状态模式:状态决定行为, 状态是一个接口,状态(子类对象不同)不同,行为不同。
策略模式:客户端选择不同的策略,选择不同的计算方法
工厂模式:各个零部件(产品零部件)的工厂,工程师组装
抽象工厂模式:每一个产品,构成一个产品族,有产品工厂生成
建造者模式:一个统领,指挥建造者一步一步构建产品对象。 统领,建造者,产品(part1,part2).
适配器模式:适配类(ada.method1)没有需要的目标对象(target.method1,target.method2)中的方法,就建造一个适配器(method1(){ada.method1},method2),继承适配类和目标对象,将目标对象的方法用适配类方法重写.
观察者模式:为主题添加观察者对象(继承自抽象观察者),当主题变化时,通知观察者。 有推模式和拉模式,推模式是将主题变化的状态推给观察者,拉模式是将主题对象直接给观察者,由观察者自己从主题对象中获取内容。
代理模式:为一个类创建一个代理类,其中,代理类和被代理的类(目标类)实现了相同的接口,代理类也实现了InvocationHandler。 生成的代理类中有目标类的方法和hashCode,equals,toString方法,当调用这几个方法时>会调用super(invocaitonHandler)>会调用invoke方法>调用method.invoke(target)>调用了目标类了的方法。
22:缓存策略
https://www.cnblogs.com/binyue/p/8057890.html
23:redis
redis底层是用字典(dict)数据结构存储的。
dict里面有两个哈希表,每个哈希表的桶里面存储dictEntry链表,dictEntry存储具体的key和value。
redis支持的数据类型hashtable是用开链表的形式(和hashMap差不多)。
Redis也是惰性删除,即要用到数据时,先检查key是否过期,过期则删除,然后返回错误。单纯的靠惰性删除,上面说过可能会导致内存浪费,所以Redis也有补充方案,Redis里面有个定时执行的函数,叫servercron,它是维护服务器的函数,在它里面,会对过期数据进行删除,注意不是全删,而是在一定的时间内,对每个数据库的expire dict里面的数据随机选取出来,如果过期,则删除,否则再选,直到规定的时间到。即随机选取过期的数据删除,这个操作的时间分两种,一种较长,一种较短,一般执行短时间的删除,每隔一定的时间,执行一次长时间的删除。这样可以有效的缓解光采用惰性删除而导致的内存浪费问题。
redis持久化
1:保存redis数据库文件 RDB ,后台线程执行bgsave
2: 保存redis命令
2.1 根据aof_buf 向aof文件中输入命令
2.2 aof_rewrite命令可以根据数据库生成操作命令(逆向),将生成的命令存入aof
aof命令载入的时候,redis生成一个假的客户端,去执行这些命令,最后将原来 的数据恢复出来。
Redis是单event loop的,主线程是单线程的。
24: epoll
https://www.cnblogs.com/lojunren/p/3856290.html
https://blog.csdn.net/shenya1314/article/details/73691088
https://www.jianshu.com/p/36197dac65d9
select 使用扫描全表的形式找出活跃的连接,有最大fd限制,1024。 10万个fd至少需要100个进程
epoll首先create是创建对象的epoll对象(事件)的,ctl操作为红黑树添加,更新事件。当有有效事件发生时,通过事件的回调函数callback事件添加到了双向链表rlist中。
await查询双向链表中有无事件即可,有的话处理,没有等待。
25:复合索引的匹配策略,左向最长匹配
例如一个索引index(a,b,c), 那么可以使用索引的选择项为:
select * from table a=''
select * from table a='' and b='';
select * from table a='' and b='' and c='';
26: 修饰符的作用范围从大到小 public - protected- default-private
27:进程间通信方式: https://blog.csdn.net/baidu_38376402/article/details/72630326
近日想总结下进程间,线程间的通信方式,在网上搜索了下,感觉写的很好,照搬过来,当做加深记忆。
几种进程间的通信方式
(1) 管道(pipe):管道是一种半双工的通信方式,数据只能单向流动,而且只能在具有血缘关系的进程间使用。进程的血缘关系通常指父子进程关系。
(2)有名管道(named pipe):有名管道也是半双工的通信方式,但是它允许无亲缘关系进程间通信。
(3)信号量(semophore):信号量是一个计数器,可以用来控制多个进程对共享资源的访问。它通常作为一种锁机制,防止某进程正在访问共享资源时,其他进程也访问该资源。因此,主要作为进程间以及同一进程内不同线程之间的同步手段。
(4)消息队列(message queue):消息队列是由消息组成的链表,存放在内核中 并由消息队列标识符标识。消息队列克服了信号传递信息少,管道只能承载无格式字节流以及缓冲区大小受限等缺点。
(5)信号(signal):信号是一种比较复杂的通信方式,用于通知接收进程某一事件已经发生。
(6)共享内存(shared memory):共享内存就是映射一段能被其他进程所访问的内存,这段共享内存由一个进程创建,但多个进程都可以访问,共享内存是最快的IPC方式,它是针对其他进程间的通信方式运行效率低而专门设计的。它往往与其他通信机制,如信号量配合使用,来实现进程间的同步和通信。
(7)套接字(socket):套接口也是一种进程间的通信机制,与其他通信机制不同的是它可以用于不同及其间的进程通信。
几种线程间的通信机制
1、锁机制
1.1 互斥锁:提供了以排它方式阻止数据结构被并发修改的方法。
1.2 读写锁:允许多个线程同时读共享数据,而对写操作互斥。
1.3 条件变量:可以以原子的方式阻塞进程,直到某个特定条件为真为止。对条件测试是在互斥锁的保护下进行的。条件变量始终与互斥锁一起使用。
2、信号量机制:包括无名线程信号量与有名线程信号量
3、信号机制:类似于进程间的信号处理。
线程间通信的主要目的是用于线程同步,所以线程没有象进程通信中用于数据交换的通信机制。
28:求一个环形链表的长度,
可以取一个节点作为头节点,然后将该节点赋值为head, 再一次向下取节点,并判断是否等于头节点,直到等于头结点,结束。
29:死锁产生的条件和预防
https://www.cnblogs.com/javabg/p/9016185.html
30:深复制与浅复制 https://www.jianshu.com/p/aa6d493603d3
浅复制:仅仅复制一个对象的引用,clone就是浅复制。 克隆对象和原对象指向相同的位置。改变浅复制的引用的值,也将改变原对象的值。
深复制:通过序列化将对象写到流里面,然后通过反序列化复原原对象。 改变深复制对象的值,不会改变原对象的值。
31:TCP的状态
http://blog.51cto.com/jinlong/2065461
32:悲观锁和乐观锁 https://www.cnblogs.com/qjjazry/p/6581568.html
首先介绍一些乐观锁与悲观锁:
悲观锁:总是假设最坏的情况,每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁,这样别人想拿这个数据就会阻塞直到它拿到锁。传统的关系型数据库里边就用到了很多这种锁机制,比如行锁,表锁等,读锁,写锁等,都是在做操作之前先上锁。再比如Java里面的同步原语synchronized关键字的实现也是悲观锁。
乐观锁:顾名思义,就是很乐观,每次去拿数据的时候都认为别人不会修改,所以不会上锁,但是在更新的时候会判断一下在此期间别人有没有去更新这个数据,可以使用版本号等机制。乐观锁适用于多读的应用类型,这样可以提高吞吐量,像数据库提供的类似于write_condition机制,其实都是提供的乐观锁。在Java中java.util.concurrent.atomic包下面的原子变量类就是使用了乐观锁的一种实现方式CAS实现的。
33:装态码
200 OK
问题
主动发起关闭连接的操作的一方将达到TIME_WAIT状态,而且这个状态要保持Maximum Segment Lifetime的两倍时间。为什么要这样做而不是直接进入CLOSED状态?
原因:
- 保证TCP协议的全双工连接能够可靠关闭
- 保证这次连接的重复数据段从网络中消失
解释
- 如果Client直接CLOSED了,那么由于IP协议的不可靠性或者是其它网络原因,导致Server没有收到Client最后回复的ACK。那么Server就会在超时之后继续发送FIN,此时由于Client已经CLOSED了,就找不到与重发的FIN对应的连接,最后Server就会收到RST而不是ACK,Server就会以为是连接错误把问题报告给高层。这样的情况虽然不会造成数据丢失,但是却导致TCP协议不符合可靠连接的要求。所以,Client不是直接进入CLOSED,而是要保持TIME_WAIT,当再次收到FIN的时候,能够保证对方收到ACK,最后正确的关闭连接。
- 如果Client直接CLOSED,然后又再向Server发起一个新连接,我们不能保证这个新连接与刚关闭的连接的端口号是不同的。也就是说有可能新连接和老连接的端口号是相同的。一般来说不会发生什么问题,但是还是有特殊情况出现:假设新连接和已经关闭的老连接端口号是一样的,如果前一次连接的某些数据仍然滞留在网络中,这些延迟数据在建立新连接之后才到达Server,由于新连接和老连接的端口号是一样的,又因为TCP协议判断不同连接的依据是socket pair,于是,TCP协议就认为那个延迟的数据是属于新连接的,这样就和真正的新连接的数据包发生混淆了。所以TCP连接还要在TIME_WAIT状态等待2倍MSL,这样可以保证本次连接的所有数据都从网络中消失。
35: 判断一个链表中是否有环, https://www.cnblogs.com/ghimtim/p/4882916.html
36: String ,StringBuffer,StringBuilder https://www.cnblogs.com/su-feng/p/6659064.html
37: jvm什么时候会进行full gc.
a:当老年代的最大可用的连续空间大于新生代所有对象的总空间时。 允许minor gc
b: 当老年代的最大可用的连续空间S小于新生代所有对象的总空间时, 但是开启了HandlePromotionFailure=true设置允许担保失败时,并且S大于历次晋升到老年代对象的平均大小。允许发生minor gc
c: jdk1.6之后,HandlePromotionFailure已经不再使用,只要老年代的最大可用的连续空间大于新生代所有对象的总空间 或者 大于历次晋升到老年代对象的平均大小。允许发生minor gc
什么时候会进行full gc.
d: 老年代的最大可用的连续空间小于历次晋升到老年代对象的平均大小,进行full gc。
当老年代的最大可用的连续空间小于新生代所有对象的总空间时,开启了HandlePromotionFailure=false不允许担保失败时,将进行full gc。
38:Spring Boot 启动流程,启动解析
https://blog.csdn.net/zl1zl2zl3/article/details/79765725
https://www.cnblogs.com/trgl/p/7353782.html
Spring 事务原理
https://www.cnblogs.com/softidea/p/5962612.html
Spring 事务传播机制:https://www.cnblogs.com/yixianyixian/p/8372832.html
39:elasticsearch 原理
https://blog.csdn.net/sdksdk0/article/details/78469190
倒排索引:https://www.cnblogs.com/zlslch/p/6440114.html
倒排索引,和MyISAM的全文检索一样,用单词找文档。单词做键,文档列表作为值。
单词1:【记录1,记录2】
单词2:【记录1,记录3,记录5】
40:iPv4 和ipv6所包含的字段
ipv4: 版本号,首部长度,服务类型(将要求低时延,高吞吐量,或可靠性的数据报区别开来),数据报长度,标签,标识,片偏移,寿命,上层协议,校验和,选项,源ip,目的ip,数据。
ipv6: 版本号,流量类型,流标签,有效载荷长度,跳限制,下一个首部,源ip,目的ip,数据。
tcp: 源端口号,目的端口号,序列号,确认号,校验和,窗口,数据,选项 等。
udp:源端口号,目的端口号,长度,校验和,数据。
41:常用linux命令
https://www.cnblogs.com/gaojun/p/3359355.html
42:项目中设置的jvm大小 871.12MB
43: Integer 详解
https://www.jianshu.com/p/9cb9c61b0986
44: Compable 和Compartor
https://www.cnblogs.com/sunflower627/p/3158042.html
45: 不使用第三方变量的交换,+-法,异或^
a = a + b;
b = a - b;
a = a - b;
46: 方法重载和重写的区别
方法重写(overriding):
1、也叫子类的方法覆盖父类的方法,要求返回值、方法名和参数都相同。
2、子类抛出的异常不能超过父类相应方法抛出的异常。(子类异常不能超出父类异常)
3、子类方法的的访问级别不能低于父类相应方法的访问级别(子类访问级别不能低于父类访问级别)
方法重载(overloading):重载是在同一个类中的两个或两个以上的方法,拥有相同的方法名,但是参数却不相同,方法体也不相同,最常见的重载的例子就是类的构造函数,可以参考API帮助文档看看类的构造方法
47:线程池
http://www.cnblogs.com/dolphin0520/p/3932921.html
https://blog.csdn.net/cjh94520/article/details/70545202/
为什么要有线程池:1:因为线程的创建和销毁cpu开销比较大,2:因为无限制的创建线程池,资源消耗比较大。3:创建线程不是越多越好,一定程度即可。超过一定限度,性能反而会降低 4:稳定性,创建线程的数量受到多个因素的制约,例如JVM启动参数,Thread请求参数中请求的栈大小以及操作系统的支持。如果破坏了这些限制,很可能抛出OutOfMemoryError 。
线程池的好处:
public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit, BlockingQueue<Runnable> workQueue,RejectedExecutionHandler handler);
1:maximumPoolSize线程池能创建的最大线程数量>稳定性加强。
2:corePoolSize 核心线程数量,这些线程一直在一个while死循环中运行(从workQueue总获取任务,执行), 其余的线程 (maximumPoolSize-corePoolSize) 个线程,当超过一定时间时,会销毁。这样能够保证资源开销不会太大。
3:long keepAliveTime,TimeUnit unit, 活跃时间和时间单位
4:workQueue 任务队列,当执行exec.execute(task)时,将会将task添加到workQueue中。 然后while循环中的线程,取出任务,最后还是执行了Runnable.run()。
5:ThreadFactory 线程工厂,用来创建线程
6: handle ,当执行出现错误时,选择的处理策略,a:抛出异常,b:丢弃任务等。
线程池的大小https://www.cnblogs.com/waytobestcoder/p/5323130.html
48:spring boot特性,启动流程 https://blog.csdn.net/zl1zl2zl3/article/details/79765725
Spring 启动流程:https://www.cnblogs.com/luoluoshidafu/p/6442055.html
https://www.cnblogs.com/trgl/p/7353782.html
AOP, DI, IOC
49:Spring 如何保证线程安全的
因为Spring中的Bean实例是单例的, 每个线程获取的时候,会用一个ThreadLocal为每个线程创建一个Bean副本进行操作,保证了线程安全。
50:系统性能瓶颈
https://www.cnblogs.com/TestWorld/p/5488710.html
https://blog.csdn.net/smooth00/article/details/63680191
51: Spring Boot启动方式
Runner
52: 类加载器:
https://blog.csdn.net/javazejian/article/details/73413292
53: 测试工具:JEMTER
https://blog.csdn.net/a13124837937/article/details/79628838
https://www.cnblogs.com/jessicaxu/p/7512680.html
测试结果:
首次查询:500次请求需要6秒
第二次查询:500次请求需要3秒
54:高并发写入:
https://segmentfault.com/q/1010000005931313
55: 将某个字段不可持久化修饰符
transient
56:什么是微服务
https://blog.csdn.net/wuxiaobingandbob/article/details/78642020?locationNum=1&fps=1
https://www.oschina.net/news/70121/microservice
57:如何保证线程安全
https://blog.csdn.net/jinggod/article/details/78275763?utm_source=blogxgwz0
https://blog.csdn.net/zhouzhaoxiong1227/article/details/74932180/
58:elasticsearch 优化
https://yq.aliyun.com/articles/38285
https://blog.csdn.net/dev_csdn/article/details/79044930
59:CAS 适合读多写少的场景,例如秒杀活动。
java.util.concurrent包中的类都是用CAS原理完成的。
60:反射原理:https://www.cnblogs.com/hongxinlaoking/p/4684652.html
因此我们就可以通过Class对象去获得成员变量的值,也就是我们想要得到的变量名、修饰符列表、方法名等等,这就是反射的基本原理
61:分析进程状态的linux命令,查询哪一个进程消耗资源过多等
ps
top
java中的命令jps
62:对象锁和类锁的作用范围
https://www.cnblogs.com/houzheng/p/9084026.html
63:为什么3次握手:
http://blog.51cto.com/zhangxinbei/1829125
64:如何保证多人同时安全修改数据库
a: 在业务层使用框架自带的事务,
b: 在业务层使用锁,防止并发修改
c: 在数据层(数据库层sql语句)使用事务
d: 在数据层(数据库层sql语句)使用版本控制
https://bbs.csdn.net/topics/390466595?page=1
https://blog.csdn.net/baimin7657/article/details/8062939
65:前后端交互原理
https://blog.csdn.net/SoftwareTester_zys/article/details/79989956
https://blog.csdn.net/gefangen/article/details/83472898
http://www.cnblogs.com/nalanshawn/p/9351782.html
66:无状态和有状态
https://www.cnblogs.com/xubiao/p/6567349.html
67:post和put的区别
https://www.cnblogs.com/ximenxiazi/p/5850273.html
68: restful和web service 的区别
https://www.cnblogs.com/best/p/8006049.html
https://www.zhihu.com/question/28570307
https://blog.csdn.net/angus_17/article/details/80693165
https://blog.csdn.net/skyshore/article/details/51130139
https://blog.csdn.net/angus_17/article/details/80693165
69:如何防止网站被爬虫
https://www.cnblogs.com/liinux/p/5558943.html
https://bbs.csdn.net/topics/392070282
70:微服务:
微服务就是把不相关的服务构成一个独立单元。服务之间相互调用。
71:造成内存泄漏的原因.