Java后端开发必备基础

先整理个大纲

目录

Java基础

 1、HashMap的put方法处理逻辑以及线程不安全体现的场景,基于HashMap实现线程安全该怎么改代码,hashMap在jdk7和jdk8的扩容过程,ConcurrentHashMap的jdk7和jdk8的实现原理

2、synchronized和ReentrantLock的区别

3、类加载机制,能否自定义一个java.lang.Thread

4、写代码实现OOM和StackOverflow

5、JVM的内存结构,GC的种类及使用场景、GCRoots有哪些、minorGC和FullGC

6、反射的原理、应用场景

7、Lsit、Set数据结构

8、String、StringBuilder、StringBuffer区别

Spring/微服务相关

1、对CAP、BASE的理解,项目中是怎么取舍的,常用中间件使用的是哪种组合方式

2、对2PC、3PC、TCC的理解

3、Spring中Bean的生命周期和扩展点

4、SpringBoot的启动流程

5、开放性问题

6、动态代理是怎么实现的

7、Spring的Aop?切入点是什么?环绕通知是什么?

8、Spring IOC

9、spring框架用到了哪些设计模式?

10、SpringMVC处理一个请求的过程

11、Springcloud微服务间的调用,如何设计权限限制服务进行调用?

12、RPC和HTTP

13、Spring的事务是怎么实现的

三、多线程相关

1、线程池的7个参数的关系,jdk自带的线程池有哪些,拒绝策略有哪些(频繁)

2、使用线程池提交任务后怎么获取返回结果,用代码实现,注意CountDownLatch的使用

3、项目中使用了哪种线程池,有没有遇到什么坑,关键参数是怎么确定的

4、当一个线程池里的线程异常后会发生什么

5、synchronized

6、对CAS的理解以及存在的问题

7、线程的状态以及如何转换

8、锁升级过程,越详细越好

9、后台服务出现卡顿怎么排查、OOM了怎么排查

10、ThreadLocal的实现原理、存在的问题,InheritableThreadLocal如何使用以及存在的问题

四、数据库相关

1、大表优化的方式

2、B+数B-树

3、索引什么时候失效 索引优化

4、InnoDB和MyISAM对比

5、MySQL的隔离级别,各自解决的问题

6、SQL优化手段有哪些

7、回表

8、主键和唯一索引的区别

9、幻读的解决方法

Reids相关:

1、布隆过滤器

2、redis有哪些数据类型,分别用于什么场景

3、redis底层数据结构-7种

4、redis到底是不是单线程

5、分布式锁常见实现方式有哪些、redis怎么实现分布式锁

6、redis的过期删除策略和淘汰策略

7、Redis的持久化和扩容机制

8、redis为啥这么快

9、如何解决Redis和数据库,数据不一致问题

消息队列:

1、RocketMQ的架构

2、kafka(发布-订阅型)

网络相关

1、HTTP VS HTTPS,SSL证书原理

2、404排查原因

3、TCP 为什么要有 TIME_WAIT 状态?

操作系统相关:

1、阻塞vs非阻塞

2、生产者消费者模型

3、进程线程区别联系


Java基础

 
1、HashMap的put方法处理逻辑以及线程不安全体现的场景,基于HashMap实现线程安全该怎么改代码,hashMap在jdk7和jdk8的扩容过程,ConcurrentHashMap的jdk7和jdk8的实现原理


#1.在jdk1.7中,在多线程环境下,扩容时因为采用头插法,会造成环形链或数据丢失。
#2.在jdk1.8中,在多线程环境下,会发生数据覆盖的情况。
HashMap resize时JAVA8做了优化, 通过(e.hash & oldCap) == 0来判断是否需要移位
ConcurrentHashMap 和JDK6不同,JDK7中除了第一个Segment之外,剩余的Segments采用的是延迟初始化的机制:每次put之前都需要检查key对应的Segment是否为null,如果是则调用ensureSegment()以确保对应的Segment被创建
https://blog.csdn.net/woaiwym/article/details/80675789

2、synchronized和ReentrantLock的区别


ReentrantLock   源码分析   http://www.blogjava.net/zhanglongsr/articles/356782.html
  1.等待可中断,持有锁的线程长期不释放的时候,正在等待的线程可以选择放弃等待,这相当于Synchronized来说可以避免出现死锁的情况。通过lock.lockInterruptibly()来实现这个机制。
2.公平锁,多个线程等待同一个锁时,必须按照申请锁的时间顺序获得锁,Synchronized锁非公平锁,ReentrantLock默认的构造函数是创建的非公平锁,可以通过参数true设为公平锁,但公平锁表现的性能不是很好。
总结
     ReentrantLock在采用非公平锁构造时,首先检查锁状态,如果锁可用,直接通过CAS设置成持有状态,且把当前线程设置为锁的拥有者。
如果当前锁已经被持有,那么接下来进行可重入检查,如果可重入,需要为锁状态加上请求数。如果不属于上面两种情况,那么说明锁是被其他线程持有,
当前线程应该放入等待队列。
     在放入等待队列的过程中,首先要检查队列是否为空队列,如果为空队列,需要创建虚拟的头节点,然后把对当前线程封装的节点加入到队列尾部。由于设置尾部节点采用了CAS,为了保证尾节点能够设置成功,这里采用了无限循环的方式,直到设置成功为止(???这里是不是由于有可能有其他节点同时在尝试加入队列,所以称之为非公平,这里没有保证入队的先后顺序???)。
     在完成放入等待队列任务后,则需要维护节点的状态,以及及时清除处于Cancel状态的节点,以帮助垃圾收集器及时回收。如果当前节点之前的节点的等待状态小于1,说明当前节点之前的线程处于等待状态(挂起),那么当前节点的线程也应处于等待状态(挂起)。挂起的工作是由LockSupport类支持的,LockSupport通过JNI调用本地操作系统来完成挂起的任务(java中除了废弃的suspend等方法,没有其他的挂起操作)。
    在当前等待的线程,被唤起后,检查中断状态,如果处于中断状态,那么需要中断当前线程。

3、类加载机制,能否自定义一个java.lang.Thread


