/*
* 线程池的核心参数有哪些,执行流程是什么?、
* corePoolSize 核心线程数
* MaxPoolSize 最大线程数
* threadFactory 线程工厂
* KeepAliveTime 线程存活时间
* workQueue 队列
* policy 拒绝策略
*
* 当线程池接收到任务,会新建线程,知道当前线程数等于核心线程数,这时候,新来的任务都会放在队列中等待处理
* 队列满了后,会新建线程直到当前线程数等于最大线程数,这时如果在来请求,就会执行拒绝策略
* 如果线程空闲下来,并且队列中没有需要处理的任务,线程在存活时间等于keepaliveTeme的时候,救会被销毁
* */
/*
* HashMap的执行流程
* 通过key的HashCode计算出元素的下标,判断他的存储位置,存储时,如果出现key不同的元素直接覆盖
* 如果有key相同的元素,会放在链表后面,如果链表长度大于8,将会转成红黑树
*
* HashMap不是线程安全的,因为在put方法操作中, 没有被锁修饰,并且有个++count的操作
*
* HashMap扩容
* 当map的中容量达到12,也就是16*0.75的时候,将会发生一次扩容、扩容为当选的两倍就是32
*
* 为什么负载因子是0.75
* 如果负载因子过大,那么扩容的成本就提升了,空间利用率加大,并且发成冲突的概率也会提升,这时就需要更加复杂的数据结构来存储,查询时间下降浪费性能
* 如果负载因子过小,库容成本降低,发生冲突的概率降低,但是空间利用率降低了,存储1M的数据却需要2M的空间
* 并且map对容量有一个硬性的要求,容量必须是2的幂,而当负载因子是0.75的时候,容量正好是一个整数,综合,选取0.75
*
* HashMap允许key或者value为null,HashTable不允许,但是他是线程安全的,因为方法都被syn修饰了
* 多线程情况下推荐使用concurrentHashMap,相比HashTable,它把Hash表分为i6个桶,每个桶都类似一个HashTabel
* 并且相比HashTable,它的加锁方式更加精细,并发效果更好
* */
/*
* Spring的Ioc和Aop
*
* IOc 控制反转,就是说吧创建对象的权力交给了spring,,之前是用new创建对象,现在可以通过di注入,
* 注入的方法有3种,注解注入,setter注入,构造方法注入
*
* AOP :面向切面编程
* 底层是动态代理:就是在程序运行期间,在内存中生成一个aop对象,这个对象包含了目标类的全部方法,并且在特定的切点做的增强
* Spring的AOP有两种 JDK 和CGLIB
* JDK要求被代理的方法必须实现一个接口,核心方法是InvctionHanlder.proxy和invocake方法,当我们调用代理类对象的方法时候
* 代理对象会作为invoke的参数proxy,method和arges传入
* CGLIB:如果目标类没有实现接口,将会执行CGLIB动态代理,它其实就是一个类库,在运行时生成指定对象的一个子类,
* 并且覆盖他特定的方法,覆盖方法时可以增强代码,从而实现AOP,CGLIB是通过继承来实现动态代理的,所以被代理的方法不能被final修饰
* */
/*
* SpringBean的生命周期
* 1、实例一个对象,2、为对象甚至名称、factory等,3、在执行初始化之前,会调用BeanPostProcessorBeforeInit方法对Bean处理
* 4、初始化Bean,5、初始化之后,会调用BeanPostProcessorAfter方法,6、当Bean不需要的时候,会对Bean进行销毁,调用destory-method
* */
/*
* BeanFactory和FactoryBean的区别
* BeanFactory是一个工厂,用来管理所有的Bean,FactoryBean是一个Bean,需要经过前者的管理
* */
/*
* BeanFactory是最顶层的一个接口,提供了最简单的容器功能,负责读取、加载、实例维护bean
* ApplicationContext是实现了BeanFactory的方法,包含的前者的所有功能吗,区别是BeanFactory每次只能加载一个Bean
* 而后者可以在项目启动的时候,实例化全部的Bean
* */
/*
* Spring的作用域
* 单例、多例、session、request
* */
/*
* 说一下Concurrent包下的类,
* Runnable、Callable、timeUnit、ConcurrentHashMap、BlockQueue、ReentrantLock、ThreadFactory、Executor、future、lock
* ReentWriteLock、ReentrantReadWriteLock
* */
/*
* 实现分布式锁的方法
* 1、redis :jedis和redisson jedis.set(key, UniqueId, "NX", "EX", seconds)
* 2、数据库 :在数据库中加一个表,这个表包含几列:锁定的方法加索引、描述、保持数据的时间。释放锁直接删除数据
* 3、Zookeeper :
* */
/*
* 线程的状态
* new、runable、block、wait、计时等待、关闭
* */
/*
* dubbo的序列号方式
* hession、java二进制、文本序列号、json
* */
/*
* 数据库的4大特性
* 原子性:事务要么执行成功,要么失败,不会存在中间环节
* 一致性:数据更改前和后,数据总体不发生改变
* 隔离性:一个数据,同一时间只能有一个请求操作
* 持久性:对数据的操作将永久保存在数据库中
*
* 数据库3范式
* 1、一张表只描述一件事情 2、表中其他列都依赖其主键 3、从表的主键必须是主表的外键
*
* 数据库的隔离级别
* 1、读未提交 2、读已提交 3、可持续读 4、串行化
*
* 事务的传播行为
* */
/*
* 锁
* 公平锁、非公平锁 : 如果锁被其他线程获取,那么当前线程将会进入排队状态,等待线程释放锁。
* 如果当前线程在获取锁的时候,锁刚好释放,那么将会直接获取到锁,好处是可以尽快执行,因为唤醒下一个线程
* 可能需要一些时间,而在唤醒期间这个线程可能已经执行完了。坏处是可能导致后面线程一直没法得到锁,造成线程饥饿
* 重入锁、不可重入锁 : 就是指当前线程在持有这把锁的情况下,可以在不释放锁的情况下,再次获取到这把锁
* 悲观锁、乐观锁 :悲观锁就是指,认为默认认为会有其他线程在我操作的时候修改数据,所有要操作,必须先获取到这把锁
* 乐观锁就是默认不会有其他线程修改数据,但是自己在操作前会判断数据有没有被其他线程修改过,使用的cas思想
* 共享锁、独占锁 : 共享锁就是指一把锁可以同时被多个线程获取到 读锁就是共享锁,写锁就是独占锁
* */
/*
* redis
* 数据结构:string、list、set、zset、hash
* 持久化方式:RDB、AOF 快照:把当前数据当作快照存储下来,把当前所有操作指令记录下来。丢失数据、占用硬盘空间
* 雪崩:指同一时间大面积的key失效,导致数据库链接异常 :给key设置一个随机的失效时间
* 穿透:就是指用户不断发起请求的数据,在缓存和DB中都没有
* 方法二:在缓存查不到,DB中也没有的情况,可以将对应的key的value写为null,或者其他特殊值写入缓存,
* 同时将过期失效时间设置短一点,以免影响正常情况。这样是可以防止反复用同一个ID来暴力攻击。
* 方法三:正常用户是不会这样暴力功击,只有是恶意者才会这样做,可以在网关NG作一个配置项,为每一个IP设置访问阀值。
* 击穿:缓存击穿是指一个key是热点,不停地扛住大并发请求,全都集中访问此key,而当此key过期瞬间,持续的大并发就击穿缓存,全都打在DB上。就又引发雪崩的问题。
* 解决方案:设置热点key不过期。或者加上互斥锁。
*
* redis中如何做到数据同步
* 1、使用定时任务,定时同步数据到redis
* 2、如果数据库执行增删改的操作,就清除reids,下次执行查询的时候查redis没有数据,就会更新到redis最新的
* */
/*
* 消息队列
* 如何保证消息的有序性:可以给消息设置一个全局唯一的递增序列号,通过比较序列号来确定先后顺序
* 如何保证消息不被重复消费:创建一张表用来存储消息的id,已经被消费过的id会放在表里,存在表中的id不会二次被消费
* mq积压了几百万条数据怎么办:
* 1、先修复consumer的问题,确保其恢复消费速度,然后将现有cnosumer都停掉
* 2、新建一个topic,partition是原来的10倍,临时建立好原先10倍或者20倍的queue数量
* 3、然后写一个临时的分发数据的consumer程序,这个程序部署上去消费积压的数据,消费之后不做耗时的处理,直接均匀轮询写入临时建立好的10倍数量的queue
* 4、接着临时征用10倍的机器来部署consumer,每一批consumer消费一个临时queue的数据
* 5、这种做法相当于是临时将queue资源和consumer资源扩大10倍,以正常的10倍速度来消费数据
* 6、等快速消费完积压数据之后,得恢复原先部署架构,重新用原先的consumer机器来消费消息
*
* 秒杀环境如何保证数据不超卖/就剩下一个商品,两个人同时下单,如何解决:使用mq
* */
/*
* 项目是如何解决并发问题的
* 1、数据层
* 集群、分库分表、开启索引、优化sql、搭建缓存服务器、搭建搜索服务器
* 2、项目层
* 采用分布式架构、使用静态页面、使用mq解耦、使用分布式文件存储系统
* 3、应用层
* 使用nginx负载均衡、LVS做二层负载
* */
/*
* mysql优化
* sql优化
* 1、SELECT语句务必指明字段名称
* 2、当只需要一条数据的时候,使用limit 1
* 3、如果排序字段没有用到索引,就尽量少排序
* 4、如果限制条件中其他字段没有索引,尽量少用or、
* 5、尽量用union all代替union
* 6、不使用ORDER BY RAND()
* 7、关于not in和not exists,推荐使用not exists
* 8、避免在 where 子句中对字段进行 null 值判断
* 9、不建议使用%前缀模糊查询
* 10、避免在where子句中对字段进行表达式操作
* 11、SQL语句中IN包含的值不应过多
* 硬件优化
* 1、分库分表
* 2、使用缓存
* 3、使用读写能力高的磁盘
*
*
* 索引分类
* 1、普通索引 2、唯一索引 3、主键索引 4、复合索引 5、全文索引
* 数据库存储引起MyLsam和Innodb的区别
* 1、Innodb支持事务,MyLsam不支持事务
* 2、Innodb支持行锁,MyLsam不支持
* 3、Innodb支持外键,MyLsam不支持
* 4、Innodb是索引表,MyLsam是堆表
* 5、Innodb支持全文索引,MyLsam不支持
* */
/*
* 单例模式
* 单例模式是指在内存中只会创建且仅创建一次对象的设计模式
* public class Singlton {
* private static Singlton singlton;
* private Singlton(){};
* public static Singlton getSinglton(){
* Singlton singlton = new Singlton();
* return singlton;
* }
* }
* */
/*
* java内存模型约定了所有变量都必须存储在主内存中,每个线程拥有自己的工作内存,保存主内存的变量副本,线程之间的变量修改不可见
* 指令重排序是指:JVM 在保证最终结果正确的情况下,可以不按照程序编码的顺序执行语句,尽可能提高程序的性能
* 使用 volatile 关键字修饰的变量,可以保证其指令执行的顺序与程序指明的顺序一致,不会发生顺序变换
* 使用 volatile 关键字修饰的变量,可以保证其内存可见性,即每一时刻线程读取到该变量的值都是内存中最新的那个值,线程每次操作该变量都需要先读取该变量。
* */
/*
- 脏读 :操作A更新了一条时间,操作B读取了更新的数据,但是A操作回滚了,则B操作读取的数据就不对了
幻读 :两次查询数据不一致
不可重复读 :一个事务读取同一条记录2次,得到的结果不一致:
SQL优化
主要是为了避免索引失效
比如:1、不对where子句中进行null判断
2、或者不适用!= 、< >操作符
3、使用exit 代替not in
4、不在where子句中进行函数操作
**/