mysql主从同步为什么不使用redolog日志?
而binlog是逻辑日志 记录了所有的写操作,用友更具体的议案的操作,更全面
< catch 关闭io资源 < with resource 直接关闭io资源spring的主要模块
1.核心模块也就是实现ioc的模块
2.aop模块
<模块 持久层4.mvc模块
深拷贝的三种方式
1.构造方法创建全新的对象
2.实现clone方法
3.Serializable序列化实现深拷贝
start和run的区别
1、线程中的start()方法和run()方法的主要区别在于,当程序调用start()方法,将会创建一个新线程去执行run()方法中的代码。但是如果直接调用run()方法的话,会直接在当前线程中执行run()中的代码,注意,这里不会创建新线程。这样run()就像一个普通方法一样。
2、另外当一个线程启动之后,不能重复调用start(),否则会报IllegalStateException异常。但是可以重复调用run()方法。
总结起来就是run()就是一个普通的方法,而start()会创建一个新线程去执行run()的代码。
————————————————
版权声明:本文为CSDN博主「未名湖畔种千玺」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:
1.设置一个日志自定义注解
target 放在神魔地方
rentention 什么地方生效
和一些属性默认值
2.使用这个注解放在需要设置日志的地方
创建一个类加上aspect直接 去设置一些切面和方法
配合注入@Slf4j 在需要注解的地方直接log打印
创建一个pointcut切面 确定在什么地方使用这个日志
创建一些前置通知方法 后置通知方法 和 环绕通知方法
1.array是数组 arraylist集合
2.array只存储基本数据类型 和 引用数据类型
arraylist存储 引用数据类型
3.array是订场的
arraylist是可变长度的
4.Array中存放的是同种数据类型的元素,ArrayList可以存放不同数据类型。
1.首先将数据分为10份,然后每个内部使用快速排序排序自己
2.然后创建一个10的最小堆,取10份的最小的然后再取最小的那个的下一个 【排序数组 排序链表就是这样】
3.最后拍出来的就是有序的
top k的问题
1.通过hash将数据分散到不同文件
2.使用hashmap存储具体的数量 每个文件都创建一个k大小的小顶堆
3.分别取各个文件的k个 然后取钱k个 【全部放进去】
创建一个java对象的过程
1.首先判断类加载有没有加载过这个对象
2.没有加载过的话取加载这个对象
3.为对象进行内存分配附上默认值
4.设置对象头
5.加载初始化方法,完成一些其他的赋值
springboot 优先读取 properties文件 再去读取yml文件的信息 先读取的也不会覆盖
悲观锁:
select*from test where id = 2 for uodate
乐观锁
update test set id = 2 version = version+1 where id = 2 and version = 210
赛码问题4
64匹马,8个赛道,选择最快4匹马最少需要多少次?
10次或11次
堆和栈的区别
1.栈操作系统自动分配 所以v快,堆认为申请的 所以v慢
2.栈空间小 堆空间大
3.栈连续的 对不连续的
6大原则:单一这则原则 理事替换原则 接口隔离原则 依赖倒置原则 开闭原则 迪米特原则
private static final 不能修饰需要重写的方法【同时也就是不能修饰abstract类的方法】
一个map,已经放了1000个key,线程1打印这1000个key值,线程1打印同时,线程2,插入1000个key(保证key都不相同),此时线程1打印情况
报错 concurrent modificationException 因为map的迭代器是fail-fast的 遍历同时不能修改
幻读:【两个select中间的update操作】
事务1;首先select 然后 事务2 uodate 此时事务1select仍然是原来的 ,但是事务1一旦update操作,就会产生幻读(换行,触发mvcc视图的更新);
object的hashcode就是根据内存地址进行计算的
string的hashcode值:根据遍历char型数组 31*一个h+vaue【i】 一致循环计算
h = 31*h+value[i] 循环计算
equals 主要先判断== 是否地址相等
然后instanceof是否为他的实现类或子类,然后判断长度是否相等,最后通过遍历两个数组,判断是否值相等
switch语句的合适范围 “byte、short、int、char、枚举 、String”
java常见的序列化方法
1.实现 Serializable 接口,
2.Json 序列化一般会使用fastjson 包
json.parseobject(a,class);
两种方式的区别:【被static修饰和transient修饰的成员不会被序列化,比如hashmap的Node数组】
1.Serializable 接口的序列化,除了对象的数据以外,还是包含有这个对象的类信息的。而json是只包含有单纯的数据信息。
2.接口的转换为字节流,一般用于rpc的序列化
json的一般用于前后端传输数据
properties文件和yaml配置文件的区别
2.properties只支持java yml支持多重语言,方便扩展
springboot读取配置文件的方式
1.@value 读取
2.@configurationproperties 注入到实体类 直接使用注入ioc容器的实体类
@ConfigurationProperties(prefix="spring.user")
list的三种遍历方式
1.for循环
2.iterator
3.foreach遍历【这种遍历过程中不能删除元素】
mybatis的三种分页方式
1.使用limit在xml分页
2.使用boundrows 分页,具体就是查询一次 然后在缓存查询
3.通过intereptor拦截器分页,拦截需要分页的sql,然后去拼接sql语句
mysql为什么使用b+树不用调表【io层面 和 插入的效率方面】
1.b+树是多叉平衡术,每个节点16kb,可以存更多的信息,存储2千万数据只需要3层,也只需要3次io, 而调表是一个数据一个节点,他存储2千万要更多的io次数
redis为什么使用调表不用b+树?
redis纯内存操作,所以上边说的层高不再是调表的劣势,
针对插入操作,调表直接插入,而b+树等需要合并拆分,旋转操作,效率低
一个对象多大内存:
对象头: marword 【8字节】+ 类型指针【4字节】
如果boolean是单独使用:boolean占4个字节。
如果boolean是以“boolean数组”的形式使用:boolean占1个字节。
没有实例变量的话就是16个字节
实例变量
填充字节
key a b c(a,b,c)
order by能使用索引最左前缀
- order by a
- order by a,b
- order by a,b,c
- order by a DESC,b DESC,c DESC
如果where使用了索引的最左前缀定义为常量 则order by能使用索引
- WHERE a=const order by b,c
- WHERE a=const AND b=const ORDRE BY c
- WHERE a=const AND b>const ORDER BY b,c
不能使用索引进行排序
- ORDERE BY a ASC,b DESC,c DESC 排序不一致
- WHERE g=const ORDER BY b,c 丢失a索引
- WHERE a=const ORDER BY C 丢失b索引
- WHERE a=const ORDER BY d d不是索引的一部分
mybatis的动态sql标签:
1.if标签 和 where标签一同使用
<select id="findUser" resultType="User">
SELECT * FROM user
<where>
<if test="class != null">
AND class = #{class}
</if>
<if test="phone != null and adress != null">
AND age > #{age}
</if>
</where>
</select>
————————————————
版权声明:本文为CSDN博主「高并发」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:
<select id="findUser" resultType="user">
select * from user
where class ='12'
<if test ="age !=null">
and age>#{age}
</if>
</select>
2.foreach 标签 集合查询
<select id="findUser" resultType="User">
select * from user
where class in
<foreach item="item" index="index" collection="list" open="(" separator="," close=")">
#{item}
</foreach>
负载均衡算法:
1.轮训
2.加权轮训
3.随机
4.最小连接【记录次数 那个最少转发到那个】
5.ip 的 hash【】
6.一致性hash【分布式缓存 根据hash环进行存储】
ping的流程
1.首先生成icmp请求报文,将报文和ping的ip地址发送给ip层,进行ip的封装,然后判断是否在同一子网(根据要请求的ip地址和自己是否在同个子网),在同子网在ip层进行arp解析,找到对应的mac地址,封装成mac帧,传递给物理层,传输到对应的接收端 然后另一边解析出icmp报文,反向发送个icmp相应报文。
2.nacos的配置中心的原理,
nacos采用长轮训【客户端发送一次轮训请求到服务器后,当服务端的配置没有变化的时候,这个连接会一直打开,直到有配置的变化或者是超时才会返回】的方式进行查询配置信息向服务端,
客户端每次发送3000个key加上具体信息的md5加密值作为一个字符串发送给服务端,服务端依次判断是否发生了改变,将发生改变的key告诉客户端,然后客户端根据变化的重新查询服务端配置完成具体的配置。
一张自增表里面总共有 7 条数据,删除了最后 2 条数据,重启 MySQL 数据库,又插入了一条数据,此时 id 是几
innodb是6,
myisam是8
因为InnoDB表只把自增主键的最大ID记录到内存中,所以重启数据库或者对表OPTIMIZE操作,都会使最大ID丢失。
但是,如果我们使用表的类型是MylSAM,那么这条记录的ID就是8。因为MylSAM表会把自增主键的最大ID记录到数据文件里面,重启MYSQL后,自增主键的最大ID也不会丢失。
volatile在i++情况会失效:::::::::::::::::::::
不是线程安全的 只能保证可见性和有序性 不能保证原子性
LRU(最近最久未使用)和LFU(最近最少使用)
幂等性问题接口
调表
IO多路复用
奇安信
网易1
网易2021提前
Redis-从海量数据里查询某一固定前缀(k1)的key
1.keys k1* 一次性返回数据量太大
2.scan 增量迭代式的命令,
scan 0 MATCH 11* 因为这里没有指定count,所以默认为10
scan 176 MATCH 11* COUNT 1000
limit a,b
limit 3,2 第几个位置开始索引,索引位置从0开始计算。第二个参数是取记录个数【4,5两个记录】
mp: 最差 最好 平均
on2 on on2 稳定
选择:on2 on2 on2 不稳定
插入: on2 on on2 稳定
快排 on2 ologn ologn 不稳定 ologn
堆 ologn olgn ologn 不稳定
聚集索引和非聚集索引的区别
1.聚集索引只有一个 非聚集索引可以多个
2.聚集索引索引的顺序和物理存储顺序一致 非聚集索引的不同
3.聚集索引的叶子结点存储的索引和数据行数据,一个文件存储
非聚集索引的叶子结点存储的索引和具体所银行的地址 二哥文件存储
四种隔离级别怎么实现的(锁+Mvcc实现的)
读未提交: select语句不加锁,每次都是最新的数据
写加行锁
读已提交:
select 使用mvcc的快照读,生成readview时机不同
修改操作使用行锁
可重复读:
select mvcc快照读
修改 使用临检锁(行锁+间隙锁)
串行化:读写都会加锁
重写Arrays.sort方法 比较两个String字符串 使用的compareTo比较 数字可直接使用- 进行比较
Arrays.sort(cur,(String a, String b)->{
return (a+b)pareTo(b+a);
});
//字符串按照字母排序 先toCharArray() 然后Arrays.sort(); 之后使用new String 即可完成排序
String s="sdsa";
char [] chs = s.toCharArray();
Arrays.sort(chs);
s = new String(chs);
//trim 去掉收尾空格 split以什么分割开
String[] intern = s.trim().split(" ");
threadlocal 使用开放地址法 - 线性探测法:当前哈希槽有其他对象占了,顺着数组索引寻找下一个,直到找到为止
hashset 中调用 hashmap 来存储数据的,hashmap 采用的链地址法:当哈希槽中有其他对象了,使用链表的方式连接到那个对象上
ThreadLocalMap中使用开放地址法来处理散列冲突,而HashMap中使用的是分离链表法。之所以采用不同的方式主要是因为:在ThreadLocalMap中的散列值分散得十分均匀,很少会出现冲突。
并且ThreadLocalMap经常需要清除无用的对象,使用纯数组更加方便。
ThreadLocalMap通过key(ThreadLocal类型)的hashcode来计算数组存储的索引位置i。如果i位置已经存储了对象,那么就往后挪一个位置依次类推,直到找到空的位置,再将对象存放。另外,在最后还需要判断一下当前的存储的对象个数是否已经超出了阈值(threshold的值)大小,如果超出了,需要重新扩充并将所有的对象重新计算位置。
HashSet是怎么去重的
根据key获得hash值 然后取余数组长度 获得数组下标,为null的话直接加入,不为null的话equals比较,相同就不存进去,不同直接存入 链表
拉链法解决hash冲突
hashmap的put方法:根据key二次hash{key.hashcode异或key.hash右移16为然后与上数组长度-1}相当于取余的操作 ,扎到对应的key,为null直接加入,不为null的话 依次equals链表元素,如果一只替换元素的值,链表长度8 数组到64才会转换为红黑树, 小于64优先进行扩容处理,因为扩容就可以实现链表长度的剪短
union将两个查询结果去重保存
union all 不去重保存
CROSS JOIN生成笛卡尔积
inner join 相等查询
left join 左连接
hashmap怎么删除元素?
remove 方法
两个join某些情况都可以使用
装箱 Integer.valueOf()
Integer.parseInt(String的);
为什么b+数 不用红黑树 io次数为什么少(多叉平衡树)
1.b+树 非叶子节点只存储索引,叶子结点存储内容 ,同样的一个磁盘页可以存更多的数据(每页16kb,每个节点就是一个内存页16kb),磁盘io次数更少 是个多路平衡树
b树 非叶子结点也存储数据 所以说存的数据更少 层数更多 磁盘io更多
叶子结点有个双向指针只需要扫一遍即可 b树还需要去中序遍历查询
2.b+树磁盘io固定的而更加稳定 红黑树和b树不稳定 层数会更多
3.b+树是多路平衡树,红黑树是二叉树 所以b+树io次数会更少
4.不用hash索引,hash底层使用的哈希表实现的等值查询,不能排序的操作,可能hash冲突
覆盖索引:就是查询的字段在索引上直接查出来,不需要回表的操作,回表的操作就是在二级索引查到了主键id(索引值)然后去主键索引查具体的数据行
当前会议udp 头部 还有怎么控制的udp当前会议的实时性 udp 头部 源端口 目的端口 长度 检验和
源端口 目的端口 长度 校验和
读已提交和可重复读都是使用MVCC实现的并发控制
怎么实现的并发控制
readview+undolog版本链
实现这个 区别在readview的生成时机不同
读已提交:每次select都会创建新的readview 保证读取到已提交的修改
可重复读:在一个事务范围内,只有在第一次select的时候会更新这个readview,以后不在更新这个复用这个readview
可重复读使用的mvcc实现的幻读
没有完全解决:两个快照读中间加个当前读就会出现幻读的情况 ,更新(当前读)使mvcc版本失效了,出现了幻读
开始查询 然后另外一个修改了数据行,当前再去修改的话 在查询就是出现了幻读
nacos feign的底层协议(对http协议的一种封装)
解决接口的幂等性:
1.使用token字段放入redis
2.唯一id(比如自己的手机号)[会访问db 效率问题]
3.乐观锁加个version字段[先查版本号 然后并发修改 肯定只能一个成功]
4.可以设置状态字段保证幂等性(比如项目中的延迟队列中的解锁库存 必须判断库存表处于锁定状态而且订单处于关闭状态)
解决hash冲突:
1.开放地址法(线性探测和二次探测)
2.链地址法
3.再hash法
1.算法
2.rabbitmq知识点
3.项目复习
4.os重要知识点
redis中的大key 怎么解决
1.比如String类型的把它分为几个key 分开
2.hash的话就是把当前对象属性都分布到field上 取的时候只取需要的字段 防止取的数据量太大 阻塞主主线程的使用
exist 和 in
exist 内大好
in 外大好
exist的话首先计算外表 然后带入内循环依次判断是否正确
in首先遍历里边的sql 生成一个表 然后去匹配外边的数据
int 1 和 int 10的区别
数字和存储空间无关 都是4byte
int(数字) 只有跟zerofill结合 才能展示准确的位数 否则显示都出不来{少于这个时可以在前边补上,超过了按照原样输出}
如何避免全表扫描
1.就是索引失效的情况
避免使用or时左右没有索引
避免使用like% %
避免使用《》 !=
避免使用索引列进行计算
避免索引列为char类型的=后边不适用‘’
不符合最左前缀原则的
约定大于配置
就是原来有一些固定的约定,如果不使用这些约定的话 可以自己设置替换他 尽可能的减少了默认配置
创建一个spring注解
@Target({ElementType.METHOD,ElementType.FIELD}) //用在什么地方 一般用在方法
@Retention(RetentionPolicy.RUNTIME) //运行时运行
public @interface zhujie {
String value() default "";
}
对象头三部分
头部(有个threadid在synchronized修改的时候去使用
有个4个bit位存储 标识年轻代晋升老年代的年龄阈值字段(jvm的分代年龄) )+实例变量+填充字节
```````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````
mysql的分层 连接层 服务层 存储引擎层
```````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````
各种bufferpool 和 changebuffer write buffer
bufferpool 是innodb存储殷勤的缓冲池,不属于mysql的server层,主要存储数据页和(写缓冲)changebuffer,用来存储变更记录
如果每次写操作,数据库都直接更新磁盘中的数据,会很占磁盘IO。为了减少磁盘IO,InnoDB在Buffer Pool中开辟了一块内存,用来存储变更记录,为了防止异常宕机丢失缓存,当事务提交时会将变更记录持久化到磁盘(redo log),等待时机更新磁盘的数据文件(刷脏),用来缓存写操作的内存,就是Change Buffer
唯一索引和普通索引怎么选择
普通索引可以重复,唯一索引只能是唯一的一个可以为空
主键索引不能为空,因为他就是聚簇索引排列的,这也就是为啥主键不能为null
如果是查询操作的话,查询会以页为单位将数据页加载进内存,bufferpool缓冲池
唯一索引根据条件查询到等值记录直接返回
普通索引会查到后,依然向后遍历 直到不满足条件的
范围查询的话 都是访问到不满足条件的值为止
但是都在内存中,所以性能几乎一致
修改操作的话
唯一索引需要检查唯一性 必须加载到内存中进行判断,直接操作内存
普通索引若数据页在内存中的直接更新
不在的话直接写到changebuffer中也可以
否则就先把更新操作记录到channge buffer 中,等下一次查询将数据读到内存中在进行 channge buffer里相关更新操作后把数据返回,等查询来了才将数据更改操作读到内存中去修改
这样在写多读少的情况下,普通索引减少了磁盘io
aqs (底层是双向链表队列
他存的是节点之间的关联关系,aqs将每条请求共享资源的thread封装成一个clh队列的一个节点来实现锁的分配
1.如果需要在aqs等待队列删除一个线程node节点 方便删除
2.方便唤醒,如果是单向的话有个pre aqs在获取锁时如果获取不到进入等待状态,此时后续节点因为阻塞了无法感知前个node节点的状态,无法唤醒,所以使用双端队列加入了个next属性 方便前个节点释放后主动唤醒后续的节点thread
) tryacquire tryrelease
当共享资源被某个线程占有,其他请求该资源的thread会被阻塞,从而进入一个等待队列
抽象队列同步器 是个父接口 比如reentrantLock semaphore countdownlatch
cyclicbirrer 实现依靠reentrantlock 和 condition实现的
他有个state属性 使用的cas的方式进行修改属性值 aqs主要有两种形式的锁 独占锁和共享锁
如果是独占锁 state=1的时候,然后后边的话在想进入就会进入双端链表的等待队列
他的唤醒和挂起使用的底层为park和unpark的机制进行 锁的
http断点续传
HTTP1.1协议(RFC2616)中定义了断点续传相关的HTTP头 Range和Content-Range字段,一个最简单的断点续传实现大概如下
1. 客户端下载一个1024K的文件,已经下载了其中512K
2. 网络中断,客户端请求续传,因此需要在HTTP头中申明本次需要续传的片段:Range:bytes=512000-,这个头通知服务端从文件的512K位置开始传输文件;
3. 服务端收到断点续传请求,根据请求头的Content-Range来决定从文件流的哪个位置上开始读,比如从文件的512K位置开始传输,并且在HTTP头中增加:Content-Range:bytes 512000-/1024000,并且此时服务端返回的HTTP状态码应该是206,而不是200。
但是在实际场景中,会出现一种情况,即在终端发起续传请求时,URL对应的文件内容在服务端已经发生变化,此时续传的数据肯定是错误的。如何解决这个问题了?
同时定义有一个If-Range头,终端如果在续传是使用If-Range。If-Range中的内容可以为最初收到的ETag头或者是Last-Modfied中的最后修改时候。服务端在收到续传请求时,通过If-Range中的内容进行校验,校验一致时返回206的续传回应,不一致时服务端则返回200回应,回应的内容为新的文件的全部数据。
先行发生原则(happens-before规则)
//ahapp b 主要就是保障a的结果对b是可见的一整套规则。 但是时间上没有关系
:主要判断数据是否存在竞争、线程是否安全。
如果A happens-before B,仅保证A的操作结果对B可见,但并不意味着A一定比B先执行;在不影响结果的前提下,B有可能会比A先执行。
Mysql主从读写分离
主库写 从库读
1.主库执行sql修改
2.主库成功修改时binlog更新
3.主库的binlog dump线程将更新部分发给从库
4.从库io thread收到binlog更新部分写入relay log中
5.从库读取relay log内容
并且ROW模式的binlog记录了完整的变更信息,在恢复数据上面将会很容易。
mysql慢查询优化:
1.查询慢查询查询日志定位sql
2.使用explain进行分析
rabbitmq
RabbitMQ一般用来干嘛?你在项目中怎么用的?消息重复消费怎么办?丢失怎么办?
反射优点:增强代码的灵活性 ,比入jdk动态代理,不需要更改代码;return newproxy 根据类.getclass().getClassLoader(),.interface 动态获得对象的类加载器和接口
反射缺点:不安全,可以获取哪些private的属性,不像被外界直接调用的属性
如何破坏单例 【反射 序列化机制 克隆】
都是通过构造器重新创建的
Constructor constructor=DeclaredConstructor(null);
constructor.setAccessible(true);
//序列化会通过反射调用无参数的构造方法创建一个新的对象。
序列化实现seriallable接口 和 clone 都不会调用构造方法
2.
1.自己的特点 注意说技术的特点,
自我介绍太啰嗦吧,把技术和项目放在自我介绍会好一点
废话多了好像,应该着重说自己会的东西
如何判断线程池的任务是否都执行完了?
1.线程池有个isTerminated的原生函数,直接判断
2.countdownlatch 任务执行完毕后执行countdown 直到最后为0 继续执行await后边的代码逻辑
3.submit提交线程任务,有个future的返回值,通过isDone()方法可以知道任务是否执行了
treemap 和hashmap区别 都不是线程安全的
1.都实现了AbstractMap接口 treemap实现了SortedMap接口 可以对key 进行排序,默认对key进行升序排序
2.hashmap数组加链表加红黑树
3.hashmap适用于对map的插入和删除和查找元素
trreemap适用于自然顺序遍历key的排序
hashmap中的排列顺序是不固定的
2.网络 http1 http2
1.x文本传输
2.x 二进制进行传输
http1
请求行
请求头
空行
请求体
io多路复用 一次连接可以多个请求或者响应
压缩头部 客户端服务端记录发送过的 相同的不会重复发送
流式的概念 以前都是服务端等待客户端请求,现在可以服务端主动发送给客户端,减少了等待延迟
队头阻塞:
http1.1 有高延迟,页面加载速度降低,队头阻塞导致带宽无法充分利用
当顺序发送的请求序列一个请求阻塞时,后面排队的所有请求会一并被阻塞,导致客户端迟迟收不到数据
http1.0和http1.1的区别
1.0使用的短连接,每个http操作建立一个连接,结合就会释放连接
1.1使用场链接 tcp连接复用
1.1增加了host字段 可以实现单ip多个主机的实现
1.1增加了更多的缓存方式
1.0有带宽浪费的现象,想要获取对象的一部分的话只能全部都发送出去
1.1的话使用的是,可以获取指定的部分
2222222222
b+树的时间复杂度 Olog(m)n
别的红黑树等等都是二叉树
innodb 聚集索引
聚集索引叶子结点存储当前数据行的数据
二级索引叶子结点存储主键id和索引值
myisam(非聚集索引)的索引
主键索引和二级索引一致
叶子结点存储的键为索引的值 数据为索引所在行的地址
间隙锁
1.唯一索引和普通索引的非等值查询都会生成间隙锁
2.或者是在唯一索引的范围查询会生成间隙锁的生成
3.非唯一索引的等值查询也会生成间隙锁 【左边左开右闭 右边同时也会有个间隙锁的生成】
行锁:
主键索引或者唯一索引的等值操作
临检锁:
间隙锁的目的 防止幻读
1.防止间隙内插入新的数据
2.防止更新间隙内的数据
next-key锁
next-key锁其实包含了记录锁和间隙锁,即锁定一个范围,并且锁定记录本身,InnoDB默认加锁方式是next-key 锁。
nextkey锁 需要更加理解一下 不是行锁+间隙锁
案例:一张表t id(主键)、c(普通索引)、d 字段 插入数据(0,0,0),(5,5,5),(10,10,10),(15,15,15
05】 5 10】 10 15】15,+无穷】
间隙锁:
1.唯一索引和非唯一索引 不存在的指定行的加锁都变为间隙锁
update t set d=1 where id = 7 主键索引上的 (5,10)间隙锁
update t set d=1 where c = 7 普通索引上的 (5,10)间隙锁
2.普通索引的等值查询(查到的),向右遍历时最后一个值不满足时,next key lock退化为间隙锁
update t set d=1 where c = 5 普通索引上的 (0,5]临键锁 (5,10)间隙锁
唯一索引上不存在临检锁
3.唯一索引的范围查询 考虑是否存在当前临检锁右边的元素 有选择的选取行锁,但是普通索引是全部的无脑临检锁
update t set d=1 where id >=10 10的行锁 10,+无穷的间隙锁
where id >=10 and id <11 主键索引上的 10行锁 (10,15)间隙锁
4.普通锁引的范围查询 【普通索引都会前个区间加上后个区间】都是临检锁
update t set d=1 where c >=10 普通索引上的 (5,10]临键锁 (10,~]的临键锁
update t set d=1 where c >=10 and c <11 普通索引上的 (5,15]临键锁
update t set d=1 where c <11 普通索引上的 (0,15]临键锁
普通索引只有在等值查询的下个区间或者非等值查询才会临建锁变为间隙锁, 范围查询都是临检锁
费唯一索引的范围查询 锁住多个区间
唯一索引上不存在临检锁
lock in share 读共享锁
for uodate 蟹排他
作者:小丸子的呆地
链接:
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
mvcc实现读已提交和可重复读的并发控制的区别
生成readview的时机不同,读已提交的话只要提交事务readview就会修改
可重复读的情况下一个事务范围内只有在第一次查询生成readview 后边一个事务内不会有修改
ForkJoin
get 操作不会阻塞 因为节点的value和next都是volatile的可见的
synchronized 会在扩容【forwardingNode 锁节点】和产生hash冲突 cas添加元素
cas添加元素替换替换元素
看旧的数组 有个forwardingNode标志
concurrentHashMap多线程扩容
和hashmap一致
1.链表长度到8 数组长度没到64 进行扩容
2.数组数据存放到了阈值
3.putall方法 可能上来就扩容
扩容为原数组的两倍
1.给thread分配任务 2.把转以后的节点设置为forwardingNode
首先从后边16个当前thread的,转移后当前节点就变成了ForwardingNode ,第二个thread的话从前边16开始领取16个hash桶
如果当前位置有数据 加上synchronized进行拷贝到新的数组,并且将当前节点设置为ForwardingNode
如果某个thread执行完成后,发现没了hash同,停止
jdk8采用多线程扩容【每个thread16个hash桶】
forwardingNode 标志为旧数组中处理过的节点,然后使用新的数组替换旧的数组
put过程:首先根据key求hash值然后看当前位值是否为null 为null通过cas插入元素
不位null的话 就会synchronized给这个节点上锁,然后判断加入元素,相同替换 不同加入
扩容也会给这个节点加锁
若果put过程中正在扩容的话,(扩容从后到前遍历扩容,转移走的节点标志为forwardingNode)
1.如果在forwardingNode节点之前的put 可以进行put
2.如果在当前正在扩容的节点会阻塞住该节点
3.在forwardingNode的节点put 就会帮助当前thread并发扩容
【什么情况下不会协助扩容】
1.当原数组所有节点都已经称为了forwardingNode 所有的节点都已经转移完了,
2.或者put的正在转移
3.或者达到了最大扩容线程数
1.8
hashMap扩容是怎么实现的
生成一个新数组一倍的,然后去判断转移元素
数组容量扩大一倍的话 n-1的话就会左边多出一个1
对应hash&就数组容量 如果是1现在的容量就是 旧的容量+原位置
如果是0的话当前的为值还是旧的位置
1.7扩容有两个条件
1.达到了扩容阈值
2.必须下一个插入的元素产生hash冲突才会进行扩容,如果没有产生冲突的话 还是不会扩容
红黑树(二叉树)时间复杂度 OlogN 链表 On
为什么小于64链表长度大于8为什么先扩容
数组比较小先扩容(节点的转移)就可以把长链表转换为短链表,比转换成红黑树的效率更高
40分钟
spring初始化是干嘛的(主要进行aop操作的)初始化前可以执行@postconstruct的方法
新生代和老年代为什么使用不同的算法
新生代对象很快就会回收掉
老年代对象很难回收 所以算法不同
索引的合适的情况:1.经常需要where查询的字段 ,这样走索引
2.经常需要查询的字段 使用覆盖索引
不合适的情况:1.区分度不高的
2.经常需要修改的字段
udp 源端口 目的端口 udp报文长度 校验和
tcp 源端口 目的端口 序号 确认序号
jvm的类加载机制主要有3种:全盘委托、双亲委派,缓存
全盘委派:就是当一个类加载器负责加载某个Class时,该Class所依赖和引用其他Class也将由该类加载器负责载入,除非显示使用另外一个类加载器来载入。
双亲委派:所谓的双亲委派,则是先让父类加载器试图加载该Class,只有在父类加载器无法加载该类时才尝试从自己的类路径中加载该类。通俗的讲,就是某个特定的类加载器在接到加载类的请求时,首先将加载任务委托给父加载器,依次递归,如果父加载器可以完成类加载任务,就成功返回;只有父加载器无法完成此加载任务时,才自己去加载。
缓存机制。缓存机制将会保证所有加载过的Class都会被缓存,当程序中需要使用某个Class时,类加载器先从缓存区中搜寻该Class,只有当缓存区中不存在该Class对象时,系统才会读取该类对应的二进制数据,并将其转换成Class对象,存入缓冲区中。这就是为很么修改了Class后,必须重新启动JVM,程序所做的修改才会生效的原因。
————————————————
tomcat利用自定义的类加载器实现了热加载
WebAppClassLoad类加载实例+A类名 修改时间 一个thread一直监控类 class文件 修改就会重新创建一个WebAppClassLocader类加载器 ,等到再需要A类 时使用新的类加载器加载
热加载(不重启服务的情况下让更改的代码生效,一个thread一直监控类 class文件 修改就会加载他)(tomcat类加载的)
jvm调优
布隆过滤器(redis整合)
位图 解决缓存穿透
首先在加入元素的时候key会经过多次hash 去吧位图对应位置设置为1
然后的话查询的时候先根据hash去查当前key对应位图位置是否为1 为1的话直接查询redis缓存,不为1的话就是说明不存在这个值直接返回,并且设置缓存空值;
压测接口+秒杀?
反射?
/
力扣中注意 组合 和 子集的区别
组合 第一个if中去添加到res集合
子集是 循环中去添加res集合中
只有可以排序的才可以使用a[i]==a[i-1]去使用去重的操作
求最长递增子序列 只求长度的话dp就可
求具体的子序列需要使用回溯 遍历完全部的
全排列 需要使用个boolean数组 来判断单条链上的所有使用过的元素
区间问题想到Arrays.sort 排序数组
3.
java内存模型 就是多线程访问下保证共享变量原子性可见性 有序性的一些规则。一般共享变量存在主存中,其他thread在修改他时,读取一份共享变量的副本放到自己的工作内存,然后修改完后同步到驻村。
juc jvm
redis 和 spring
redeview的最小事务id 和 最大事务id
AQS的一些基础知识
如果state等于0,那么获取锁并将state设置为1。
如果state不等于0,但是当前线程就是加锁线程,那么获取锁定资源,并把state+1
否则,调用LockSupport.park(this),把当前线程挂起。
可重入锁:表示当前线程获取锁后,再次获取锁不需要阻塞
当 state>0 时,表示已经有线程获得了锁,也就是 state=1,但是因为ReentrantLock 允许重入,所以同一个线程多次获得同步锁的时候,state 会递增,比如重入 5 次,那么 state=5。 而在释放锁的时候,同样需要释放 5 次直到 state=0其他线程才有资格获得锁。
synchronized的可重入锁的实现原理:
每一个锁关联一个线程持有者和计数器,当计数器为 0 时表示该锁没有被任何线程持有,那么任何线程都可能获得该锁而调用相应的方法;当某一线程请求成功后,JVM会记下锁的持有线程,并且将计数器置为 1;此时其它线程请求该锁,则必须等待;而该持有锁的线程如果再次请求这个锁,就可以再次拿到这个锁,同时计数器会递增;当线程退出同步代码块时,计数器会递减,如果计数器为 0,则释放该锁。
————————————————
=============================================
syncgronized的加锁原理:
进入同步代码块 执行monitorenter指令,视图获取当前monitor对象,然后去看内部的一个计数器,如果为0就获取该锁然后+1,直到执行了monitorexit指令才会退出当前同步代码快,别的阻塞的thread放入到entrylist等待队列等待
如果是放在方法上的,synchronized会给方法加一个acc标识,代表当前方法为同步方法
Reentrantlock加锁的流程:因为分为公平锁和非公平锁
公平锁的话,调用tryAcquire加锁的时候先去看state是否为0,是的话去看双向链表中有没有thread在等待,有的话使用LockSupport.park()把当前thread挂起加入队尾,没有的话执行thread加锁
解锁的话调用tryRelease成功的话唤型等待队列中的thread
失败的话直接返回false
非公平锁的话,加锁的话直接尝试把状态设置state为1,成功获取锁,否则去获取state值,0的话直接获取锁,不管队列中还有没有thread在等待,不等于0的话放入队尾
非公平锁加锁过程不同于FairSync,NonFairSync会在调用lock()时,直接尝试把state设置为1:
解锁的话调用tryRelease()成功的话 使用LockSupport.unpark唤醒等待队列中的thread
失败的话直接返回false
aqs (底层是双向链表队列)
AQS(AbstractQueuedSynchronizer)是抽象队列同步器,在线程访问共享资源时候,会先判断资源是否上锁了,
如果上锁了,那么把该线程放入fifo的双向链表中进行等待;
如果没上锁,非公平锁那么把该线程设置为工作线程,公平锁会从双向链表中唤醒第一个节点thread,并且把自己放到双向链表尾部
AQS 队列内部维护的是一个 FIFO 的双向链表,双向链表可以从任意一个节点开始很方便的访问前驱和后继。每个 Node 其实是由线程封装,当线程争抢锁失败后会封装成 Node 加入到 ASQ 队列中去;当获取锁的线程释放锁以后,会从队列中唤醒一个阻塞的节点(线程)。
————————————————
aqs为什么使用双向链表(但是仍然是fifo的)? 中断操作方便+主动唤醒下一个节点
1.中断操作需要在aqs队列中删除thread的Node节点,如果需要在aqs等待队列删除一个线程node节点 方便删除
2.方便主动唤醒,如果是单向的话有个pre aqs在获取锁时如果获取不到进入等待状态,此时后续节点因为阻塞了无法感知前个node节点的状态,无法唤醒,所以使用双端队列加入了个next属性 方便前个节点释放后主动唤醒后续的节点thread
tryacquire()获取锁 tryrelease ()释放锁
reentrantLock的可中断
ReentrantLock中的lockInterruptibly()方法使得线程可以在被阻塞时响应中断,比如一个线程t1通过lockInterruptibly()方法获取到一个可重入锁,并执行一个长时间的任务,另一个线程通过interrupt()方法就可以立刻打断t1线程的执行,来获取t1持有的那个可重入锁。而通过ReentrantLock的lock()方法或者Synchronized持有锁的线程是不会响应其他线程的interrupt()方法的,直到该方法主动释放锁之后才会响应interrupt()方法。
————————————————
当共享资源被某个线程占有,其他请求该资源的thread会被阻塞,从而进入一个双向链表的等待队列
抽象队列同步器 是个父接口 比如reentrantLock semaphore countdownlatch
cyclicbirrer 实现依靠reentrantlock 和 condition实现的
他有个volatile修饰的state属性 使用的cas的方式进行修改属性值 aqs主要有两种形式的锁 独占锁(synchronized和rerntrantlock)和共享锁
state=1的时候,然后后边的话在想进入就会进入双向链表的等待队列尾部
他的解锁上锁使用的底层为park和unpark的机制进行thread的挂起和唤醒
————————————————————————————————————————————————————————
各种bufferpool 和 changebuffer write buffer
bufferpool 是innodb存储殷勤的缓冲池,不属于mysql的server层,主要存储数据页和(写缓冲)changebuffer,用来存储变更记录
如果每次写操作,数据库都直接更新磁盘中的数据,会很占磁盘IO。为了减少磁盘IO,InnoDB在Buffer Pool中开辟了一块内存,用来存储变更记录,为了防止异常宕机丢失缓存,当事务提交时会将变更记录持久化到磁盘(redo log),等待时机更新磁盘的数据文件(刷脏),用来缓存写操作的内存,就是Change Buffer
————————————————
处理数据库死锁问题
间隙锁和next-key lock的引入,解决了幻读的问题,但同时也带来了一些困扰
1.sessionA执行select … for update语句,由于id=9这一行并不存在,因此会加上间隙锁(5,10)
2.sessionB执行select … for update语句,同样会加上间隙锁(5,10),间隙锁之间不会冲突
3.sessionB试图插入一行(9,9,9),被sessionA的间隙锁挡住了,只好进入等待
4.sessionA试图插入一行(9,9,9),被sessionB的间隙锁挡住了
两个session进入互相等待状态,形成了死锁
间隙锁是在可重复读隔离级别下才会生效的。所以,你如果把隔离级别设置为读已提交的话,就没有间隙锁了。但同时,你要解决可能出现的数据和日志不一致问题,需要把 binlog 格式设置为 row(记录每行的修改记录)。
————————————————
快照读:读取的是快照版本。普通的SELECT就是快照读。通过mvcc来进行并发控制的,不用加锁。
当前读:读取的是最新版本。UPDATE、DELETE、INSERT、SELECT … LOCK IN SHARE MODE、SELECT … FOR UPDATE是当前读。
锁还不太清晰,何时间隙锁和临检所
使用next key锁不能完全解决幻读问题,当当前读和快照读同时发生
两次快照读中间一次当前读操作 更新(当前读)使mvcc版本失效了,出现了幻读
java为什么不支持多继承
单继承的话子类可以修改父类的某个方法进行重写,
如果c继承a 和 b 两个类都有同个方法,c去调用这个方法时就无法确定调用哪个
多继承不可以但是可以多实现 实现多个接口,
接口为什么加入了默认方法?
因为多个普通的类实现了接口,扩展增加接口方法所有的实现类必须全部重写这个方法,
因此加入了默认方法就不用去全部重写,方便接口的扩展
冒泡
class Solution {
List<String> rec;
boolean[] vis;
public String[] permutation(String s) {
int n = s.length();
rec = new ArrayList<String>();
vis = new boolean[n];
char[] arr = s.toCharArray();
Arrays.sort(arr);
StringBuffer perm = new StringBuffer();
backtrack(arr, 0, n, perm);
int size = rec.size();
String[] recArr = new String[size];
for (int i = 0; i < size; i++) {
recArr[i] = (i);
}
return recArr;
}
public void backtrack(char[] arr, int i, int n, StringBuffer perm) {
if (i == n) {
rec.String());
return;
}
for (int j = 0; j < n; j++) {
if (vis[j] || (j > 0 && !vis[j - 1] && arr[j - 1] == arr[j])) {
continue;
}
vis[j] = true;
perm.append(arr[j]);
backtrack(arr, i + 1, n, perm);
perm.deleteCharAt(perm.length() - 1);
vis[j] = false;
}
}
}
4.
重点 93复原ip
和接雨水
105 从前序与中序遍历序列构造二叉树
三个树遍历的迭代写法
Lru 缓存
LFU?
二叉树中和为某个值的路径 【注意叶子结点的地方不能写return ,因为需要回溯】
最长公共子数组 最长公共子序列 b编辑距离 使用二维dp n+1 m+1
重排链表(首先根据链表中间节点分成两半,之后一致分到只有单节点【==null】 return 之后 return merage()两个节点 最后合并为一个正的链表) 归并排序 1.中间节点 2.
insert into student(name , age)values(' andy' ,20);
delete from user where id > 4;
update user set username = '百里守约',description = '玄策的哥哥';
update u set cid = 01 where name = 'zs';
tail -f -n10 文件
端口被哪个进程占用
neetstart tunlp|grep 20
neststat tunlp|grep 10
端口是否监听
neatstat anp|grep 端口
CREATE TABLE Person
(
LastName varchar,
FirstName varchar,
Address varchar,
Age int
)
别的区别:::::::
StringBuffer每次获取toString都会直接使用缓存区的 toStringCache值(,一旦StringBuffer被修改就清除这个缓存值。)来构造一个字符串。StringBuilder 则每次都需要复制一次字符数组,再构造一个字符串。所以说StringBuffer利用缓存区进行了部分优化操作。
状态码304,502,504什么含义
502网关错误 504网关超时
301 永久重定向
302 临时重定向
304 自从上次请求后,网址内容没有修改过,服务器不会返回网页的内容,直接使用本地资源即可
502服务器作为网关出错 从上游服务器收到了无效的响应
504服务器作为网关超时了 没有及时收到上游服务器的响应
DNS劫持:攻击dns服务器然后修改域名服务器中的dns缓存让他跳转到错误的网页。
如何预防呢?
通过防火墙限制外来的访问
大部分攻击是通过恶意软件/木马病毒进行攻击,有意避开病毒网站提高服务器安全性。
发生劫持了可以这样:
修改hosts文件,操作系统中Hosts文件的权限优先级高于DNS服务器,
操作系统在访问某个域名时,会先检测HOSTS文件,然后再查询DNS服务器。可以在hosts添加受到污染的DNS地址来解决DNS污染和DNS劫持。
linux沙雕一个进程(查看全部进程和进程id kill沙雕具体的进程id)
ps -ef|grep 某个程序
kill 他的进程id
kill -9 强制杀死 带有强制执行的意思
然后kill
linux如何查看端口被哪个进程占用
netstat -tunlp|grep 端口号
查看端口是否被占用(listen 状态)
netstat -anp|grep 端口号
tail-f -n 10 查看最近10行的日志
查看磁盘占用情况 du -h 查看每个根目录的分区大小
内存占用情况:free 查询
建造者模式说一下 builder
myisam和innodb索引的区别
没有条件的count(*) myisam比innodb快的多,因为myisam有个计数器 可以更快的查询计数
m的主键索引叶子结点具体行数据,二级索引存储的是主键值+索引值
in 的主键和二级索引都是存储的对应数据行的指针,所以他是两个文件
myisam 适合读多写少的场景
1.行锁表锁 表锁
2.支持mvcc并发控制
3.支持事务,可以事务回滚
4.m的count操作,特有一个记录,不用查询,直接返回,i需要去查询
5.支持外键
redis持久化方式,重启时,master和slave读取RDB有什么不同
主节点直接读取reb文件重启
从节点比较runid 是否为上个主节点,runid不同的话直接全量复制
offset和主节点唤醒缓冲区的差值,如果超过唤醒缓冲区直接全量复制,没有的话直接增量复制
rdb 和 aof
7成环 2个thread同时扩容,首先第一个thread把 当前第一个节点转到头结点,然后把第二个节点转到头结点 ,此时变成了21 倒叙,另外一个thread 要把1节点指向链表头结点2所以形成了死链。
jdk7 和jdk8的扩容区别啊
底层数据结构不一样,1.7是数组+链表,1.8则是数组+链表+红黑树结构(当链表长度大于8,转为红黑树)。
JDK1.7用的是头插法,而JDK1.8及之后使用的都是尾插法,那么他们为什么要这样做呢?
为什么开始使用头插法?开始考虑的后插入的元素使用频率会更高容易查找,但是扩容的话会逆序循环死链等问题。
因为JDK1.7是用单链表进行的纵向延伸,当采用头插法时会容易出现逆序且环形链表死循环问题。但是在JDK1.8之后是因为加入了红黑树使用尾插法,能够避免出现逆序且链表死循环的问题。
————————————————
版权声明:本文为CSDN博主「李昊轩的博客」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:
为什么与上2的n次方 求位置的时候,只有这样的话-1就是全1,最大程度减少hash碰撞
因为为了求下标的时候方便查找下标,并且位运算速度快,-1之后为全1减少了hash碰撞
求节点的位置:hash值异或上这个hash右移16位然后与上数组长度-1(相当于取余操作)
7:先扩容后插入 8:先插入后扩容
resize 【创建新的数组 然后迁移节点到新的位置】 扩容 rehash
jdk7的话插入达到阈值如果没有产生hash冲突会直接插入这个位置,直到产生hash冲突才会进行扩容
jdk8到了阈值直接扩容
扩容判断有区别啊:
7的话是hash值 与上 新数组长度-1
8的时候使用这个
hash与旧数组长度为0 位置不变
为1的话长度变为原位置+原数组长度
计算key的位置的值 jdk8 key.hash^(h>>>16)&(length-1)
为什么null在第一个位置?
因为null的hash值为0 索引只能存储在第一个位置
hashmap方null hashtable不可以的 con 也不可以
Redis AOF不也要把日志写到磁盘么,那和MySQL的IO有啥区别,凭啥Redis就快
因为redis aof只有在写入磁盘的时候才会有磁盘io 读写还是在内存
mysql是读写都需要磁盘io
分库分表 : 连接数过多的 只能分库了 分表是单表数据量太大
垂直查分表的话:根据业务进行拆分的【比如商品的简介 和点击的具体详情 将两个操作解耦了 觉少了】
垂直分库: 将SELLER_DB(卖家库),拆分为PRODUCT_DB(商品库)和STORE_DB(店铺库)
水平分库:可以把一个表的数据(按数据行)分到多个不同的库,每个库只有这个表的部分数据,这些库可以分布在不同服务器,从而使访问压力被多服务器负载,大大提升性能。它不仅需要解决跨库带来的所有复杂问题,还要解决数据路由的问题。
水平分表:可以把一个表的数据(按数据行)分到多个同一个数据库的多张表中,每个表只有这个表的部分数据,这样做能小幅提升性能,它仅仅作为水平分库的一个补充优化。
一致性hash 首先根据数据某个自增属性分到一个圆环上的某几个节点,由于可能不均匀所以设置几个虚拟节点分别对应相对应的事迹节点(采用顺时针进行存),然后再添加节点的话直接添加啊新的虚拟节点 只有这个虚拟节点和签个节点直接的数据放入到这个新添假的节点 ,不用全部替换位置。
————————————————
版权声明:本文为CSDN博主「小Y是我的」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:
关系型db和非关系型数据库的区别:
1.关系型db采用关系模型存储在二维表格中
2.非关系型db根据key value 存储在特定的数据结构中,
关系型支持事务 非关系型不支持
new FixedThreadPool
new SingleThreadExecutor
New cCacheThreadPool
CachedThreadPool 是一个会根据需要创建新线程的线程池,
核心线程数 0 最大线程数 Integre.MAX_VALUE 阻塞队列 SynchronousQueue 最长时间 60 秒
如果主线程提交任务的速度高于 maximumPool 中线程处理任务的速度时,CachedThreadPool 会不断创建新线程。极端情况下,CachedThreadPool 会因为创建过多线程而耗尽 CPU 和内存资源。
,适用于执行很多thread的短期异步任务
1.LinkedBlockingQueue是基于链表实现的初始化是可以不用指定队列大小(默认是Integer.MAX_VALUE);ArrayBlockingQueue是基于数组实现的初始化时必须指定队列大小
2.LinkedBlockingQueue在puts操作都会生成新的Node对象,takes操作Node对象在某一时间会被GC,可能会影响GC性能;ArrayBlockingQueue是固定的数组长度循环使用,
不会出现对象的产生与回收
3.LinkedBlockingQueue是基于链表的形式,在执行remove操作时,不用移动其他数据;ArrayBlockingQueue是基于数组,在remove时需要移动数据,影响性能
4.LinkedBlockingQueue使用两个锁将(生产者和消费者两把锁)puts操作与takes操作分开;ArrayBlockingQueue(生产者和消费者用一把锁)使用一个锁来控制,在高并发高吞吐的情况下,LinkedBlockingQueue的性能较好
————————————————
三色标记 在并打标机的阶段
完全扫描黑色,扫描到的灰色 白色没有扫描过的垃圾
并发标记重新标记:都怎摸解决漏标问题的
漏标怎么解决的?
cms:增量更新
插入了一条从黑色对象到白色对象的引用,同时去掉了从黑色对象到这个白色对象的直接引用
增量更新:记下这个黑色对象对白色对象的引用,并发标记结束后,重新标记根据新的引用重新判断
g1:原始快照(satb)
记录下这个删除引用,灰色对象到白色对象的引用,根据这个灰色对象最终标记
CREATE INDEX indexName ON mytable(username(length));
execute和submit 的区别
e = wFixedThreadPool(3);
e.execute(实现Runnable的具体的类);
1.exectue只能提交runnable的任务
submit runnable和callable的都可以
2.exectue没有返回值 submit可以有返回值
3.e 是可以直接抛出异常的
submit的这个返回的future 然后 才能捕获异常
runnable和callable的区别
重写run方法 重写call方法
返回值
runnable不能抛出异常
callable可以抛出异常
runnable可以使用newthread 和 仍如线程池使用
callable 只能放到线程池使用 furetureTask
聚集索引 和非聚集索引
1.聚集索引存储的物理上是连续的,和索引顺序万群一致
费聚集索引物理上是不连续的,和索引的顺序不同
2.聚集索引叶子结点是数据行记录和索引值,存储在一个文件上
费聚集索引的叶子结点是指向数据的地址和索引值,存储在两个文件,
为什么innodb表(聚集索引必须要主键)? 没有主键去第一个非空的唯一索引,或者自己增加个隐藏的row-id
因为主键索引的聚集索引就是根据主键形成的聚集索引
自增主键的坏处?
分布式存储的数据表由于每个表都自增,导致主键冲突
高并发情况下,在innodb中插入可能会导致间隙锁之间的竞争,
对象头、{markword ,对象头的引用 gc的分代年龄4个bit 【这个gc4bit在markword中】
锁的标志位:
指向类的指针(类数据保存在方法区 class)}
实例变量 (各种属性值)
填充字节
01偏向锁 无锁 这两个的区别就是前个标志位区别 0位无锁 1位偏向锁
00 轻量级锁
10 重量级锁
LRU和LFU:
幂等性问题接口:1.使用token字段 或者(根据插入的内容)数据库唯一字段插入数据
2.数据库的唯一id 根据业务的某个值插入数据库看是否能插入
3.字段上设置为多个状态 保证幂等性,根据状态判断是否能继续修改
4.乐观锁 也就是加上version字段
调表:让链表有序,然后向上每隔两个位置引出来个二级链表 一直向上引,直到最后向下根据折半查找一样查找
IO多路复用
奇安信
网易1
网易2021提前
方法区gc的?????????????????????3个条件
方法区的垃圾回收主要有两种,分别是对废弃常量的回收(常量池的回收)和对无用类的回收(类的卸载)。
当一个常量对象不再任何地方被引用的时候,则被标记为废弃常量,这个常量可以被回收。
方法区中的类需要同时满足以下三个条件才能被标记为无用的类:
1.Java堆中不存在该类的任何实例对象;
2.加载该类的类加载器已经被回收;
3.该类对应的java.lang.Class对象不在任何地方被引用,且无法在任何地方通过反射访问该类的方法。
当满足上述三个条件的类才可以被回收,但是并不是一定会被回收,需要参数进行控制,例如HotSpot虚拟机提供了-Xnoclassgc参数进行控制是否回收。
————————————————
版权声明:本文为CSDN博主「五山口老法师」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:
redis哨兵模式:
1.监控(同步所有信息) 所有主节点然后去查看各自的从节点,将信息全都同步到烧饼节点,烧饼节点之间也是互通的
2.通知 (查看各节点状态) 烧饼节点去查看各节点是否在线,然后把状态同时通知给所有的哨兵节点
3.故障转移 当某个主节点挂了 然后当前哨兵认为他挂了,然后别的哨兵也去查看他的状态,超过半数认为他挂了就是当前节点挂了
选一个烧饼节点
首先去选一个哨兵节点(竞选次数多的)让他去选举主节点
1.选择在线的从节点得优先级最高的
2.如果有多个最高优先级的slave,则选取复制偏移量最大(即复制越完整)的当选
3.如果以上条件都一样,选取runid最小的slave。
优先原则:比较offset和runid
通知其他从节点选举出的新节点
关系型和非关系型数据库
1.关系型数据库基于关系模型的,数据存储在行列的表格中,
2.非关系型数据库 主要基于kv键值对的形式
1.关系型数据库存储在磁盘上,非关系型存在内存,读写速度很快
2.关系型db支持事务,redis很难完成事务操作
我的文件助手 16:36:21
了解()么?为什么虚拟机不会立即GC?
只是提醒虚拟机希望进行一次垃圾回收,什么时候回收还是取决虚拟机
我的文件助手 16:36:34
集群的分布式锁怎么实现的?
我的文件助手 16:37:32
集群模式导致session分布问题如何解决
mysql的分层架构
连接层 提供和客户端的连接 【把sql语句交给服务层】
mysql的服务层 解析sql语句,使用优化器优化sql,交给执行器执行
innodb存储引擎层 提供存储引擎进行存取
cas怎么保证原子性的 他使用的unsafe的方法,本地方法,由os完成的,他是属于一种源语,由若干条指令组成的,并且源语的执行必须连续,在执行过程中不能中断, 即是说cas是cpu的原子指令
双写和失效模式
创建订单 (状态 新建状态【订单号枢纽】) 订单项(1.根据当前购物车所有数据
currentUserCartItems.stream().map(cartItem -> {}遍历每个sku
2.根据skuid 获取spu,并且设置上订单号,根据生成 订单 订单项 总价【根据这个进行验价 之后进行保存订单和订单项】)
根据订单项stream出了 skuid 多少件,然后去根据这个参数去锁定库存
3.然后进行了锁定库存【库存工作单+库存详情】
wms_ware_order_task_detail
WareOrderTaskEntity库存工作单【设置一个订单号id OrderSn 用于外边的订单回滚了这个远程调用库存扣减不能实现 的枢纽】
遍历每个skuid过程中 然后去遍历它锁能去扣减的库存id 扣减成功后,保存库存各商品的详情
将WareOrderTaskEntity库存工作单id和库存详情的锁定信息【skuid 锁那个库存 几件】发给延迟队列
另外一端监听延迟队列中发出来到exchange转发到下一个queue的消息
@RabbitListener(){
@RabbitHandler(具体的类型)
unlock(); 前边发送过来了,现在40分钟了 需要库存解锁要去判断幂等性等操作了
解锁库存根据前边传过来的OrderSn查询当前订单
没有订单了(前边回滚了,)或者当前状态为取消去解锁库存
注意啦啊 这里还要去判断库存是否锁定状态,保证幂等性
channel.basicAck();
try catch这个basic.ack操作 出现了异常channel.basicReject();
}
定时关单
生产者把消息发送给rabbitmq server端的过程中丢失 confim处理
returncallback机制 有个设置直接把消息返回生产者
处理都是是否重新发送消息
setmandatory()设置为消息可以返回给生产者
rabbitmq server收到消息后在持久化之前宕机导致数据丢失
接下来到了Mq中了,需要保证消息的持久化
开启消息持久化机制, 和创建交换机和queue【确保这里边的消息不丢失,
持久化队列会被保存在磁盘中,固定并持久的存储】设置为持久化
消费端收到消息还没处理宕机,导致server端以为已经签收了这个消息。 手动ack{有重复消费问题,考虑幂等性}
channel.basicAck() channel.basicReject()
分布式事务,两阶段提交和三阶段提交的好处和坏处,
2pc
事务管理器 本地资源管理器
1.预提交 都预提交并且反应是否可以提交 如果所有的资源管理器都准备成功,事务管理器要求所有的资源管理器执行提交
错误全部回滚
优点:实现方便
缺点: 同步阻塞 单点故障 数据不一致问题
1.2PC是一个同步阻塞协议,资源管理器在执行的过程中会锁定资源。对资源进行了长时间的锁定,并发程度比较低
2.事务管理器存在单点故障的问题,事务管理器故障资源管理器会一直阻塞下去
3.一阶段有超时机制,超时后就会判断为事务失败发送回滚命令,二阶段失败只能不断重试
//重点这个数据不一致问题 如果事务管理器也就是协调者发生故障,资源管理器有的提交了有的没提交一值阻塞
4.二阶段一半的时候协调者(事务管理器)发生异常了,有的提交了有的没提交一致阻塞 不同数据库之间数据不能一致了
2.TCC事务补偿方案【业务代码实现分布式事务】
引入了超时机制(等待超时会中断事务)和准备机制 解决这个同步阻塞和改进数据不一致问题
3pc 同时在事务管理器和本地资源管理器引入了超时
在一阶段和二阶段中间插入了一个准备阶段,保证了提交阶段的各节点状态数据一致
1.事务管理器只是去问资源管理器是否可以执行操作
2.协调者收到参与者的回复后决定是否进行 预操作
如果进行预提交则参与者执行事务操作,记录事务日志,返回操作结果给协调者
如果不能预提交,参与者收到不能提交的消息 或者超时未接收到协调者的消息或者协调者没接收到参与者的响应都中断事务
3.
协调者发送提交或者回滚给参与者
提交的话,参与者收到提交进行正式提交
中断,参与者根据预提交阶段的日志进行回滚
优点和缺点:3pc因为加入了超市机制,在第三阶段如果发生回滚操作的话,因为事务管理器中途故障,本地资源管理器超时会自动提交事务发生了数据不一致问题。
缺点:三阶段仍然存在不一致,如果三阶段的最后中断的提交阶段中断命令参与者没收到的话,参与者超时会自动提交事务(避免了单点问题,不会像二阶段一样一值阻塞不处理)
优点:相比二阶段提交,三阶段提交降低了阻塞范围,在等待超时后协调者或参与者会中断事务。
避免了协调者单点问题,阶段 3 中协调者出现问题时,参与者会继续提交事务。
Try(全部在try阶段完成 事务操作+确认+撤销):对各个服务的资源做检测和 预留业务资源;
Confirm :执行确认操作
Cancel:如果任何一个服务的业务方法执行出错,那么这里就需要进行补偿,即执行回滚操作,释放Try阶段预留的业务资源 ,
try失败直接使用cancel回滚 【2pc一阶段超时直接回滚】
Confirm,Confirm失败后需要进行重试;
CancelCancel失败后需要进行重试
3.最终一致性(加入中间件) 如延迟队列
根据队列状态进行相应的修改操作,实现代码上的回滚
三色标记在cms并发标记阶段 进行可达性分析的
【增量更新和satb原始快照】
漏标的现象 cms使用增量更新 记录下新增的引用(当前节点断开,前边节点引用了这个节点)
g1 satb快照记录,并发标记阶段记录了删除的引用,结束后再次扫描
反射 应用:
.winstance() 不会任何类初始化工作
Class.forname(“类的全局名”) 完成初始化工作
.getclass() 静态初始化和非静态初始化工作都会进行,
反射就是在.class文件通过类加载器加载到jvm后 可以解析出他的所有方法和属性然后可以使用他的对象属性等
应用:
动态代理:
newProxyInstance方法,传递3个参数,分别是:
目标对象的加载器 通过Class().getClassLoader方式获取
目标对象的实现接口类型 通过Class().getInterfaces()方式获取
InnvocationHandler事件处理器 通过new实例化对象并重写invoke方法方式获取
加载数据库的jdbc驱动 classforname
Class.forName(sql.jdbc.Driver"); //加载MySQL驱动
rabbitmq交换机类型:
fanout(发布订阅):不判断routekey,直接发到绑定的所有队列
direct(点对点):必须和routekey 完全一致
topic(模糊匹配) 可以模糊匹配 *一个单词 #多个单词 ad.sad.sda 就是多个单词 sd 一个单词
header: 指定键值对 的
交换机去解开header数据 看是否有匹配的键值对
rabbitmq的持久化机制
exchange queue message 都持久化
都是创建时候自己设置为持久化
rabbitmq启动两个thread 一个负责持久化消息存储
另外一个负责(内存不够时)非持久化消息的存储
消息存储时会在ets表中记录消息在文件中的映射,读取消息时根据这个ets表查找具体的消息
删除消息时只会从ets表删除,变为垃圾数据,当垃圾数据占了一个文件50%,并且文件数到达3个,触发垃圾回收
锁定当前文件左右两个文件,将自己的有效数据写入左边的文件,删除当前文件,完成合并。
写入文件前先写入buffer缓冲区,如果buffer满了,继续写入os的页存
每隔25s刷一次磁盘,把buffer和os的页存数据都落盘,每次写入后没有后续操作直接刷盘
死信队列 延迟队列
1.消息被nack或者reject后并且不重新消费,投递到死新队列
2.延迟队列的ttl时间到了 投入到死新队列
3.队列信息数量到达最大长度 发给死新交换机 传给死新队列
配置为死信消息的话 就会把他通过配置一个死信交换机投入到死新队列,没有配置的话就会直接丢弃
没有配置就会抛弃
延迟队列 配合 死信队列一起使用
5.
如何保证udp的可靠
什么是零拷贝
BIO、NIO、IO多路复用,AIO
hashmap的get方法
1.根据put方法的步骤获得数组的下标【注意扩容转移元素的区别 那个是与上旧的数组的长度 然后判断的】
2.判断根节点是否为查找的元素
3.不是的话向下遍历
mybatis缓存机制:
1.一级缓存,sqlsession级别的查询的时候将查询的数据放入到一级缓存,下次查询直接从sqlsession查询
2.二级缓存(缓存的粒度控制在namespace的级别):跨sqlsession级别的,任何一个sqlsession查询到数据直接放到二级缓存中,别的查询就可以直接去二级缓存加载数据
查询的时候先去缓存查,查不到才去查db放入缓存
先查二级再查一级再db
-Xms 初始堆的大小
-Xmx 最大堆的大小
-Xmn 堆内的新生代的大小
老年代的大小 -Xmx 减去 -Xmn
查看某个端口被哪个进程占用 netstat -tunlp|grep 端口号
查询最新的日志 tail -f -n 10 文件名
查询redis的某个前缀 scan 0 match a* count 10
linux沙雕某个进程 ps-ef|grep 进程名 kill-9
端口是否监听 netstat - anp|grep 端口号
查看磁盘占用情况 du -h
怎么看cpu的使用情况 top
neicun free
tail -f -n 10 文件名
查询redis的某个前缀
scan 0 match aa* count 1000
linux沙雕某个进程
ps-ef|grep 名称 查进程号
kill 进程号
查看某个端口被哪个进程占用
netstat -tunlp|grep 端口号
spring boot启动流程
1.首先main函数中找到run方法,在执行run方法之前 new一个SpringApplication对象
2.进入run方法后,创建应用监听器SpringApplicationRunListeners开始监听
3.加载springboot的配置环境,然后把配置环境加到监听对象中
4.之后加载应用上下文,当做run方法的返回对象
5.最后创建Spring容器 refreshContext(context),实现starter自动化配置和bean的实例化
tcp拆包和粘包
tcp没有数据边界的 基于流传输的
所以当客户端接收服务器端发送的多个数据包时,由于服务端一次读取字节数是不确定的,tcp基于流传输没有数据边界,发生拆包和粘包
应用层上
1.把包封装成固定大小,不足的补0补齐
2.在包的末尾加指定字符 r n ftp就是用这种指定字符解决沾包粘包问题的
3.消息分为消息头+消息体 头部有消息体大小的信息
Java的static关键字理解
静态代码块(方法区)类初始化运行一次
静态方法
静态变量(方法区) 直接类名就可以调用
普通代码块,每个对象创建都会运行一次
而成员属性和成员方法,必须new 对象 成员方法既可以访问静态也可以成员的
静态方法中只能访问静态属性,不能访问成员属性
父类静态代码块 子类静态代码块 父类代码块 父类构造方法 子类代码块 子类构造方法
今晚设计模式专场
单例模式 ,代理模式,工厂模式、建造者模式, 适配器模式、
适配器模式 创建一个适配器接口,创建一个适配器的实现类然后把要使用的类传入适配器的构造方法,之后在实现类的某个方法中直接调用传入类的某个方法
根据不同的类同个方法的实现是不同的 这就是适配器模式
创建一个类 ,放入到一个接口实现类的构造方法中去,调用他的这个方法
装饰器模式,有个装饰器接口,在根据装饰器接口实现一个类,实现方法将前边两个实现类放入构造方法放入新建的装饰器实现类,实现方法的增强
适配器是调用他们的自己实现的方法,装饰器是实现方法的进一步增强【都是直接放入到具体的实现类中去】
工厂模式都是:【一个接口 和(不同对象都去实现这个接口 )】
简单工厂模式,多个不同类实现这个接口,然后设置工厂类根据一个方法不同的输入return不同的对象实例
根据参数不同产生不同的对象实例
工厂方法模式:增加新的产品,不需要去修改工厂类,只需要去实现接口,创造新的实现类,然后创建工厂类,通过不同的方法直接return 具体对象
工厂模式:创建一个总的接口(只有一个抽象方法),多个产品实现这个接口 ,工厂类创建不同类的生成方法直接return自己的对象, 自己去调用具体的工厂类的方法现在。
【工厂模式一个接口只有一个抽象方法】
因为工厂方法模式有一个工厂类,去添加新的对象放大需要在原类进行修改,此时不需要了,直接写一个工厂接口类,然后不同的对象创建一个工厂类 实现方法return自己的对应的对象。
抽象工厂模式: 创建一个总的工厂接口(有多个抽象的方法)【接口上有多个方法实现】有多个抽象方法,然后去实现这个接口,
工厂类根据不同对象的不同抽象方法,有好几个return 对象,自己去调用具体的工厂类的方法现在。
建造者模式(生成器模式)说一下
避免了属性赋值放在构造方法中
builder
将复杂的对象根据生成器然后一步一步构建而成
生成一个当前类的静态内部类的生成器 有和当前类同样的属性,静态内部类他的所有的属性都是通过方法进行构建的(每个方法都返回this自己所以可以使用方法链进行创建对象)
product
装饰器模式:(开闭原则【修改只能扩展 不能那个修改以前的】)
实现同个接口,以前的类传入新的装饰器实现类(实现的同个接口,通过构造方法传入新的接口实现类)这个类实现方法可以进行修饰
适配器没有更多的方法,只是传入到这个方法去调用多个类的同个方法有不同的实现。
SpringMVC(处理器适配器)
Mybatis的设计模式
1.单例模式 errorcontext 错误返回日志
2.代理模式 jdk 和cglib都有,主要的就是jdk的,mapper接口 如MapperProxy
非常典型的,该MapperProxy类实现了InvocationHandler接口,并且实现了该接口的invoke方法。
通过这种方式,我们只需要编写Mapper.java接口类,当真正执行一个Mapper接口的时候,就会转发给MapperProxy.invoke方法
3.工厂模式 sqlsessionfactory
4.建造者模式 sqlsessionfactorybuilder
设计模式及其六大原则
spring中使用了哪些
1.简单工厂模式 根据名称获取具体的bean对象
2.单例模式
3.适配器模式 HandlerAdataper 处理器适配器
4.代理模式 动态代理
六大原则:
单一职责原则(类):一个类只能被一个功能模块使用
里是替换:父类可以的地方子类也可以使用(避免子类扩展别的方法)
依赖倒置原则:上下层模块直接用接口交互,直接通过接口交互【不需要直到怎么实现】(spring中的额大量应用)
接口隔离(接口):一个接口只给一个工能模块使用
开闭原则:类的修改尽量进行扩展 而不是修改,(装饰器模式)
迪米特原则:两个类不直接使用,那么两个类就不应该相互调用
6.
select 'sd'=1; 1 触发全表扫描
select 'dsa'=1; 1
select'123' =123; 1
select '123a' = 123; 1
select 'a123' = 123; 0
泛型试什么?
自定义注解
@Target({ElementType.METHOD,ElementType.FIELD}) //用在什么地方 一般用在方法
@Retention(RetentionPolicy.RUNTIME) //运行时运行
public @interface zhujie {
String value() default "";
}
beanDefinition 是 bean的定义信息:
包括bean的类名 构造参数 属性设置等等
三级缓存中存储的ObjectFactory对象,因为在进行aop对象的时候 必须使用这个初始对象完成aop代理操作
单例模式变为原型bean
scope=”prototype”
迭代器的底层原理?
iterator是个接口,每个集合类都有具体的实现
对集合进行遍历,调用hasnext判断是否有元素
2.next方法来去获取这个元素
2Msl 是4分钟
redis的吞吐量为什么高?
bio nio aio
io 就是io读写操作
bio 同步阻塞:一个连接一个thread,一个thread触发io操作必须等待这个io操作完成,期间不能去做其他工作阻塞主了
nio 同步非阻塞(reactor模型):一个连接一个thread, 一个thread触发io操作后,它可以立即返回,但是需要不断主动轮训去获取执行结果
io多路复用 通知 ,与一个线程维护一个连接相比,io多路复用不需要维护这些线程,交给内核去监控,内核准备好了直接去通知你
aio 异步非阻塞:一个thread触发io操作后他可以去立即返回去做其他工作,内核系统将io操作执行完成之后通知该thread已经执行完成【向内核注册IO操作,内核在IO操作完成后,通知用户程序】 不需要阻塞读写操作
io多路复用:因为nio需要不断的轮训等待,消耗cpu,
整体非阻塞io (读取还是阻塞的) 基于事件通知,当内核准备好了 去通知应用程序
redis询问内核,当内核准备好数据 就会去通知redis【事件通知】来取拿数据,然后去阻塞读写数据
其实io多路复用就是通过一种机制,可以监视多个描述符,一旦某个描述符就绪,就能够通知程序进行相应的操作(通过监视描述符,将对数据库的操作转换成了事件,从而减少了线程切换时上下文的切换和竞争)
同步就是自己主动轮训或者等待
异步就是内核系统执行完成之后去通知这个thread
高效的数据结构 io多路复用(非阻塞io时间通知的)
redis是单线程还是多线程?
以前是单线程 io读写都在worker thread执行
后来多线程,单个worker thread,多个io读写thread,只有workerthread是单的 用来处理具体的命令
挑表 :多级索引 原始一个顺序的单链表
接口幂等:
1.token + redis
2.根据修改的内容 ,添加一个唯一id 别的不能加入了,(比如加入了订单的订单号)
3.乐观锁 根据一个新的字段 实现添加
mybatis 的设计模式 spring(工厂 单例 代理模式 适配器模式(mvc的))
1.工厂模式
sqlsessionfactory
2.建造者模式
sqlsessionFactoryBuilder
3.单例模式 ErrorContext 异常日志的输出
4.代理模式
讲讲mvc
m model 层用于处理具体的事件的,接收来自controller的数据
v 展示层 接收model的返回数据 进行展示
c 接收v层的数据 进一步发给m层进行处理的,处理完成后返还给v 层进行展示
15.TCP和UDP的区别【字节流 报文】,TCP如何保证可靠
三次握首和四次挥手
超时重传 【发送数据包在一定的时间周期内没有收到相应的ACK,等待一定的时间,超时之后就认为这个数据包丢失,就会重新发送】
流量控制
拥塞控制
16.TCP滑动窗口原理,流量控制,拥塞控制是如何实现的
滑动窗口就是解决流量控制问题的,接收方和发送方都维护一个接收窗口和发送窗口,各自的发送窗口取决于接收方的接收窗口
通过接收方发送的确认报文中的窗口大小【16bit 65535】可以用来控制发送方窗口大小
联合索引(a,c,b)是否能够命中,为什么 数据库会有个优化
生产者消费者模型
8.执行一条update语句的具体流程
协城:用户态下的轻量级线程,不需要操作系统内核管理,完全由用户程序控制,性能很大的提升。
写成可以理解为一个方法,用友自己的寄存器和栈,写成调度时,保存自己的寄存器上下文和栈的信息,等切换回来后根据保存的寄存器上下文和栈恢复,直接操作栈基本没有切换的开销,所以上下文切换很快。
线程和协程有什么区别呢?
1、线程是抢占式,而协程是非抢占式的,所以需要用户自己释放使用权来切换到其他协程,因此同一时间其实只有一个协程拥有运行权,相当于单线程的能力。
2、线程是协程的资源。协程通过执行器(Interceptor)来间接使用线程的资源的。
进程之间通信方式: 管道 匿名 命名【不需要父子关系】 共享内存+信号量
1.管道
匿名管道:数据只能单向流动,只能在具有父子关系的进程间使用,管道由父进程创建,fork子进程后,就可以在父子进程之间使用【一个读一个写】
命名管道:他是可以在没有父子关系的进程之间通信。
2.消息队列
进程可以从中读写数据,他可以保存数据,不像匿名管道和命名管道 一旦一个进程关闭后 里面的数据就没有了
3.共享内存+信号量(大于0 就是可用 -1变为0 表示休眠):
共享内存允许多个进程共享一个给定的存储区,配合信号量实现同步
信号量就是个计数器,不能让两个进程同时访问共享内存
进程切换的过程:
每个进程都有个进程控制块(pcb)1.进程标识符pid2.进程状态 3.处理机的信息(寄存器 程序计数器等) 4.资源分配清单
1.保存当前进程状态,程序计数器和寄存器保存在pcb中
2.更新pcb信息,例如更新进程的状态,加入阻塞队列
3.更新pcb信息,另外一个进程,从就绪转为运行
4.将另个进程的上下文从pcb取出来进行执行
进程调度策略:【先来先服务 短作业优先 最短剩余时间优先 时间片轮转 优先级调度】
1.先来先服务:每次去就绪队列中选择一个最先进入队列的进行使用
2.短作业优先:按照运行时间最短的优先进行调度
3.最短剩余时间优先:属于是短作业优先的抢占版本,进来一个进程他需要的时间比当前进程的剩余时间更少的话挂起当前进程,运行新的进程
4.时间片轮转:所有就绪进程按照先来先服务排成一个队列,每次调度,把cpu的时间分配给队列首部执行一个时间片,执行完把它放到队尾,同时继续把cpu时间片分配给队列首部
5.优先级调度:为每个进程分配一个优先级,按照优先级调度
用户态和内核态
用户态(非特权的状态 3 级特权等级):运行用户程序,只能访问受限的资源,不能访问设备,用户态下处理机可抢占
内核态(特权的状态 0级特权等级):运行操作系统程序,处于内核态的 CPU 可以访问操作系统内核数据结构和程序,内核态下的处理机不可抢占
最大的区别:运行在用户态下的程序不能直接访问操作系统内核数据结构和程序,大部分时间都在用户态,需要os帮助完成时就会切换到内核态。
当需要os帮助完成一些用户态没有的特权操作时就需要切换到内核态,最常见的形式就是系统调用
如何从用户态陷入到核心态的方式?????????
如何从用户态转换到内核态。
1.系统调用
用户进程主动发起,用户态进程通过系统调用申请os提供服务完成工作,比如fork()就是执行创建新进程的系统调用
2.发生了异常
会从当前的用户进程切换到处理此异常的内核程序中
3.外围设备中断
从键盘输入时,这些操作只能os来做,程序请求os来完成这些操作,从用户态切换到内核态
限制不同的程序之间的访问能力,防止他们获取别的程序的内存数据,或者获取外围设备的数据, CPU划分出两个权限等级 -- 用户态和内核态。
用户态访问内核态资源的方式?
1.系统调用 就是os的最小功能单位
2.库函数 封装了系统调用的细节,提供接口给用户
3.shell脚本 大部分情况下 Shell 都会去调用内核暴露出来的接口,这就是在使用内核
内存不足时,从设置过期时间的key中使用LRU(最近最久未使用)算法,选择最斤使用最少的
从 所有的key
从设计过期时间的key中使用LFU(最近最少使用)
从所有key
从设计了过期时间的,随机选出数据淘汰
所有key中
内存不足时 不淘汰(redis默认的)
或者从设置了过期时间的key中,选出即将过期的数据
Lru和 redis的内存淘汰的lru【lfu 或者 】
页面置换算法:
为什么使用页面置换算法?
因为应用程序分多次装入到内存,运行过程中发生缺页,要访问的页面不在内存,发生缺页中断,此时os必须在内存选择一个页面把它移除内存,为要访问的页面让出空间,。选择淘汰那个页面的规则额就是页面置换算法。
1.最佳置换算法 (opt) 在未来最长时间内不会被访问的页面置换出去
2.先进先出 【fifo】淘汰最早调入的页面【这个块数增多缺页率坑能下降 只有这个 beloy现象】
3.最近最久未使用{lru} 根据画图 上边第一行直接划线去掉
4.最近最少使用【lfu】设置寄存器记录页面被访问次数,每次置换当前访问次数最少的
零拷贝:
虚拟内存 :: 虚拟地址【虚拟页号,偏移量】 去页表根据虚拟页号查询物理页,然后根据偏移量 找到对应物理内存地址了
程序分多次调入内存,os会把虚拟内存地址 和 物理地址做一个映射,所以可以容纳更多的进程并发执行,
一个进程访问虚拟内存的数据时,根据虚拟页号查询对应的物理页,如果有效说明在物理内存,可以直接访问
如果无效的话(也就是没有映射到物理内存),发生缺页中断,去磁盘中拷贝数据到物理内存,并且刷新页表完成新的映射
对于用户程序很久都用不到的内存空间或者物理内存放不下的数据由操作系统临时放在磁盘上存储,需要的时候由操作系统从磁盘上加载到真实内存中
由于这个虚拟内存发生页面中断,非常耗时的磁盘操作,所以os会在发生这个缺页中断时候,预测还有哪些页即将被访问,将他们一并换入物理页内存从而减少无额也异常的次数
7.
myisam的场景
查询多的,(因为查询的时候直接查询地址,不会存在回表的现象) count多的,不需要去遍历一遍,myisam一致有个记录
还有没有事务操作的
rabbitmq
RabbitMQ一般用来干嘛?你在项目中怎么用的?消息重复消费怎么办?丢失怎么办?
rabbitmq怎么保证可靠性呢?
1.首先发布者到broker中的路由器有个confim回调方法,可以判断是否发送成功,这个返回值没有发送的消息所以需要在发布者这边先保存一下,发布失败的话记录日志就好了(因为rabbitmq丢失信息的几率很低,到时候补个数据就好了),再就是从路由器到队列有个returncallback回调,失败的话回调这个方法,写入到日志就好了
2.消息必须持久化(防止rabbitmq宕机), 持久化将消息写出磁盘(重启后消息仍然存在)
交换机持久化 队列持久化 以及消息持久化
持久化采用了2个thread来保证的
1个thread把持久化的消息的存储
另外一个负责内存不足时非持久化消息的存储
消息存储会在ets表中记录消息在文件中的映射,读取消息时根据这个ets表查询具体的消息
删除消息 只会从ets表中删除这个映射关系,真正的消息变为了垃圾数据,当垃圾数据占了文件50%,并且文件数量到达了3个,就会把当前文件的存在的数据转移到左边文件,删除当前的文件。完成合并
3.手动ack删除消息记录,有重复消费的问题(考虑幂等性处理)
最后把接收方这个自动ack取消掉,改为手动ack这样防止了数据丢失,
但是这种因为业务失败,拒签重新回到队列的一般业务代码除了问题,可能一致重试,所以可以不冲回队列直接记录日志等开发解决。
因为消息消费者消费完成之后,ack回复出现了问题,所以出现重复消费的问题
1.保证消费者端的业务数据幂等性处理【根据db字段判断防止重复消费 比如库存表的是否锁定状态以及订单表是否提交订单】
2.方案2:消费者用消息日志保证幂等
利用一张日志表来记录已经处理成功的消息的 ID,如果新到的消息 ID 已经在日志表中,那么就不再处理这条消息。
注意:此时需要保证每个消息都有唯一的id。
消息堆积怎么处理::::::::::::
1..消息处理的比生产消息的速度更快,导致大量的消息无法消费
2.消息被拒绝,就是消费者出现了问题,又重新入队了,又放到了队首后边的消息就不能重复消费了,所以导致消息持续堆积,
可以加个死信队列进行处理
解决:1.增加消费者的处理能力,采用多线程处理消息,集群进行消费
2.消费者批量获取消息,
sql执行顺序?
1.from
2.join
3.where
4.group by
5.having
6.select
7.order by [asc升序]
8.limit
分布式id:
1.uuid 时间戳+时钟序列+全剧唯一的机器识别码
缺点:16个字节 占空间 2.无序的加入mysql放入索引造成页分裂,性能差
优点 1.就是简单
2.db自增主键
优点:int 类型 占内存少
缺点:1. 磁盘操作,性能低 2.自增的容易被猜出来,不安全3.分布式下加机器的话,步长不能改变了
3.redis的自增 incr id
4.雪花算法 64bit位的
0 41 10 12
41位的时间戳 + 10 位的workid + 12位的序列号
优点:1.三个部分都是自增的 总题自增的 2. 占内存少
缺点:可能存在时钟回拨产生重复的id,
解决的话:保存过去时间内每台机器在当前这一毫秒产生的id的最大值,
比如使用 Map 形式,就是< machine _ id , maxid >,这样如果某台及其发生了时钟回拨,就去map中查找这个最大值+1
分布式锁:
条件:1.分布式环境下,必须同时间一个thread获得锁,
2.可重入的锁
3.必须存在失效时间【防止死锁】
4.非阻塞的 使用while()循环获取
1.redis的倒背如流
redis的如果要实现可重入锁,将value值也就是uuid存入到threadlocal中去,然后和redis的进行比较如果相同,也就是可重入的直接进入。
2.使用db的唯一索引
一个thread 获得锁,释放删除这个插入的行。
1.失效时间的设定,做一个定时任务,每隔一段时间把潮湿的数据清理掉
2.可重入的:在数据库表中介个字段没记录当前锁的及其的主机信息和线程信息,下次先查询这个字段,查到的话直接把锁给他
3.非阻塞的:使用while循环 直到获取锁
根据zk实现,
执行select语句的执行流程?
客户端与服务建立连接。
查询缓存中查询是否执行过当前select语句。如果之前执行过相应的select语句,则执行过的select语句和查询结果会以key-value的形式存放在查询缓存中,其中,key是查询语句,value是查询的结果数据,查询缓存中没有找到相应的数据,则会继续执行后续的查询阶段。
分析器主要是对select语句进行
select语句中如果使用了多个索引,则优化器会决定使用哪个索引来查询数据;再比如,在select语句中,有多表关联的操作,优化器会决定各表的连接顺序,数据表的连接顺序不同,对于执行的效率会大不相同,优化器往往会选择使用查询效率高的连接顺序。
执行,通过存储引擎操作底层的数据文件查询
8.执行一条update语句的具体流程【sql执行流程?】
update T set c = c+1 where id = 1;
连接层 服务层 【优化器 执行器】存储引擎层【架构分为这是3个】
1.执行器首先去存储引擎找id=1这行
2.存储引擎判断这行数据是否在内存中,不在去磁盘读到内存
3.执行器把这行数据完成修改操作
4,存储引擎将新行更新到内存,同时把这个更新操作记录到redolog【buffer】中此时处于prepare阶段,然后告诉执行器执行完成了,可以随时提交事务。
5.执行器生成这个操作的binlog【binlogcache】并把写入磁盘,
6.执行器调用存储引擎的提交事务的接口,redolog改为commit状态,更新完成
commit时候才会把buffer写入到redolog日志
两阶段提交 是为了 binlog和redilog两个日志逻辑上一致,
redolog在内存有个redologbuffer,binlog也有个binlogcache,所以在开启事务处于prepare状态时,执行语句首先写入
到这两个缓存,commit时候才会把buffer写入到redolog日志。事务回滚也是回滚的buffer数据
🎈在update过程中,mysql突然宕机,会发生什么情况?
1.如果redolog写入了,处于prepare状态,binlog还没写入,那么宕机重启后,redolog中的这个事务就直接回滚了。
2.如果redolog写入了,binlog也写入了,但redolog还没有更新为commit状态,那么宕机重启以后,mysql会去检查对应事务在binlog中是否完整。如果是,就提交事务;如果不是,就回滚事务。
🎈如果MySQL宕机,而此时Buffer Pool中修改的数据还没有刷新到磁盘,
如果MySQL宕机,重启时可以读取redo log中的数据,对数据库进行恢复。
为什么可以使用redolog呢?所有修改先写入日志,再更新到Buffer Pool,保证了数据不会因MySQL宕机而丢失,从而满足了持久性要求。
🎈既然redo log也需要在事务提交时将日志写入磁盘,为什么它比 直接将Buffer Pool中修改的数据写入磁盘(即刷脏)要快呢?主要有以下两方面的原因:
刷脏是随机IO,因为每次修改的数据位置随机,但写redo log是追加操作,属于顺序IO。
刷脏是以数据页(Page)为单位的,MySQL默认页大小是16KB,一个Page上一个小修改都要整页写入;而redo log中只包含真正需要写入的部分,无效IO大大减少。
泛型是什么?
泛型就是保证编译期保证类型安全,确保你把正确类型的对象放入到了集合中,避免以前的从集合取对象的类型转换
泛型通过类型擦除来实现工作的,在编译时擦除了所有类型相关的信息。 List<String > 运行时仅用List来表示
无法在运行时访问到类型参数,因为编译器已经把泛型类型转换成了原始类型
泛型中的限定通配符和非限定通配符?
一种是<? extends T>它通过确保类型必须是T的子类来设定类型的上界,另一种是<? super T>它通过确保类型必须是T的父类来设定类型的下界。
另一方面<?>表 示了非限定通配符,因为<?>可以用任意类型来替代。
List<String>传递给一个接受List<Object>参数的方法吗?不可以 因为范围不同了,Object支持的更多
array不支持泛型
TLS对称加密和非对称加密的过程;
1.客户端跟服务端发送 client Hello 把自己支持的tls版本和加密套件 和第一个随机数发给服务端
2.服务端给客户端返回 服务端支持的tls版本和选择的加密套件和 第二个随机数 发给客户端
3.服务端接着把证书和公钥发给客户端端【证书内容 签名算法 签名】
4.客户端验证证书 客户端生成第三个随机数用公钥加密后再发送出去 发给服务端
5.服务端使用私钥解密这个秘钥
6.服务端和客户端都是用前两个随机数和第三个秘钥生成会话秘钥
7.根据这个会话秘钥对称加密
继承和实现的区别
继承就是多个类有部分共同的功能,把这部分抽离出来组成一个类 然后继承这个类就行了
实现:多个类实现的目标是一样的,但是处理的具体方法不一样,抽象出一个接口,实现这个接口去重写自己的方法
如何排查oom
Heap dump文件是一个二进制文件,它保存了某一时刻JVM堆中对象使用情况。Heap Dump文件是指定时刻的Java堆栈的快照,是一种镜像文件。
1.获取dump文件
.JVM的启动参数中加入如下的一些参数:
-XX:+HeapDumpOnOutOfMemoryError
-XX:HeapDumpPath=/usr/local/oom
第一个参数意思是在OOM的时候自动dump内存快照出来,第二个参数是说把内存快照存放在哪里
2.导入mat分析这个dump文件
3.然后去代码查看 修复
常用服务以及它的端口
22ssh
21 ftp
smtp 23
dns 53
80 http
443 https
生产者消费者模型【idea】
跟abc打印一致 生成一个类 然后去设置condition去精确唤醒
while(自己不满足的条件){自己await}
然后设置自己的运行,没去唤醒下一个 比如生产者的put,之后xiaofeizhe.singalAll()
public class t1 {
private Queue queue;
private int max = 16;
private ReentrantLock lock = new ReentrantLock();
private Condition shengchan = wCondition();
private Condition xiaofei = wCondition();
public t1(int size) {
this.max = size;
queue = new LinkedList();
}
public void put(Object o) throws InterruptedException {
lock.lock();
try {
while (queue.size() == max) {
shengchan.await();
}
queue.add(o);
xiaofei.signalAll();
} finally {
lock.unlock();
}
}
public Object take() throws InterruptedException {
lock.lock();
try {
while (queue.size() == 0) {
xiaofei.await();
}
Object item = ve();
shengchan.signalAll();
return item;
} finally {
lock.unlock();
}
}
}
}
cas怎么保证原子性的?
cas底层使用的unsafe方法类的cas方法实现的,这个cas属于一种系统原语,源语有多条指令组成,执行的过程必须是连续的中不可以中断,所以就保证了原子性
maven的package和install的区别?
package 把程序打包放在target目录下
install 程序打包放到target目录下,同时放到Maven的本地仓库,其他程序也可以使用这里面的依赖
深度分页【一般id是普通索引】
分页查询:使用limit ,百万数据分页查询优化
select * from book where type='计算机' and
id >= (select id from book where type='计算机' limit 100000,1)
limit 100;
select*from t where id>=(select id from t limit 10000,1) and t.name = '' limit 100;
1.使用 select*from t limit 10w-10,10
走的全表扫描
2.优化一,采用主键索引查出来这的主键id,select id from t order by id limit 10w-10,10【extra using index 使用了覆盖索引】
3.根据id关联子查询
select t.* from t , ( select id from t order by id limit 1900000,10 ) t1 where t.id = t1.id
传播行为再复习一下 项目总攻
required 需要事务操作 当前存在事务 b直接加入 a不存在事务 b新建个事务
:a没有事务的话,a出问题都不会回滚,b出现问题,b自己回滚
: a有实物的话,a和b同属于一个事务了,都回滚
support
支持当前事务,a没有,b非事务执行
:a没有事务的话,都是非
事务执行,不会滚
a有实物的话,都回滚
mandoitory a 没有事务的话 加入b的话 直接报错
a有实物的话,都回滚
required-new:需要新的事务,挂起旧的事务 a的
都存在事务的话
b挂起了a的事务
a出错的话,a回滚,b不会回滚, b出错的话都会回滚
not soupport 不支池事务,a有实物挂起
never 不支持事务,a存在事务的话报错
nested 存在事务,嵌入进去,没有的话就是新开一个
a 出错 ab同时回滚
b出错 b回滚,a不会回滚
事务什么时候失效?
1.发生了自调用,调用的不是aop对象
this 因为spring事务基于aop执行的,有了声明式事务注解后,把当前对象的代理对象放入到了ioc容器中,以后使用的都是代理对象,以及重写的方法,同时把事务的自动提交关闭,然后去执行代码,出现了异常就会回滚。
同类中的解决办法?
、把methodA()和methodB()分别放到不同的类里 2、自己注入自己,用注入的实例调用 3、获取代理类,利用代理类调用自己类的
A方法@Transactional,B方法没有,B中直接调用A方法那A的@Transactional能生效吗(不会,提示主要和AOP的工作模式有关)
不会,aop的动态代理,主要是用的代理对象放入的ioc容器,自己显示的this调用相当于没有使用代理对象
如果这个有注解的方法是被同一个类中的其他方法调用的,那么该方法的调用并没有通过代理类,而是直接通过原来的那个bean,所以就不会启动transaction,
2.异常try catch了
3.跑出的异常不是RuntimeExeception 和 error的 并且也没有rollbackfor指定
4.使用了多线程,多线程多个连接,事务就会失效
5.使用在了非public方法上,事务也会失效,因为有个失误拦截器,不是public的方法会拦截下来
tcp可靠?序列号 和 确认应答 【保证了数据的有序到达】超时重传 流量控制 拥塞控制
http3次?
tcp的痛点
1.建立连接有点繁琐,
2.tcp存在队头阻塞的问题
3.网络连接迁移断一下的话 需要重新建立tcp连接
队友阻塞,因为tcp的包是严格有序的,某个阻塞了 后边的都会阻塞主
16zijie 8zijie 31 10 12
UDP怎么实现可靠传输(QUIC协议)。视频会议的过程(这个不会,扯了DNS啥的。。。希望大佬教一下)
在应用层进行封装,整合tcp的可靠传输以及udp的效率
1.自定义的连接机制:不需要三次握手,一次数据的往返确认双方的连接标识就可以建立首次连接,
2.连接迁移的优化
客户端随机生成一个64比特的随机数作为标识,客户端服务端都是有这个标识,网络中断只要这个标识不变,就完成了连接迁移
2.解决了队头阻塞的问题,tcp的话有个包丢失了,就会形成队头阻塞,只有包恢复了才能重新传输。
http2的流【多个流代表着多次http1.1中的请求和相应】的概念,多个流共用同个tcp连接,可能造成tcp的队头阻塞
quic使用一个递增number数字的设计,可以让数据报不用再像tcp那样有序确认了,quic支持了乱序确认,当前数据报丢失,只要有新的确认就会继续向右移动这个滑动窗口,丢失的重传过来后根据自己的stream id和一个offset都相同就是丢失那个数据报,offset是(标识当前数据包在当前Stream ID 中的字节偏移量)
3.
流量控制的优化,
基于多个stream流(一次http请求和相应),每个stream有独立的滑动窗口,每个都单独流量控制
限制所有的stream流的总字节数,达到总体的流量控制
4.拥塞控制就是把tcp的各种算法搬到了应用层实现了
quic借鉴了http2的流的概念,区别是quic给每个流提供一个独立的滑动窗口,使依次连接上的多个流没有了依赖关系,不像http2那个流共用一个tcp连接共用一个滑动窗口,丢失一个数据 就会队头阻塞,所以不会有这个队头阻塞的问题,
linux上服务出现大量close_wait连接该怎么排查????晚上复习3次握手4次?
这个是客户端主动发送fin请求后服务端发送ack后进入了close wait状态,
如果服务端发送完数据 服务器不执行sockt的close操作的话,服务器就不能从close wait进入last ack,所以系统会出现很多close wait
原因就是关闭socket不及时:可能io线程被阻塞 一致不能去执行关闭
1.程序问题:如果代码层面忘记了 close 相应的 socket 连接,那么自然不会发出 FIN 包,从而导致 CLOSE_WAIT 累积;
2.可能使用的http1.0 因为是短连接 需要多次tcp的连接 也可能过多
哪个进程id的netstat处于close_wait比较久了,然后看看代码啥的
oom异常能否try catch捕获?
哟ban来说是不可以的因为这种属于error异常,出现的时候已经代表出现了指明的错误,程序就会终止,
仅在我们可控的代码,并且在 try 块中存在申请大量内存的情况下,此时触发的 OOM,才是可以被 catch 住的。
当我们 catch 住 OOM 的时候,我们应该主动释放一些我们可控的内存,做好内存管理,避免在后续的操作中,立即又会触发 OOM,导致崩溃
hashmap的遍历方式 iterator()方法是java.lang.Iterable接口,被Collection继承。
set() 使用foreach 循环 【因为属于fail-fast机制下的 遍历会报错】
2.或者iterator迭代器遍历
Iterator < Entry < Integer, String >> iterator = Set().iterator();
while (iterator.hasNext()) {
Entry < Integer, String > entry = ();
System.out.Key());
————————————————
1.map.keySet();
得到key的组合 然后for() 遍历 也可以get出来value
2.map.values 遍历所有的value 不能遍历key
set Key Value
.数据库全表统计是用count(*)还是count(1)
count(字段):统计不为null的记录数
count(1)比count(主键字段)快 因为1的话只是记录多少行,主键字段还要判空
count(*)和count(1)性能一致,他们俩如果只有主键索引,会根据主键索引去判断多少条记录,如果是存在二级索引,则会优先根据二级索引去查询多少套记录,因为二级索引的叶子结点更小,可以存储更多的记录,io次数会更少
volatile保证可见性和有序性
可见性:会在该字段默认加上一个lock前缀,启用了mesi缓存一致性协议,修改数据的时候会直接写入到主存中【通过store【store之前加lock】和write修改内存的值】,同时根据嗅探机制,其他线程这个变量的值全部失效,再次去获取这个值会直接去主存中去读取
在store之前要加锁,因为如果不加锁的话 可能store操作就触发了嗅探机制,此时还没有write修改主存数据,直接去主存拿数据,取到了脏数据
volatile导致i++操作失效::::::
因为i++分为3个操作 1.将主存的值读入当前thread 的本地内存
那么进行如下过程,则会发生线程安全问题。
有序性:有个内存屏障,读屏障之后的操作不能到前边,写屏障之前的操作不能到后边避免了这个指令重排序的优化
指令重排序:jit的优化,在单线程下指令发生重排序不会影响结果的情况下就会发生重排序,
spring中配置beanl 2. 注解 3. javaconfig
依赖注入bean:1.set 2.构造器注入 3.注解
cas怎么保证原子性的?
cas底层使用的unsafe方法类的cas方法实现的,这个cas属于一种系统原语,源语有多条指令组成,执行的过程必须是连续的中不可以中断,所以就保证了原子性
8.
List、Set接口的区别
list 有序可重复 set无序不可重复【但是linkedHashset是有序的】
list可以加入多个null set只能加入一个null
另外 List 支持for循环,也就是通过下标来遍历,也可以用迭代器,但是set只能用迭代,因为他无序,无法用下标来取得想要的值
线程切换,又问了cpu是如何进行线程切换,如何调度的
用户态和内核态的转换。
IO多路复用epoll水平触发和边缘触发区别
nacos openfeign gateway 为什么用?
用户太(3级特权等级):只能运行用户程序,访问受限的资源,不能访问os内核数据结构和程序,用户态下的处理机可抢占
内核态(0级特权等级):运行os程序,处于内核态下可以访问os内核数据结构和程序,内核态下处理机不可抢占
大部分情况都在用户态,当需要os的操作时需要从用户态转到内核态,最常见的形式系统调用
1.系统调用:
2.发生了异常
3.外围设备中断
软中断和硬中断?
当设备发生某件事情就会发生中断,中断分为上下两部分,上半部分为硬中断门下半部分为软终端
1.硬中断:由外围设备引发的短时间就可以完成工作,
软中断是执行中断指令产生的,处理硬中断未完成的工作
2.硬中断的中断信号由中断控制器提供,软中断由中断指令
用户态访问内核态的3中方式:1.系统调用 2.库函数 3.shell
newfixedthreadpool 核心thread数和最大thread数都为固定值 采用的无界的队列 后边的都无效(非核心thread的存活时间为0,不存在)
newsinglethreadexecutor 核心therad数和最大therad数都为1 ,采用无界队列,适合单thread执行任务
newcahcedthreadpool 可缓冲的thread池 核心为0,最大为Integer——MAXVALUE 使用synchronousqueue 阻塞队列, 非核心thread的最大存活时间为60s,如果一直需要thread处理 会一直生成thread 导致oom
1.linkedblockquue:基于链表实现的他默认为最大值 array的数组实现的自己指定thread数
2.链表的添加元素会一直添加额外节点,占用空间,需要大量的gc会使用,数组固定长度不会
3.链表的remove节点不需要别的节点移动,array删除的话需要移动
4.链表的添加任务和取任务两把锁 array一把锁,链表的性能更好
中断正在运行的thread:
stop方法可以中断,但是不适用 有可能thread未运行完,导致运行出错
使用interrupt打断thread,配合isinterrupt使用,实现therad中断
两个接口中有同名方法,类实现这两个接口会发生什么:会在类中只实现一个方法,不需要关注具体是哪个接口,只是类的功能的扩展
项目中有一个接口,有很多实现类,为什么不直接调用实现类呢?而创建这个接口来调取子类的实现?
设计模式的依赖倒置原则:上下层模块之间直接使用接口进行调用,不需要直到具体怎么实现的
private 属性提供了set get方法去更改属性值,但是为什么不把值直接设置为public进行更改呢?
因为某些属性是只读的如果设置为public 就肯定可以修改了,使用private就可以控制这个属性只读和只改了
多态的优缺点:{1.继承关系2.重写父类的方法3.父类引用指向子类对象 【不能访问子类特有的方法和属性信息】}
优点:提高了代码的扩展性
缺点:不能访问子类特有的方法
项目在运行中,如果一直转圈加载,怎么排查问题
可能是断点打在了方法上了
maven如何解决依赖冲突问题
22端口号 ;ssh
21 ftp
69 tftp
小表在前,大表在后 防止数据倾斜
java socket编程中,哪一个是tcp协议编程会使用的socket对象?
TCP中,客户端用Socket,服务器端用ServerSocket
java NIO中一个选择器可以 (Selector,)用于检查一个或多个NIO Channel状态是否处于可读、可写。
mybatis怎么映射db表和实体类
namespace 对应具体的接口的全类名
select id对应具体的接口
<select id="selectOrder" parameterType="int" resultType="me.gacl.domain.Order"> select order_id id, order_no orderNo,order_price price from orders where order_id=#{id} </select>
select id paramertype resulttype(返回值类型) resultMap(可以实现返回结果的类和数据库名的映射)
property column
实体类 db字段
<resultMap type="com.ity.IntegrationChangeHistoryEntity" id="integrationChangeHistoryMap"><result property="id" column="id"/><result property="memberId" column="member_id"/><result property="createTime" column="create_time"/>
redis的过期键:
主动删除:1s进行10次查询,每次随机查带过期时间的key20个 如果有1/4个过期,那么就继续删除
为什么不是扫描所有的key?
redis单thread,扫所有就卡死了,而且为防止每次扫描都超过1/4,redis为每次扫描加上了一个上线时间默认的25ms。
从库的删除不会自己扫描,是通过主库key过其实,在aof文件中增加一条del指令,同步到所有从库的,从库执行del指令完成删除
redis缓存淘汰c策略
mysql主从和redis主从区别
redis是通过rdb文件将所有的数据都进行同步【全量复制】
redis通过增量复制实时进行同步
mysql主机不会向从机发送任何东西,主从分离,但是redis的主机会,redis主机直接和从机沟通
tcp首部 源端口 目的端口 序号 确认序号
udp首部:源端口目的端口 udp长度 校验和
ip首部:主要包括源ip地址和目标ip地址
··················=======··输入url后物理层、数据链路层、网络层如何工作的
dns解析 然后将http报文传给传输层 分段
1.应用层创建http报文(请求行【方法 url 版本】 请求头【cookie host connection=keepalive】 请求体)
2.传输层和对应ip建立连接,并把数据进行分割,传输给网络层
3.网络层:把数据进行打包加上(ip首部)主要就是源ip和目标ip地址,判断目标地址是否与当前地址处于同一个网络中,如果是直接根据Mac地址发送,否则使用路由表查找下一跳的地址,以及使用ARP协议查询它的Mac地址。
数据链路层:明确了数据要传送到的实际物理地址后封装成真和差错检测,使用交换机来加快传输速率。
每一个数据链路层PPP帧在物理层均被解析为物理层二进制位码流,然后通过电信号、光信号或者无线信号来进行传输,这样整个数据就实现了交换。
网络的大小端模式,数据怎么进行存储 【一般通信都是大端通信】
大端1.数据的低字节保存在内存的高地址,高字节保存在低
小端2.低字节保存在内存的低地址处,高字节保存在内存的高地址处
java程序如何定位死锁
jps获得死锁的线程id
jstack -l id 获得死锁的线程栈信息
cpu使用率 : top
内存使用率:free
linux的磁盘占用情况:du -h
111 top找到使用率高的进程id
使用命令top -H-p PID【注意转换16进制】
333.jstack 进程id |grep 对应的线程id
oom解决:
开启程序是-xx:heapdumponoutofmemoryError
-xx:heapdumpfilepath: 指定的路径
2.启动程序 然后去对应的路径查找文件
3.使用mat分析文件 找到哦啊具体的位置 然后去查找错误
深克隆和浅克隆
浅的:克隆对象和原来的对象赋值一份相同的变量,引用数据类型还是指向同个对象的
a b 量对象 b中引用了a对象
b实现clone方法 ,然后return super.clone
深的:克隆对象和原来对象 赋值一份相同的变量 ,同时引用独享也是复制了一份对象,
两个都实现clone方法
b中
b newb = super.clone();
newb.a = this.b.clone();
本文发布于:2024-01-28 17:38:57,感谢您对本站的认可!
本文链接:https://www.4u4v.net/it/17064347419113.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
留言与评论(共有 0 条评论) |