类加载机制
https://www.cnblogs.com/ityouknow/p/5603287.html#:~:text=java%E7%B1%BB%E7%9A%84%E5%8A%A0%E8%BD%BD%E6%9C%BA%E5%88%B6.%201%E3%80%81%E4%BB%80%E4%B9%88%E6%98%AF%E7%B1%BB%E7%9A%84%E5%8A%A0%E8%BD%BD.%20%E7%B1%BB%E7%9A%84%E5%8A%A0%E8%BD%BD%E6%8C%87%E7%9A%84%E6%98%AF%E5%B0%86%E7%B1%BB%E7%9A%84.class%E6%96%87%E4%BB%B6%E4%B8%AD%E7%9A%84%E4%BA%8C%E8%BF%9B%E5%88%B6%E6%95%B0%E6%8D%AE%E8%AF%BB%E5%85%A5%E5%88%B0%E5%86%85%E5%AD%98%E4%B8%AD%EF%BC%8C%E5%B0%86%E5%85%B6%E6%94%BE%E5%9C%A8%E8%BF%90%E8%A1%8C%E6%97%B6%E6%95%B0%E6%8D%AE%E5%8C%BA%E7%9A%84%E6%96%B9%E6%B3%95%E5%8C%BA%E5%86%85%EF%BC%8C%E7%84%B6%E5%90%8E%E5%9C%A8%E5%A0%86%E5%8C%BA%E5%88%9B%E5%BB%BA%E4%B8%80%E4%B8%AAjava.lang.Class%E5%AF%B9%E8%B1%A1%EF%BC%8C%E7%94%A8%E6%9D%A5%E5%B0%81%E8%A3%85%E7%B1%BB%E5%9C%A8%E6%96%B9%E6%B3%95%E5%8C%BA%E5%86%85%E7%9A%84%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%E3%80%82.,%E7%B1%BB%E7%9A%84%E5%8A%A0%E8%BD%BD%E7%9A%84%E6%9C%80%E7%BB%88%E4%BA%A7%E5%93%81%E6%98%AF%E4%BD%8D%E4%BA%8E%E5%A0%86%E5%8C%BA%E4%B8%AD%E7%9A%84Class%E5%AF%B9%E8%B1%A1%EF%BC%8CClass%E5%AF%B9%E8%B1%A1%E5%B0%81%E8%A3%85%E4%BA%86%E7%B1%BB%E5%9C%A8%E6%96%B9%E6%B3%95%E5%8C%BA%E5%86%85%E7%9A%84%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%EF%BC%8C%E5%B9%B6%E4%B8%94%E5%90%91Java%E7%A8%8B%E5%BA%8F%E5%91%98%E6%8F%90%E4%BE%9B%E4%BA%86%E8%AE%BF%E9%97%AE%E6%96%B9%E6%B3%95%E5%8C%BA%E5%86%85%E7%9A%84%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%E7%9A%84%E6%8E%A5%E5%8F%A3%E3%80%82.%20%E7%B1%BB%E5%8A%A0%E8%BD%BD%E5%99%A8%20
加载 校验 准备 解析 初始化
双亲委派,向上委托,向下查找
为对象分配空间,分配方式有 “指针碰撞” 和 “空闲列表” 两种,选择那种分配方式由 Java 堆是否规整决定,而Java堆是否规整又由所采用的垃圾收集器是否带有压缩整理功能决定。
内存分配并发问题,2种方案
CAS+失败重试: CAS 是乐观锁的一种实现方式。所谓乐观锁就是,每次不加锁而是假设没有冲突而去完成某项操作,如果因为冲突失败就重试,直到成功为止。虚拟机采用 CAS 配上失败重试的方式保证更新操作的原子性。
TLAB: 为每一个线程预先在Eden区分配一块儿内存,JVM在给线程中的对象分配内存时,首先在TLAB分配,当对象大于TLAB中的剩余内存或TLAB的内存已用尽时,再采用上述的CAS进行内存分配
JAVA能否自定义一个加载器? https://blog.csdn.net/sufu1065/article/details/106760850

4、写代码实现OOM和StackOverflow


https://blog.csdn.net/universe_ant/article/details/52996398
OOM  对象数量过多
S O F 递归不退出 死循环

5、JVM的内存结构,GC的种类及使用场景、GCRoots有哪些、minorGC和FullGC


堆:  新生代(eden from to 8:1:1) 老年代 
程序计数器
堆 存放对象实例 可能OOM GC区域
栈 存放局部变量 方法出口等 栈帧出入栈 OOM SOF 
方法区 常量 已加载的类信息 静态变量 OOM
JDK8移除永久代,新增元空间,元空间与永久代之间最大的区别在于:元空间并不在虚拟机中,而是使用本地内存。
原因:1、字符串存在永久代中,容易出现性能问题和内存溢出。
  2、类及方法的信息等比较难确定其大小,因此对于永久代的大小指定比较困难,太小容易出现永久代溢出,太大则容易导致老年代溢出。
  3、永久代会为 GC 带来不必要的复杂度,并且回收效率偏低。
  4、Oracle 可能会将HotSpot 与 JRockit 合二为一。

GC种类: 
serial  单线程 效率高 要停工作线程 新生代复制,老年代标记-整理
parallel 
concurrent(CMS) 标记-清除
https://blog.csdn.net/high2011/article/details/80177473
https://www.cnblogs.com/redcreen/archive/2011/05/04/2037029.html
https://blog.csdn.net/weixin_42615068/article/details/102813947

minorGC:新生代gc(复制),eden区满,每发生一次对象年龄+1,超过阈值对象被promote到老年代
majorGC/fullGC:老年代GC(标记-清除/标记-整理),system.gc()/老年代空间不足/方法区空间不足/minorGC后进入老年代的平均大小大于老年代的可用内存

G1收集器:最新的,标记-整理/复制,没有内存碎片,可预测停顿

这几个都是 GCRoots:
两个栈: Java栈 和 Native 栈中所有引用的对象;
两个方法区:方法区中的常量和静态变量;
所有线程对象;
所有跨代引用对象;
和已知 GCRoots 对象同属一个CardTable 的其他对象。

6、反射的原理、应用场景


https://zhuanlan.zhihu.com/p/162971344
调用反射的总体流程如下:
准备阶段:编译期装载所有的类,将每个类的元信息保存至Class类对象中,每一个类对应一个Class对象
获取Class对象:调用x.class/x.getClass()/Class.forName() 获取x的Class对象clz(这些方法的底层都是native方法,是在JVM底层编写好的,涉及到了JVM底层,就先不进行探究了)
进行实际反射操作:通过clz对象获取Field/Method/Constructor对象进行进一步操作

Class类中包含的ReflectionData,用于保存进行反射操作的基础信息
应用场景:
Spring/Spring Boot、MyBatis 等等框架中都大量使用了反射机制。
这些框架中也大量使用了动态代理,而动态代理的实现也依赖反射。
另外,像 Java 中的一大利器 注解 的实现也用到了反射。

7、Lsit、Set数据结构


https://blog.csdn.net/qq_28033239/article/details/98204664
1、List
Arraylist: Object数组(动态数组)
Vector: Object数组
LinkedList: 双向链表(JDK1.6之前为循环链表,JDK1.7取消了循环)
2、Set
HashSet(无序,唯一): 基于 HashMap 实现的,底层采用 HashMap 来保存元素,查找O(1)
LinkedHashSet: LinkedHashSet 继承与 HashSet,并且其内部是通过 LinkedHashMap 来实现的。有点类似于我们之前说的LinkedHashMap 其内部是基于 Hashmap 实现一样,不过还是有一点点区别的。
TreeSet(有序,唯一): 红黑树(自平衡的排序二叉树,查找O(logn))

8、String、StringBuilder、StringBuffer区别

Spring/微服务相关


1、对CAP、BASE的理解,项目中是怎么取舍的,常用中间件使用的是哪种组合方式


CAP: 
 C 一致性 A 可用性 P 分区网络容错性(一般为必须) 另外2个2选1
对于需要确保强一致性的场景如银行一般会选择保证 CP
ETCD,强一致性,CP。ZooKeeper、HBase 就是 CP 架构,Cassandra、Eureka 就是 AP 架构,Nacos 不仅支持 CP 架构也支持 AP 架构

https://gitee.com/SnailClimb/JavaGuide/blob/master/docs/system-design/distributed-system/CAP%E7%90%86%E8%AE%BA.md

BASE:
 Basically Available(基本可用) 、Soft-state(软状态) 和 Eventually Consistent(最终一致性)
牺牲数据的一致性来满足系统的高可用性,系统中一部分数据不可用或者不一致时,仍需要保持系统整体“主要可用”
BASE 是 CAP 理论中 AP 方案的延伸(放弃一定强一致性),但是要达到最终一致性,三种方式:读时修复、写时修复(推荐,性能消耗比较低)、异步修复
https://gitee.com/SnailClimb/JavaGuide/blob/master/docs/system-design/distributed-system/BASE%E7%90%86%E8%AE%BA.md

2、对2PC、3PC、TCC的理解


https://www.cnblogs.com/wudimanong/p/10340948.html
2PC:2阶段提交,请求阶段,提交阶段,事务发起者、协调者、事务参与者(有超时机制)
3PC:precommit,cancommit,docommit,事务发起者、协调者(有超时机制)、事务参与者(有超时机制)
TCC(Try-Confirm-Cancel)又称补偿事务。其核心思想是:"针对每个操作都要注册一个与其对应的确认和补偿(撤销操作)"。对应用的侵入性非常强,业务逻辑的每个分支都需要实现try、confirm、cancel三个操作
《分布式事务之如何基于RocketMQ的事务消息特性实现分布式系统的最终一致性?》 https://www.cnblogs.com/wudimanong/p/10558710.html


3、Spring中Bean的生命周期和扩展点


https://gitee.com/SnailClimb/JavaGuide/blob/master/docs/system-design/framework/spring/Spring%E5%B8%B8%E8%A7%81%E9%97%AE%E9%A2%98%E6%80%BB%E7%BB%93.md

4、SpringBoot的启动流程


https://www.jianshu.com/p/bbb2cbe2c49a
https://www.cnblogs.com/javaguide/p/springboot-auto-config.html
@SpringBootApplication ==》@Configuration配置类,@ComponentScan类,包扫描,@EnableAutoConfiguration根据需求自动加载相关的bean

5、开放性问题


让你实现一个微服务框架,如何设计

6、动态代理是怎么实现的


https://gitee.com/SnailClimb/JavaGuide/blob/master/docs/java/basis/%E4%BB%A3%E7%90%86%E6%A8%A1%E5%BC%8F%E8%AF%A6%E8%A7%A3.md
从 JVM 角度来说,动态代理是在运行时动态生成类字节码,并加载到 JVM 中的。
JDK 动态代理类使用步骤
定义一个接口及其实现类;
自定义 InvocationHandler 并重写invoke方法,在 invoke 方法中我们会调用原生方法(被代理类的方法)并自定义一些处理逻辑;
通过 Proxy.newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h) 方法创建代理对象;

JDK 动态代理有一个最致命的问题是其只能代理实现了接口的类。
为了解决这个问题,我们可以用 CGLIB 动态代理机制来避免。


7、Spring的Aop?切入点是什么?环绕通知是什么?


AOP(Aspect-Oriented Programming:面向切面编程)能够将那些与业务无关,却为业务模块所共同调用的逻辑或责任(例如事务处理、日志管理、权限控制等)封装起来,便于减少系统的重复代码,降低模块间的耦合度,并有利于未来的可拓展性和可维护性。
Spring AOP就是基于动态代理的,如果要代理的对象,实现了某个接口,那么Spring AOP会使用JDK Proxy,去创建代理对象,而对于没有实现接口的对象,就无法使用 JDK Proxy 去进行代理了,这时候Spring AOP会使用Cglib生成一个被代理对象的子类来作为代理
使用 AOP 之后我们可以把一些通用功能抽象出来,在需要用到的地方直接使用即可,这样大大简化了代码量。我们需要增加新功能时也方便,这样也提高了系统扩展性。日志功能、事务管理等等场景都用到了 AOP 。

8、Spring IOC


IoC(Inverse of Control:控制反转)是一种设计思想,就是 将原本在程序中手动创建对象的控制权,交由Spring框架来管理。 IoC 在其他语言中也有应用,并非 Spring 特有。 IoC 容器是 Spring 用来实现 IoC 的载体, IoC 容器实际上就是个Map(key,value),Map 中存放的是各种对象。
将对象之间的相互依赖关系交给 IoC 容器来管理,并由 IoC 容器完成对象的注入。这样可以很大程度上简化应用的开发,把应用从复杂的依赖关系中解放出来。 IoC 容器就像是一个工厂一样,当我们需要创建一个对象的时候,只需要配置好配置文件/注解即可,完全不用考虑对象是如何被创建出来的。

IoC源码阅读https://javadoop.com/post/spring-ioc

9、spring框架用到了哪些设计模式?


https://www.cnblogs.com/kyoner/p/10949246.html#:~:text=Spring%20%E6%A1%86%E6%9E%B6%E4%B8%AD%E7%94%A8%E5%88%B0%E4%BA%86%E5%93%AA%E4%BA%9B%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F%EF%BC%9A%20%E5%B7%A5%E5%8E%82%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F%3A%20Spring%E4%BD%BF%E7%94%A8%E5%B7%A5%E5%8E%82%E6%A8%A1%E5%BC%8F%E9%80%9A%E8%BF%87%20BeanFactory%E3%80%81ApplicationContext%20%E5%88%9B%E5%BB%BA%20bean%20%E5%AF%B9%E8%B1%A1%E3%80%82,Spring%20AOP%20%E5%8A%9F%E8%83%BD%E7%9A%84%E5%AE%9E%E7%8E%B0%E3%80%82%20%E5%8D%95%E4%BE%8B%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F%3A%20Spring%20%E4%B8%AD%E7%9A%84%20Bean%20%E9%BB%98%E8%AE%A4%E9%83%BD%E6%98%AF%E5%8D%95%E4%BE%8B%E7%9A%84%E3%80%82

工厂设计模式 : Spring使用工厂模式通过 BeanFactory、ApplicationContext 创建 bean 对象。
代理设计模式 : Spring AOP 功能的实现。
单例设计模式 : Spring 中的 Bean 默认都是单例的。
模板方法模式 : Spring 中 jdbcTemplate、hibernateTemplate 等以 Template 结尾的对数据库操作的类,它们就使用到了模板模式。
包装器设计模式 : 我们的项目需要连接多个数据库,而且不同的客户在每次访问中根据需要会去访问不同的数据库。这种模式让我们可以根据客户的需求能够动态切换不同的数据源。
观察者模式: Spring 事件驱动模型就是观察者模式很经典的一个应用。
适配器模式 :Spring AOP 的增强或通知(Advice)使用到了适配器模式、spring MVC 中也是用到了适配器模式适配Controller。


10、SpringMVC处理一个请求的过程


11、Springcloud微服务间的调用,如何设计权限限制服务进行调用?

12、RPC和HTTP


Http协议:超文本传输协议,是一种应用层协议。规定了网络传输的请求格式、响应格式、资源定位和操作的方式等。基于TCP
RPC,即 Remote Procedure Call(远程过程调用),是一个计算机通信协议。 该协议允许运行于一台计算机的程序调用另一台计算机的子程序,而程序员无需额外地为这个交互作用编程。
差异:
RPC并没有规定数据传输格式,这个格式可以任意指定,不同的RPC协议,数据格式不一定相同。
Http中还定义了资源定位的路径,RPC中并不需要
最重要的一点:RPC需要满足像调用本地服务一样调用远程服务,也就是对调用过程在API层面进行封装。Http协议没有这样的要求,因此请求、响应等细节需要我们自己去实现。
优点:RPC方式更加透明,对用户更方便。Http方式更灵活,没有规定API和语言,跨语言、跨平台
缺点:RPC方式需要在API层面进行封装,限制了开发的语言环境。
对比:
速度来看,RPC要比http更快,虽然底层都是TCP,但是http协议的信息往往比较臃肿
难度来看,RPC实现较为复杂,http相对比较简单
灵活性来看,http更胜一筹,因为它不关心实现细节,跨平台、跨语言。
因此,两者都有不同的使用场景:
如果对效率要求更高,并且开发过程使用统一的技术栈,那么用RPC还是不错的。
如果需要更加灵活,跨语言、跨平台,显然http更合适

微服务,更加强调的是独立、自治、灵活。而RPC方式的限制较多,因此微服务框架中,一般都会采用基于Http的Rest风格服务。

13、Spring的事务是怎么实现的


三、多线程相关


1、线程池的7个参数的关系,jdk自带的线程池有哪些,拒绝策略有哪些(频繁)


核心线程数、最大线程数、workqueue、非核心线程存活时间、timeunit、饱和拒绝策略、线程工厂
4种拒绝策略:
直接抛异常(默认)、交给调用者执行、直接discard、discard最早未处理的线程

2、使用线程池提交任务后怎么获取返回结果,用代码实现,注意CountDownLatch的使用


ExecutorService接口中有以下方法,返回值是Future:返回值Future也是一个接口,通过他可以获得任务执行的返回值。
<T> Future<T> submit(Callable<T> task);
<T> Future<T> submit(Runnable task, T result);
返回结果是异步的,但是如果调用Future.get()方法时线程还没有执行完,会阻塞
public interface Future<V> {  
    boolean cancel(boolean mayInterruptIfRunning);  
    boolean isCancelled();  
    boolean isDone();  
    V get() throws InterruptedException, ExecutionException;  
    V get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException;  
}


3、项目中使用了哪种线程池,有没有遇到什么坑,关键参数是怎么确定的

4、当一个线程池里的线程异常后会发生什么


1、execute方法执行时,会抛出(打印)堆栈异常。
     submit方法执行时,返回结果封装在future中,如果调用future.get()方法则必须进行异常捕获,从而可以抛出(打印)堆栈异常
2、线程池中一个线程异常了后,不影响其他线程任务
3、线程池会把这个线程移除掉,并创建一个新的线程放到线程池中。

关于异常捕获:
1、线程池中线程中异常尽量手动捕获
2、通过设置ThreadFactory的UncaughtExceptionHandler可以对未捕获的异常做保底处理,通过execute提交任务,线程依然会中断,而通过submit提交任务,可以获取线程执行结果,线程异常会在get执行结果时抛出。

5、synchronized


https://developer.aliyun.com/article/666316 (synchronized源码)
同步方法调用指令读取运行时常量池中方法的 ACC_SYNCHRONIZED 标志来隐式实现的
代码块是由 monitorenter 和 monitorexit 指令来实现同步的
ObjectMonitor中有两个队列,_WaitSet 和 _EntryList,用来保存ObjectWaiter对象列表( 每个等待锁的线程都会被封装成ObjectWaiter对象),_owner指向持有ObjectMonitor对象的线程。
1、当多个线程同时访问一段同步代码时,首先会进入 _EntryList 集合。
2、当线程获取到对象的monitor 后进入 _Owner 区域并把monitor中的owner变量设置为当前线程同时monitor中的计数器count加1。
3、若线程调用 wait() 方法,将释放当前持有的monitor,owner变量恢复为null,count自减1,同时该线程进入 WaitSet集合中等待被唤醒。
4、若线程被唤醒重新获取对象monitor后进入_Owner 区域并把monitor中的owner变量设置为当前线程同时monitor中的计数器count加1。
5、若当前线程执行完毕也将释放monitor(锁)并复位变量的值,以便其他线程进入获取monitor(锁)。


6、对CAS的理解以及存在的问题

7、线程的状态以及如何转换


https://zhuanlan.zhihu.com/p/130875882
New(新创建)
Runnable(可运行)
Blocked(被阻塞)
Waiting(等待)
Timed Waiting(计时等待)
Terminated(被终止)


8、锁升级过程,越详细越好


https://www.cnblogs.com/mingyueyy/p/13054296.html  (好帖)
偏向锁01(无锁为001,偏向锁为101,前一位表示当前是无锁还是偏向锁)、自旋锁00、重量级锁11,
synchronized的执行过程:
1. 检测Mark Word里面是不是当前线程的ID,如果是,表示当前线程处于偏向锁
2. 如果不是,则使用CAS将当前线程的ID替换Mard Word,如果成功则表示当前线程获得偏向锁,置偏向标志位1
3. 如果失败,则说明发生竞争,撤销偏向锁,进而升级为轻量级锁。
4. 当前线程使用CAS将对象头的Mark Word替换为锁记录指针,如果成功,当前线程获得锁
5. 如果失败,表示其他线程竞争锁,当前线程便尝试使用自旋来获取锁。
6. 如果自旋成功则依然处于轻量级状态。
7. 如果自旋失败(默认10次)或者当前自旋线程数超过了cpu总线程的一半,则升级为重量级锁。

9、后台服务出现卡顿怎么排查、OOM了怎么排查

10、ThreadLocal的实现原理、存在的问题,InheritableThreadLocal如何使用以及存在的问题


Thread 类中有一个 threadLocals 和 一个 inheritableThreadLocals 变量,它们都是 ThreadLocalMap 类型的变量,我们可以把 ThreadLocalMap 理解为ThreadLocal 类实现的定制化的 HashMap。默认情况下这两个变量都是 null,只有当前线程调用 ThreadLocal 类的 set或get方法时才创建它们,实际上调用这两个方法的时候,我们调用的是ThreadLocalMap类对应的 get()、set()方法。
内存泄漏问题:ThreadLocalMap 中使用的 key 为 ThreadLocal 的弱引用,而 value 是强引用。所以,如果 ThreadLocal 没有被外部强引用的情况下,在垃圾回收的时候,key 会被清理掉,而 value 不会被清理掉。这样一来,ThreadLocalMap 中就会出现 key 为 null 的 Entry。假如我们不做任何措施的话,value 永远无法被 GC 回收,这个时候就可能会产生内存泄露。ThreadLocalMap 实现中已经考虑了这种情况,在调用 set()、get()、remove() 方法的时候,会清理掉 key 为 null 的记录。使用完 ThreadLocal方法后 最好手动调用remove()方法

InheritableThreadLocal:
在thread的init方法内判断有无父线程,且父线程的InheritableThreadLocal是否为空,不为空则将父线程的InheritableThreadLocal传递给子线程
问题:
线程池中的线程是反复使用的,可能发生value串位问题
如果需要解决这个问题,可以自定义一个RunTask类,使用反射加代理的方式来实现业务主线程存放在InheritableThreadLocal中值的间接复制。


四、数据库相关


事务有4个非常重要的特性 A(原子性)C(一致性)I(隔离性)D(持久性)
数据库基本设计规范:
https://gitee.com/SnailClimb/JavaGuide/blob/master/docs/database/MySQL%E9%AB%98%E6%80%A7%E8%83%BD%E4%BC%98%E5%8C%96%E8%A7%84%E8%8C%83%E5%BB%BA%E8%AE%AE.md


1、大表优化的方式


https://zhuanlan.zhihu.com/p/147615129

2、B+数B-树

3、索引什么时候失效 索引优化


https://www.cnblogs.com/liehen2046/p/11052666.html#:~:text=%E7%B4%A2%E5%BC%95%E5%A4%B1%E6%95%88%E7%9A%847%E7%A7%8D%E6%83%85%E5%86%B5.%20%E7%AE%80%E8%BF%B0.%20%E4%BB%80%E4%B9%88%E6%97%B6%E5%80%99%E6%B2%A1%E7%94%A8.%201.%E6%9C%89or%E5%BF%85%E5%85%A8%E6%9C%89%E7%B4%A2%E5%BC%95%3B,2.%E5%A4%8D%E5%90%88%E7%B4%A2%E5%BC%95%E6%9C%AA%E7%94%A8%E5%B7%A6%E5%88%97%E5%AD%97%E6%AE%B5%3B%203.like%E4%BB%A5%25%E5%BC%80%E5%A4%B4%3B%204.%E9%9C%80%E8%A6%81%E7%B1%BB%E5%9E%8B%E8%BD%AC%E6%8D%A2%3B%205.where%E4%B8%AD%E7%B4%A2%E5%BC%95%E5%88%97%E6%9C%89%E8%BF%90%E7%AE%97%3B%206.where%E4%B8%AD%E7%B4%A2%E5%BC%95%E5%88%97%E4%BD%BF%E7%94%A8%E4%BA%86%E5%87%BD%E6%95%B0%3B

什么时候索引失效(避免索引失效,即为索引优化)
1.如果条件中有or,即使其中有部分条件带索引也不会使用(这也是为什么尽量少用or的原因)
2.复合索引未用左列字段;
3.like以%开头;
4.存在索引列的数据类型隐形转换,则用不上索引,比如列类型是字符串,那一定要在条件中将数据使用引号引用起来,否则不使用索引
5.where中索引列有运算;
6.where中索引列使用了函数;
7.如果mysql觉得全表扫描更快时(数据少);
什么时候没必要用索引
1. 数据唯一性差(一个字段的取值只有几种时)
2.频繁更新的字段不用(更新索引消耗);
3.where中不用的字段;(只有在where语句出现,mysql才会去使用索引)
4.where 子句里对索引列使用不等于(<>),使用索引效果一般
查看sql有没有用索引:explain + sql

4、InnoDB和MyISAM对比


https://blog.csdn.net/qq_35642036/article/details/82820178
innodb支持:事务,异常恢复(redo),行级锁,外键
1. InnoDB支持事务,MyISAM不支持,对于InnoDB每一条SQL语言都默认封装成事务,自动提交,这样会影响速度,所以最好把多条SQL语言放在begin和commit之间,组成一个事务; 
2. InnoDB支持外键,而MyISAM不支持。对一个包含外键的InnoDB表转为MYISAM会失败; 
3. InnoDB是聚集索引,使用B+Tree作为索引结构,数据文件是和(主键)索引绑在一起的(表数据文件本身就是按B+Tree组织的一个索引结构),必须要有主键,通过主键索引效率很高。但是辅助索引需要两次查询,先查询到主键,然后再通过主键查询到数据。因此,主键不应该过大,因为主键太大,其他索引也都会很大。
4. InnoDB不保存表的具体行数,执行select count(*) from table时需要全表扫描。而MyISAM用一个变量保存了整个表的行数,执行上述语句时只需要读出该变量即可,速度很快(注意不能加有任何WHERE条件);
5. Innodb不支持全文索引,而MyISAM支持全文索引,在涉及全文索引领域的查询效率上MyISAM速度更快高;PS:5.7以后的InnoDB支持全文索引了
6. MyISAM表格可以被压缩后进行查询操作
7. InnoDB支持表、行(默认)级锁,而MyISAM支持表级锁
8、InnoDB表必须有唯一索引(如主键)(用户没有指定的话会自己找/生产一个隐藏列Row_id来充当默认主键),而Myisam可以没有
9、Innodb存储文件有frm、ibd,而Myisam是frm、MYD、MYI
        Innodb:frm是表定义文件,ibd是数据文件
        Myisam:frm是表定义文件,myd是数据文件,myi是索引文件

5、MySQL的隔离级别,各自解决的问题


RU
RC 脏读
RR 不可重复读(一条数据中的字段被修改)
SER 幻读(同一条语句查询出来的数据条数不一样)

6、SQL优化手段有哪些


数据库优化:
1、sql/索引优化
2、数据库结构优化
① 表的字段长度尽可能小
一般说来数据库的表越小,那么它的查询速度就越快,因此为了提高表的效率,应该将表的字段设置的尽可能小,比如身份证号,可以设置为 char(18) 就不要设置为 varchar(18)。
② 使用最简单数据类型
能使用 int 类型就不要使用 varchar 类型,因为 int 类型比 varchar 类型的查询效率更高。
③ 尽量少定义 text 类型
text 类型的查询效率很低,如果必须要使用 text 定义字段,可以把此字段分离成子表,需要查询此字段时使用联合查询,这样可以提高主表的查询效率。
④ 适当分表、分库策略
分表和分库方案也是我们经常说的垂直分隔(分表)和水平分隔(分库)。
分表是指当一张表中的字段更多时,可以尝试将一张大表拆分为多张子表,把使用比较高频的主信息放入主表中,其他的放入子表,这样我们大部分查询只需要查询字段更少的主表就可以完成了,从而有效的提高了查询的效率。
分库是指将一个数据库分为多个数据库。比如我们把一个数据库拆分为了多个数据库,一个主数据库用于写入和修改数据,其他的用于同步主数据并提供给客户端查询,这样就把一个库的读和写的压力,分摊给了多个库,从而提高了数据库整体的运行效率。
3、硬件升级
https://www.cnblogs.com/liaowenhui/p/12318812.html#:~:text=MySQL%20%E6%95%B0%E6%8D%AE%E5%BA%93%E5%B8%B8%E8%A7%81%E7%9A%84%E4%BC%98%E5%8C%96%E6%89%8B%E6%AE%B5%E5%88%86%E4%B8%BA%E4%B8%89%E4%B8%AA%E5%B1%82%E9%9D%A2%EF%BC%9A%20SQL%20%E5%92%8C%E7%B4%A2%E5%BC%95%E4%BC%98%E5%8C%96%E3%80%81%E6%95%B0%E6%8D%AE%E5%BA%93%E7%BB%93%E6%9E%84%E4%BC%98%E5%8C%96%E3%80%81%E7%B3%BB%E7%BB%9F%E7%A1%AC%E4%BB%B6%E4%BC%98%E5%8C%96%20%E3%80%82%20%E6%AD%A4%E4%BC%98%E5%8C%96%E6%96%B9%E6%A1%88%E6%8C%87%E7%9A%84%E6%98%AF%E9%80%9A%E8%BF%87,%E4%BC%98%E5%8C%96%20SQL%20%E8%AF%AD%E5%8F%A5%E4%BB%A5%E5%8F%8A%E7%B4%A2%E5%BC%95%20%E6%9D%A5%E6%8F%90%E9%AB%98%20MySQL%20%E6%95%B0%E6%8D%AE%E5%BA%93%E7%9A%84%E8%BF%90%E8%A1%8C%E6%95%88%E7%8E%87
(1) 查询具体的字段而非全部字段 任何地方都不要使用select * from t
(2) 优化子查询
尽量使用 Join 语句来替代子查询,因为子查询是嵌套查询,而嵌套查询会新创建一张临时表,而临时表的创建与销毁会占用一定的系统资源以及花费一定的时间,但 Join 语句并不会创建临时表,因此性能会更高。
(3)尽量使用小表驱动大表(注意查询结果集)
我们要尽量使用小表驱动大表的方式进行查询,也就是如果 B 表的数据小于 A 表的数据,那执行的顺序就是先查 B 表再查 A 表
(4) 适当增加冗余字段
增加冗余字段可以减少大量的连表查询,因为多张表的连表查询性能很低,所有可以适当的增加冗余字段,以减少多张表的关联查询,这是以空间换时间的优化策略。
(5) 当只要一行数据时使用limit 1
查询时如果已知会得到一条数据,这种情况下加上limit 1会增加性能。因为MySQL数据库引擎会在找到一条结果停止搜索,而不是继续查询下一条是否符合标准直到所有记录查询完毕。
(6)对于连续数值,使用BETWEEN不用IN,in可能会索引失效
使用in时,当IN的取值范围较大时可能会导致索引失效,走全表扫描
(7) 排查慢SQL
慢查询:超过指定时间的SQL语句查询称为“慢查询”。
慢查询通常的排查手段是先使用慢查询日志功能,查询出比较慢的 SQL 语句,然后再通过 explain 来查询 SQL 语句的执行计划,最后分析并定位出问题的根源,再进行处理。

7、回表


https://juejin.cn/post/6938357172791148575
先定位主键值,再定位行记录
 InnoDB 存储引擎中,如果不是主键索引,叶子节点存储的是主键+列值。最终还是要“回表”,也就是要通过主键再查找一次,这样就会比较慢。覆盖索引就是把要查询出的列和索引是对应的,不做回表操作
将被查询的字段,建立到联合索引里去(或者说 查询的字段都已经建立了索引)

8、主键和唯一索引的区别


主键是一种约束,唯一索引是一种索引,两者在本质上是不同的。
主键创建后一定包含一个唯一性索引,唯一性索引并不一定就是主键。
唯一性索引列允许空值,而主键列不允许为空值。
主键列在创建时,已经默认为空值 + 唯一索引了。
主键可以被其他表引用为外键,而唯一索引不能。
一个表最多只能创建一个主键,但可以创建多个唯一索引。
主键更适合那些不容易更改的唯一标识,如自动递增列、身份证号等。
在 RBO 模式下,主键的执行计划优先级要高于唯一索引。 两者可以提高查询的速度。

9、幻读的解决方法


MVCC 多版本控制

Reids相关:


1、布隆过滤器

2、redis有哪些数据类型,分别用于什么场景


string(SDS int,raw或者是embstr)
介绍 :string 数据结构是简单的 key-value 类型。虽然 Redis 是用 C 语言写的,但是 Redis 并没有使用 C 的字符串表示,而是自己构建了一种 简单动态字符串(simple dynamic string,SDS)。相比于 C 的原生字符串,Redis 的 SDS 不光可以保存文本数据还可以保存二进制数据,并且获取字符串长度复杂度为 O(1)(C 字符串为 O(N)),除此之外,Redis 的 SDS API 是安全的,不会造成缓冲区溢出。
常用命令: set,get,strlen,exists,decr,incr,setex 等等。
应用场景: 一般常用在需要计数的场景,比如用户的访问次数、热点文章的点赞转发数量等等。
list(早期版本中,列表对象使用的编码是ziplist或linkedlist,现在使用的是快速列表(quicklist))
介绍 :list 即是 链表。链表是一种非常常见的数据结构,特点是易于数据元素的插入和删除并且可以灵活调整链表长度,但是链表的随机访问困难。许多高级编程语言都内置了链表的实现比如 Java 中的 LinkedList,但是 C 语言并没有实现链表,所以 Redis 实现了自己的链表数据结构。Redis 的 list 的实现为一个 双向链表,即可以支持反向查找和遍历,更方便操作,不过带来了部分额外的内存开销。
常用命令: rpush,lpop,lpush,rpop,lrange,llen 等。
应用场景: 发布与订阅或者说消息队列、慢查询。
set(intset、字典 不满足intset使用条件的情况下都使用字典(拉链法),使用字典时把value设置为null)
介绍 : set 类似于 Java 中的 HashSet 。Redis 中的 set 类型是一种无序集合,集合中的元素没有先后顺序。当你需要存储一个列表数据,又不希望出现重复数据时,set 是一个很好的选择,并且 set 提供了判断某个成员是否在一个 set 集合内的重要接口,这个也是 list 所不能提供的。可以基于 set 轻易实现交集、并集、差集的操作。比如:你可以将一个用户所有的关注人存在一个集合中,将其所有粉丝存在一个集合。Redis 可以非常方便的实现如共同关注、共同粉丝、共同喜好等功能。这个过程也就是求交集的过程。
常用命令: sadd,spop,smembers,sismember,scard,sinterstore,sunion 等。
应用场景: 需要存放的数据不能重复以及需要获取多个数据源交集和并集等场景
hash(ziplist或者hashtable(字典))
介绍 :hash 是一个 string 类型的 field 和 value 的映射表,特别适合用于存储对象,后续操作的时候,你可以直接仅仅修改这个对象中的某个字段的值。 比如我们可以 hash 数据结构来存储用户信息,商品信息等等。
常用命令: hset,hmset,hexists,hget,hgetall,hkeys,hvals 等。
应用场景: 系统中对象数据的存储。
sortedset(数据少时用ziplist,数据多用skiplist skiplist底层是zset结构,包含一个字典和一个跳跃表,字典用来根据数据查score,跳表用来根据score查找数据(查找效率高))
介绍: 和 set 相比,sorted set 增加了一个权重参数 score,使得集合中的元素能够按 score 进行有序排列,还可以通过 score 的范围来获取元素的列表
常用命令: zadd,zcard,zscore,zrange,zrevrange,zrem 等。
应用场景: 需要对数据根据某个权重进行排序的场景。比如在直播系统中,实时排行信息包含直播间在线用户列表,各种礼物排行榜,弹幕消息(可以理解为按消息维度的消息排行榜)等信息。
bitmap
介绍: bitmap 存储的是连续的二进制数字(0 和 1),通过 bitmap, 只需要一个 bit 位来表示某个元素对应的值或者状态,key 就是对应元素本身 。我们知道 8 个 bit 可以组成一个 byte,所以 bitmap 本身会极大的节省储存空间。
常用命令: setbit 、getbit 、bitcount、bitop
应用场景: 适合需要保存状态信息(比如是否签到、是否登录...)并需要进一步对这些信息进行分析的场景。比如用户签到情况、活跃用户情况、用户行为统计(比如是否点赞过某个视频)。


3、redis底层数据结构-7种


https://blog.csdn.net/weixin_41519463/article/details/109208476
SDS
优点:
1>获取字符串长度的复杂度为O(1)。
2>杜绝缓存区溢出。因为其API会进行空间扩展,扩展之后未使用字节数量free和已使用字节数量len一样
3>减少字符串修改时的内存重分配次数,因为有free(预分配),所有在最坏的情况下就是修改n次,重分配n次。

链表
字典
跳跃表
跳跃表是一种有序的数据结构,通过每个节点中维持多个指向其他节点的指针,从而达到快速访问节点的目的。这种数据结构可以在小于等于O(n)的情况下找到相应的数据。
1>由很多层组成
2>每一层都是一个有序的链表
3>最底层的链表包含了所有的元素;
4>如果一个元素出现在某一层的链表中,那么在该层之下的链表也全都会出现(上一层的元素是当前层的元素的子集);
5>链表中的每个节点都包含两个指针,一个指向同一层的下一个链表节点,另一个指向下一层的同一个链表节点;

intset
只有当数据全是整数值,而且数量少于512个时,才使用intset,intset是一个由整数组成的有序集合,可以保存类型为int16_t、int32_t 或者int64_t 的整数值,并且保证集合中不会出现重复元素,可以进行二分查找。

压缩列表ziplist
压缩列表(ziplist)是Redis为了节省内存而开发的,是由一系列特殊编码的连续内存块组成的顺序型数据结构,一个压缩列表可以包含任意多个节点(entry),每个节点可以保存一个字节数组或者一个整数值。

快速列表quicklist
(1)由于使用链表的附加空间相对太高以及内存碎片化等缺点,Redis后续版本对列表数据结构进行改造,使用quicklist代替了ziplist和linkedlist。
(2)快速列表有quicklistNode和quicklist结构组成
quicklist实际上是ziplist和linkedlist的混合体,它将linkedlist按段进行切分,每一段使用ziplist进行紧凑存储,多个ziplist之间使用双向指针进行串接。

4、redis到底是不是单线程


5、分布式锁常见实现方式有哪些、redis怎么实现分布式锁


6、redis的过期删除策略和淘汰策略


7、Redis的持久化和扩容机制


8、redis为啥这么快


9、如何解决Redis和数据库,数据不一致问题


消息队列:


1、RocketMQ的架构


2、kafka(发布-订阅型)


主要的优势如下:
极致的性能 :基于 Scala 和 Java 语言开发,设计中大量使用了批量处理和异步的思想,最高可以每秒处理千万级别的消息。
生态系统兼容性无可匹敌 :Kafka 与周边生态系统的兼容性是最好的没有之一,尤其在大数据和流计算领域。

消息模型:
1、队列模型
使用队列(Queue)作为消息通信载体,满足生产者与消费者模式,一条消息只能被一个消费者使用(也是缺陷),未被消费的消息在队列中保留直到被消费或超时。
2、发布-订阅模型:Kafka 消息模型(kafka采用的模型)
使用主题(Topic) 作为消息通信载体,类似于广播模式;发布者发布一条消息,该消息通过主题传递给所有的订阅者,在一条消息广播之后才订阅的用户则是收不到该条消息的。

几个重要概念:
Producer(生产者) : 产生消息的一方。
Consumer(消费者) : 消费消息的一方。
Broker(代理) : 可以看作是一个独立的 Kafka 实例。多个 Kafka Broker 组成一个 Kafka Cluster。
Topic(主题) : Producer 将消息发送到特定的主题,Consumer 通过订阅特定的 Topic(主题) 来消费消息。
Partition(分区) : Partition 属于 Topic 的一部分。一个 Topic 可以有多个 Partition ,并且同一 Topic 下的 Partition 可以分布在不同的 Broker 上,这也就表明一个 Topic 可以横跨多个 Broker 。这正如我上面所画的图一样。

Kafka 如何保证消息的消费顺序?
Kafka 中 Partition(分区)是真正保存消息的地方, Partition(分区) 又存在于 Topic(主题) 这个概念中,并且我们可以给特定 Topic 指定多个 Partition。每次添加消息到 Partition(分区) 的时候都会采用尾加法。Kafka 只能为我们保证 Partition(分区) 中的消息有序,而不能保证 Topic(主题) 中的 Partition(分区) 的有序。
消息在被追加到 Partition(分区)的时候都会分配一个特定的偏移量(offset)。Kafka 通过偏移量(offset)来保证消息在分区内的顺序性。
Kafka 中发送 1 条消息的时候,可以指定 topic, partition, key,data(数据) 4 个参数。如果你发送消息的时候指定了 Partition 的话,所有消息都会被发送到指定的 Partition。并且,同一个 key 的消息可以保证只发送到同一个 partition,这个我们可以采用表/对象的 id 来作为 key 。
1 个 Topic 只对应一个 Partition。
(推荐)发送消息的时候指定 key/Partition。

Kafka 如何保证消息不丢失
1、生产者丢失消息的情况
2、消费者丢失消息的情况
3、kafka弄丢了消息
https://blog.csdn.net/a1240466196/article/details/109299019#:~:text=kafka%20%E5%A6%82%E4%BD%95%20%E4%BF%9D%E8%AF%81%20%E6%95%B0%E6%8D%AE%E7%9A%84%E4%B8%8D%20%E4%B8%A2%E5%A4%B1%201.%E7%94%9F%E4%BA%A7%E8%80%85%E6%95%B0%E6%8D%AE%E7%9A%84%E4%B8%8D%20%E4%B8%A2%E5%A4%B1kafka%20%E7%9A%84ack%E6%9C%BA%E5%88%B6%EF%BC%9A%E5%9C%A8,%28Producer%29%20%E8%B0%83%E7%94%A8send%E6%96%B9%E6%B3%95%E5%8F%91%E9%80%81%20%E6%B6%88%E6%81%AF%20%E4%B9%8B%E5%90%8E%EF%BC%8C%20%E6%B6%88%E6%81%AF%20%E5%8F%AF%E8%83%BD%E5%9B%A0%E4%B8%BA%E7%BD%91%E7%BB%9C%20%E9%97%AE%E9%A2%98%20%E5%B9%B6%E6%B2%A1%E6%9C%89%E5%8F%91%E9%80%81%E8%BF%87%E5%8E%BB%E3%80%82

重复消费问题:通过业务来保证消息的幂等性,可以使用redis的原子性或者mysql的唯一ID来保证

网络相关


1、HTTP VS HTTPS,SSL证书原理


HTTP 明文传输,数据都是未加密的,安全性较差,HTTPS(SSL+HTTP) 数据传输过程是加密的,安全性较好。
使用 HTTPS 协议需要到 CA(Certificate Authority,数字证书认证机构) 申请证书,一般免费证书较少,因而需要一定费用。证书颁发机构如:Symantec、Comodo、GoDaddy 和 GlobalSign 等。
HTTP 页面响应速度比 HTTPS 快,主要是因为 HTTP 使用 TCP 三次握手建立连接,客户端和服务器需要交换 3 个包,而 HTTPS除了 TCP 的三个包,还要加上 ssl 握手需要的 9 个包,所以一共是 12 个包。
http 和 https 使用的是完全不同的连接方式,用的端口也不一样,前者是 80,后者是 443。
HTTPS 其实就是建构在 SSL/TLS 之上的 HTTP 协议,所以,要比较 HTTPS 比 HTTP 要更耗费服务器资源。

2、404排查原因

3、TCP 为什么要有 TIME_WAIT 状态?


https://draveness.me/whys-the-design-tcp-time-wait/#fn:3
 TIME_WAIT 仅在主动断开连接的一方出现,被动断开连接的一方会直接进入 CLOSED 状态,进入 TIME_WAIT 的客户端需要等待 2 MSL 才可以真正关闭连接。
TCP 协议需要 TIME_WAIT 状态的原因和客户端需要等待两个 MSL 不能直接进入 CLOSED 状态的原因是一样的:
防止延迟的数据段被其他使用相同源地址、源端口、目的地址以及目的端口的 TCP 连接收到;
保证 TCP 连接的远程被正确关闭,即等待被动关闭连接的一方收到 FIN 对应的 ACK 消息;

操作系统相关:


1、阻塞vs非阻塞


2、生产者消费者模型

3、进程线程区别联系


https://www.jianshu.com/p/a4fa4edbeb8a
进程是表示资源分配的基本单位,又是调度运行的基本单位。
线程是进程中执行运算的最小单位,亦即执行处理机调度的基本单位。

  • 1
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值