自梳理JAVA,持续优化

自我介绍!!!!

说一下你对分布式理解是什么样的?
springcloud里面的几个组件?
    Eureka:服务注册中心
    Ribbon:客户端负载均衡
    Hystrix:熔断器
    Fegin:声明式的Http客户端
    Zuul:服务网关
权限是怎么设计的? 用户-->角色-->权限(菜单按钮等资源)
项目用的权限框架是什么?spring security认证和授权流程;认证验证账号密码,授权:登录token
jwt和token区别?
        jwt(JSON Web Token)无状态,安全性,可避免CSRF攻击
分布式事务是怎么处理的?MQ事务消息  seata分布式事务
tcc (seata)二阶段提交 有没有基于tcc的一些其他解决方案 比如说最大努力通知(基于消息队列来说)?
rocket mq用过吗,网络波动?
更新数据库 redis缓存数据怎么去更新(双写一致性)?
redis除了做缓存你们还做其他东西吗?
redis有没有用它做分布式锁?
zookeeper是怎么去实现分布式锁?
redis缓存和我们框架项目去做缓存,有什么其他区别(比如用map做缓存)?
数据库优化?
有没有用过相关命令去查看sql执行?
分表!分好以后怎么去确认数据在那张表?
分表策略?
分表以后查询一个范围但跨表了?怎么办?
union和unionall区别?
索引有去了解他的底层吗
B+tree能做到什么优化? 它和二叉树有什么不同?
myisam和Innodb区别引擎?
有没有遇到锁表的情况?

目录

1.Java基础

1.1 线程池

 1.2 Synchronized和Volatitl原理

1.3.jdk用到单例模式的有哪些?

 1.4 jdk1.8hashmap集合底层原理

1.5 类加载过程

1.6 为什么堆的常量和栈的常量要设置成一样

 1.7 Jvm垃圾回收

1.8 顺序遍历和逆序遍历的区别?

1.9 为什么hashcode和equals方法需要重写?

2.0 栅栏:CyclicBarrier

2.Spring

2.1.AOP原理

2.2 依赖注入原理

2.3.springBoot

1.特有的配置文件?

2.特有的注解?

3.生命周期

2.4.springCloud

2.4.1 微服务各种注解的使用

2.5 springMvc

        2.6 spring事务

2.7 bean的生命周期

3.中间件

        3.1Redis

        Redis问题点:

        1.缓存穿透

        2.缓存雪崩

        3.缓存击穿

        4.持久化:

        5.如何保证Redis与数据库的数据一致性?双写一致

        6.分布式锁

        3.2RocketMQ

4.数据库

        4.1数据库优化

        4.2 Mysql

5.数据结构

        5.1 算法

 5.2 数据结构

1.二叉树

2.红黑树(平衡树)

3.B树

4.B+树

6.网络通信

        6.1 IO/NIO

        6.2.TCP/IP

三次握手:

四次握手:

7.k8s

k8s详细教程/Kubernetes详细教程.md · java668/LearningNotes - Gitee.com


1.Java基础

1.1 线程池

线程池创建:

1. 线程池刚创建时,里面没有一个线程。任务队列是作为参数传进来的。不过,就算队列里面有任务,线程池也不会马上执行它们。

2. 当调用 execute() 方法添加一个任务时,线程池会做如下判断:

a) 如果正在运行的线程数量小于 corePoolSize,那么马上创建线程运行这个任务;

b) 如果正在运行的线程数量大于或等于 corePoolSize,那么将这个任务放入队列;

c) 如果这时候队列满了,而且正在运行的线程数量小于 maximumPoolSize,那么还是要

创建非核心线程立刻运行这个任务;

d) 如果队列满了,而且正在运行的线程数量大于或等于 maximumPoolSize,那么线程池

会抛出异常 RejectExecutionException。

3. 当一个线程完成任务时,它会从队列中取下一个任务来执行。

4. 当一个线程无事可做,超过一定的时间(keepAliveTime)时,线程池会判断,如果当前运行的线程数大于 corePoolSize,那么这个线程就被停掉。所以线程池的所有任务完成后,它

最终会收缩到 corePoolSize 的大小。

@1.具体执行过程

@2.线程池参数两个都相等的时候会怎样

1.Executors.newFixedThreadPool(10);创建10个线程的线程池

2.ExecutorService executorService2 = Executors.newCachedThreadPool();创建缓存的线程池,这种方式可以控制内存不会被占满

3.创建拥有定时任务的固定线程个数的线程池,可以定时执行ScheduledExecutorService scheduledExecutorService =Executors.newScheduledThreadPool(10);

4.创建单线程ExecutorService executorService = Executors.newSingleThreadExecutor();

参数1:corePoolSize:线程池的基本大小

参数2. maximumPoolSize:线程池中允许的最大线程数

参数3:poolSize:线程池中当前线程的数量,当该值为0的时候,意味着没有任何线程,线程池会终止;同一时刻,poolSize不会超过maximumPoolSize

拒绝策列:第31个任务被拒绝


提交优先级

执行优先级

@3.sleep,wait 方法区别

--sleep()方法是Thread类里面的,

主要的意义:就是让当前线程停止执行,让出cpu给其他的线程,但是不会释放对象锁资源以及监控的状态,当指定的时间到了之后又会自动恢复运行状态。

加参数:sleep()方法必须传入参数,参数就是休眠时间,时间到了就会自动醒来。

--wait()方法是Object类里面的,

主要的意义:就是让线程放弃当前的对象的锁,进入等待此对象的等待锁定池,只有针对此对象调动notify,notifyAll方法后本线程才能够进入对象锁定池准备获取对象锁进入运行状态

加参数:wait()方法可以传入参数也可以不传入参数,传入参数就是在参数结束的时间后开始等待,不穿如参数就是直接等待

--join 等待目标线程执行完成之后再继续执行

--yield 线程礼让。目标线程由运行状态转换为就绪状态,也就是让出执行权限,让其他线程得以优先执行,但其他线程能否优先执行是未知数

注意:wait()、notify()、notifyAll()必须放在synchronized block中,否则会抛出异常

 1.2 Synchronized和Volatitl原理

Synchronized原理:代码反编译(字节码)monitorentermonitorexit

Volatitl:同步关键字,字节码中是lock(线程与线程之间没法直接通信)

volatile关键字:简单理解:线程修改值后,马上将值存放到主内存,所有子线程都可见

1)保证了不同线程对这个变量进行操作时的可见性,即一个线程修改了某个变量的值,这新值对其他线程来说是立即可见的。

2)禁止进行指令重排序。

底层原理:assign,load,read,store,write

1.3.jdk用到单例模式的有哪些?

@1.Runtime

第一种:懒汉式:

public static synchronized UserModel getInstance() {

if (userModel == null) {

userModel = new UserModel();

}

return userModel;

第二种:饿汉式

public static UserModel getInstance(){

        return new userModel();

第三种:双重检索式:双重检索的方式,可以说是在性能和安全两个角度找了一个平衡点,可以理解为懒汉式单例模式的加强版,既考虑性能又考虑安全性的问题。

public static UserModel getInstance() {

        if (userModel == null) {

            synchronized (DoubleCheckSingletonPattern.class) {

                if (userModel == null) {

                    userModel = new UserModel();

                }

            }

        }

        return userModel;

问题点:隐患补充:这里隐藏着一个问题,当两个线程进来后,先获取锁的线程开始创建线程的同时,第二个线程进入判断,因为构造对象的过程可能会比较长,

这时第一个线程还未完成对象的完整创建,但第二个线程会拿到一个不是null的值,从而认为已经构造完成,导致返回的类并非是一个完整的对象。解决方案可以通过volatile来解决这个问题,完美的解决了这个问题的还是推荐使用内部类的创建方式

第四种:注册登记式:Spring框架中IOC容器就采用的这种方式来管理我们系统中的Bean对象

private final static Map<String, Object> objectsMap = new ConcurrentHashMap<>();

    public static synchronized Object getInstance() {

        String key = "&userModel";

        if (!objectsMap.containsKey(key)) {

            objectsMap.put(key, new UserModel());

        }

        return objectsMap.get(key);

    }

第五种:内部类形式:程序启动后并不会初始化内部类,而当外部类调用内部类的方法时,才会初始化内部类的UserModel实例,保证在不浪费资源的情况下达到的单例模式的应用

public class InnerClassSingletonPattern {

    static {

        System.out.println("父类加载了");

    }

    public static UserModel getInstance() {

        return UserModelSingleton.userModel;

    }

    static class UserModelSingleton {

        static final UserModel userModel = new UserModel();

        static {

            System.out.println("子类加载了");

        }

 1.4 jdk1.8hashmap集合底层原理

@1.hashMap底层原理:有序? Hash

.hashMap:

1.7:数组+链表

1.8:数组+链表+红黑树

ConcurrentHashMap实现线程安全的原理?ReentrantLock  是基于AQS实现的。分为公平锁和非公平锁。

初始容量:16 (2的指数次幂)

负载因子:0.75

1.5 类加载过程

类加载主要分为:加载,连接,初始化,使用,卸载5个阶段;
其中连接分为:验证,准备,解析;

1.6 为什么堆的常量和栈的常量要设置成一样

 1.7 Jvm垃圾回收

JVM调优总结 -Xms -Xmx -Xmn -Xss - unixboy - ITeye博客

堆:

方法区:(1.8之前叫永久代)存放常量,静态变量,类元信息(对象头每个类唯一,比如同步锁,,,)

本地方法区:native方法。。

栈内存:先进后出,(栈中的局部变量引用堆中的地址)

操作数栈:代码执行加减乘除

堆:GC

分为年轻代(占1/3),老年代(占2/3),

年轻代:分为Eden区,From区,To区

对象分代年龄:对象头上的一个4bt标识,每移动一次区域就会+1,当达到15(好像可设置),就会将对象移到老年代(存在老年代的一般是线程池,静态对象,spring bean)

Eden区:new的对象一般放在Eden区,当此内存区放满时会触发字节码执行引擎minor GC(不被引用的对象)

Eden区和From区到To区是复制算法

当老年代放满时会触发full Gc 如果还是清理不掉对象,则会OOM

GC用到的算法

标记清除算法:

对象存活判断:

可达性分析

垃圾收集算法:(标记 -清除算法)

复制算法:它将可用内存按容量划分为大小相等的两块,每次只使用其中的一块。当这一块的内存用完了,就将还存活着的对象复制到另外一块上面,然后再把已使用过的内存空间一次清理掉。---内存缩小为原来的一半,持续复制长生存期的对象则导致效率降低

标记-压缩算法:

分代收集算法:

程序计数器:简单理解线程代码执行步数,执行到的位置

对象:

GC

1.8 顺序遍历和逆序遍历的区别?

1.9 为什么hashcode和equals方法需要重写?

        1、重写equals()是为了实现自己的区分逻辑。

        2、重写hashCode()是为了提高hash tables的使用效率,以及和equals()保持一致(看下面hashcode的第三点)。

举例:

1、String重写Object的equals方法

2、HashSet是如何保证存储的元素不同的?

举例:

1、String重写Object的equals方法

2、HashSet是如何保证存储的元素不同的?
                        
原文链接:https://blog.csdn.net/river66/article/details/87803663

2.0 栅栏:CyclicBarrier

2.Spring

@Autowired 与@Resource的区别:

1、@Autowired与@Resource都可以用来装配bean. 都可以写在字段上,或写在setter方法上。

2、@Autowired默认按类型装配(这个注解是属业spring的),默认情况下必须要求依赖对象必须存在,如果要允许null值,可以设置它的required属性为false,如:@Autowired(required=false) ,如果我们想使用名称装配可以结合@Qualifier注解进行使用,如下:

spring不但支持自己定义的@Autowired注解,还支持几个由JSR-250规范定义的注解,它们分别是@Resource、@PostConstruct以及@PreDestroy。
@Resource的作用相当于@Autowired,只不过@Autowired按byType自动注入,而@Resource默认按 byName自动注入罢了。@Resource有两个属性是比较重要的,分是name和type,Spring将@Resource注解的name属性解析为bean的名字,而type属性则解析为bean的类型。所以如果使用name属性,则使用byName的自动注入策略,而使用type属性时则使用byType自动注入策略。如果既不指定name也不指定type属性,这时将通过反射机制使用byName自动注入策略。
@Resource装配顺序
1. 如果同时指定了name和type,则从Spring上下文中找到唯一匹配的bean进行装配,找不到则抛出异常
2. 如果指定了name,则从上下文中查找名称(id)匹配的bean进行装配,找不到则抛出异常
3. 如果指定了type,则从上下文中找到类型匹配的唯一bean进行装配,找不到或者找到多个,都会抛出异常
4. 如果既没有指定name,又没有指定type,则自动按照byName方式进行装配;如果没有匹配,则回退为一个原始类型进行匹配,如果匹配则自动装配;

@Autowired 与@Resource的区别:

1、 @Autowired与@Resource都可以用来装配bean. 都可以写在字段上,或写在setter方法上。

2、 @Autowired默认按类型装配(这个注解是属业spring的),默认情况下必须要求依赖对象必须存在,如果要允许null值,可以设置它的required属性为false,如:@Autowired(required=false) ,如果我们想使用名称装配可以结合@Qualifier注解进行使用,如下:

https://blog.csdn.net/weixin_40423597/article/details/80643990

2.1.AOP原理

Ioc:控制反转,是一种思想,主要是用来解耦,核心做法是增加ioc容器(将特定包下的代码扫描注册实例话在一个bean容器中),使用时通过注入的方式即可。

Spring AOP:分为静态代理和动态代理

静态代理:

动态代理

JDK 动态代理:是通过 JDK 中的 java.lang.reflect.Proxy 类实现的。它也有一定的局限性,这是因为 JDK 动态代理必须要实现一个或多个接口。

CGLIB:

名称

说明

JoinpointJoinpoint(连接点)

指那些被拦截到的点,在 Spring 中,可以被动态代理拦截目标类的方法。

Pointcut(Pointcut切入点)

指要对哪些 Joinpoint 进行拦截,即被拦截的连接点。

Advice( Advice通知)

指拦截到 Joinpoint 之后要做的事情,即对切入点增强的内容。

Target(  Target目标)

指代理的目标对象。

Weaving(Weaving植入)

指把增强代码应用到目标上,生成代理对象的过程。

Proxy(   Proxy代理)

指生成的代理对象。

Aspect     Aspect( 切面)

切入点和通知的结合。

2.2 依赖注入原理

2.3.springBoot

运行机制:

从启动类注解:

springbootApplication

涉及注解:

@SpringBootConfiguration

@EnableAutoConfiguration—

  @AutoConfigurationPackage

@Import

@ComponentScan

Springboot根据配置文件自动装配所属依赖的类再用动态代理的方式注入到spring容器里面

1.特有的配置文件?

2.特有的注解?

@SpringBootApplication

@ ServletComponentScan

3.生命周期

https://www.it610.com/article/1288250549858250752.htm

首先说一下Servlet的生命周期:实例化,初始init,接收请求service,销毁destroy;

 Spring上下文中的Bean生命周期也类似,如下:

(1)实例化Bean:

对于BeanFactory容器,当客户向容器请求一个尚未初始化的bean时,或初始化bean的时候需要注入另一个尚未初始化的依赖时,容器就会调用createBean进行实例化。对于ApplicationContext容器,当容器启动结束后,通过获取BeanDefinition对象中的信息,实例化所有的bean。

(2)设置对象属性(依赖注入):

实例化后的对象被封装在BeanWrapper对象中,紧接着,Spring根据BeanDefinition中的信息 以及 通过BeanWrapper提供的设置属性的接口完成依赖注入。

(3)处理Aware接口:

接着,Spring会检测该对象是否实现了xxxAware接口,并将相关的xxxAware实例注入给Bean:

如果这个Bean已经实现了BeanNameAware接口,会调用它实现的setBeanName(String beanId)方法,此处传递的就是Spring配置文件中Bean的id值;

如果这个Bean已经实现了BeanFactoryAware接口,会调用它实现的setBeanFactory()方法,传递的是Spring工厂自身。

如果这个Bean已经实现了ApplicationContextAware接口,会调用setApplicationContext(ApplicationContext)方法,传入Spring上下文;

(4)BeanPostProcessor:

如果想对Bean进行一些自定义的处理,那么可以让Bean实现了BeanPostProcessor接口,那将会调用postProcessBeforeInitialization(Object obj, String s)方法。

(5)InitializingBean 与 init-method:

如果Bean在Spring配置文件中配置了 init-method 属性,则会自动调用其配置的初始化方法。

(6)如果这个Bean实现了BeanPostProcessor接口,将会调用postProcessAfterInitialization(Object obj, String s)方法;由于这个方法是在Bean初始化结束时调用的,所以可以被应用于内存或缓存技术;

以上几个步骤完成后,Bean就已经被正确创建了,之后就可以使用这个Bean了。

(7)DisposableBean:

当Bean不再需要时,会经过清理阶段,如果Bean实现了DisposableBean这个接口,会调用其实现的destroy()方法;

(8)destroy-method

最后,如果这个Bean的Spring配置中配置了destroy-method属性,会自动调用其配置的销毁方法。

2.4.springCloud

@1.组件有哪些

K8S:

服务发现——Netflix Eureka

客服端负载均衡——Netflix Ribbon

断路器——Netflix Hystrix

服务网关——Netflix Zuul

分布式配置——Spring Cloud Config

2.4.1 微服务各种注解的使用

@Mapper:  注解写在你的Mapper映射接口上面

@SpringBootApplication:  写在主程序上面

@Configuration:   写在配置类上面

@Bean:  写在配置类中的返回新的对象的方法上面

@EnableEurekaServer:  把当前微服务标记为Eureka注册中心 接收其他微服务的注册

@EnableEurekaClient:  注册该微服务到Eureka中

@LoadBalanced:  该注解写在配置RestTemplate的配置类方法上来启动ribbon负载均衡

@EnableFeignClients:  写在主程序上来支持feign

@HystrixCommand(fallbackMethod=“你的方法”)

@EnableCircuitBreaker :  启用对Hystrix熔断机制的支持

@FeignClient(value="服务名",fallbackFactory=实现FallbackFactory的类.class):  实现服务降级

@EnableHystrixDashboard:   加在主程序上启动服务监控

@FeignClient(value=“服务名”):  写在接口上 来调用远程服务

@EnableZuulProxy:  写在主程序上启动zuul路由访问功能

2.5 springMvc

SpringMVC框架是以请求为驱动,围绕Servlet设计,将请求发给控制器,然后通过模型对象,分派器来展示请求结果视图。其中核心类是DispatcherServlet,它是一个Servlet,顶层是实现的Servlet接口。

SpringMVC运行原理

需要在web.xml中配置DispatcherServlet。并且需要配置spring监听器ContextLoaderListener

(1)客户端(浏览器)发送请求,直接请求到DispatcherServlet。

(2)DispatcherServlet根据请求信息调用HandlerMapping,解析请求对应的Handler。

(3)解析到对应的Handler后,开始由HandlerAdapter适配器处理。

(4)HandlerAdapter会根据Handler来调用真正的处理器开处理请求,并处理相应的业务逻辑。

(5)处理器处理完业务后,会返回一个ModelAndView对象,Model是返回的数据对象,View是个逻辑上的View。

(6)ViewResolver会根据逻辑View查找实际的View。

(7)DispaterServlet把返回的Model传给View。

(8)通过View返回给请求者(浏览器)

2.6 spring事务

事务传播行为是指方法之间事务的传播. 比如, 在方法A中调用了方法B:

PROPAGATION_REQUIRED:默认传播

如果A有事务就使用当前事务, 如果A没有事务, 就创建一个新事务.

PROPAGATION_SUPPORTS :支持

如果A有事务就使用当前事务, 如果A没有事务, 就以非事务执行.

PROPAGATION_MANDATORY :强制性

如果A有事务就使用当前事务, 如果A没有事务, 就抛异常,用来检验上下逻辑有没有加事务

PROPAGATION_REQUIRES_NEW

不管A有没有事务都创建一个新事务.

PROPAGATION_NOT_SUPPORTED

不管A有没有事务都以非事务执行.

PROPAGATION_NEVER :不能有事务

如果A有事务就抛异常, 如果A没有事务, 就以非事务执行.

PROPAGATION_NESTED:

如果A没有事务就创建一个事务, 如果A有事务, 就在当前事务中嵌套其他事务.

2.7 bean的生命周期

3.中间件

        3.1Redis

                @1.了解多少

Redis支持五种数据类型:string(字符串),hash(哈希),list(列表),set(集合)及zset(sorted set:有序集合)。string 类型的值最大能存储 512MB

Redis问题点:

https://blog.csdn.net/womenyiqilalala/article/details/105205532

1.缓存穿透

缓存穿透是指查询一个根本不存在的数据

解决:设置null值返回/设置返回null的key过期时间/布隆过滤器

2.缓存雪崩

Key失效,大量请求直接到达存储层,存储层压力过大导致系统雪崩

三方面:1.redis系统宕机(多个节点高可用)。2.不让key同时失效,随机失效时间。3.做多级缓存,本地进程一级缓存,redis二级缓存

3.缓存击穿

系统中存在以下两个问题时需要引起注意:

  • 当前key是一个热点key(例如一个秒杀活动),并发量非常大。
  • 重建缓存不能在短时间完成,可能是一个复杂计算,例如复杂的SQL、多次IO、多个依赖等。

在缓存失效的瞬间,有大量线程来重建缓存,造成后端负载加大,甚至可能会让应用崩溃。

解决方案:分布式锁,ression-》lock。布隆过滤器

4.持久化:

AOF

RDB

5.如何保证Redis与数据库的数据一致性?双写一致

6.分布式锁

Jedis

Lettuce

RedisTemplate

Redisson

        3.2RocketMQ

                @1.了解多少

                异步处理,应用解耦,流量削锋和消息通讯四个场景

                https://www.cnblogs.com/linjiqin/p/5720865.html

rocketMq如何保证消息不丢失?

Producer发送消息阶段

手段一:提供SYNC的发送消息方式,等待broker处理结果。

手段二:发送消息如果失败或者超时,则重新发送。

手段三:broker提供多master模式

Broker处理消息阶段

手段四:提供同步刷盘的策略【等待刷盘成功才会返回producer成功】

手段五:提供主从模式,同时主从支持同步双写

Consumer消费消息阶段

手段六:consumer默认提供的是At least Once机制

手段七:消费消息重试机制

4.数据库

        4.1数据库优化

                数据库会问有没有调优经验?

        4.2 Mysql

MySQL 索引和事务、并发访问处理、脏读、不可重复读、幻读、丢失更新(C/C++)_哔哩哔哩_bilibili

https://www.bilibili.com/video/BV1cv411P7Wb/?spm_id_from=333.337.search-card.all.click&vd_source=4f507e36c1556aa9a2cf62fa04b94c6f

两种引擎:(引擎是来形容表的)

MYISAM(my sam):不支持外键,表锁,插入数据时,锁定整个表,查表总行数时,不需要全表扫描

INNODB支持外键,行锁,查表总行数时,全表扫描

为什么innodb必须有主键,并且推荐使用整型的自增主键?

数据库B+树决定的,自增是用于判断子节点

索引分为:有B+索引和hash索引

Hash hash索引,等值查询效率高,不能排序,不能进行范围查询

B树:数据有序,范围查询

聚集索引:

索引和数据在一个文件,只需要查询一次

非聚集索引:

索引和数据在两个文件,需要查询两次

联合索引:

5.数据结构

        5.1 算法

雪花算法:

  • 时间位:可以根据时间进行排序,有助于提高查询速度。
  • 机器id位:适用于分布式环境下对多节点的各个节点进行标识,可以具体根据节点数和部署情况设计划分机器位10位长度,如划分5位表示进程位等。
  • 序列号位:是一系列的自增id,可以支持同一节点同一毫秒生成多个ID序号,12位的计数序列号支持每个节点每毫秒产生4096个ID序号

Redis也能生成自增主键

Uuid和雪花算法

UUID (Universally Unique Identifier),通用唯一识别码。UUID是基于当前时间、计数器(counter)和硬件标识(通常为无线网卡的MAC地址)等数据计算生成的。

格式 & 版本

UUID由以下几部分的组合:

当前日期和时间,UUID的第一个部分与时间有关,如果你在生成一个UUID之后,过几秒又生成一个UUID,则第一个部分不同,其余相同。

时钟序列。

全局唯一的IEEE机器识别号,如果有网卡,从网卡MAC地址获得,没有网卡以其他方式获得。

优点

  • 简单,代码方便。
  • 生成ID性能非常好,基本不会有性能问题。本地生成,没有网络消耗。
  • 全球唯一,在遇见数据迁移,系统数据合并,或者数据库变更等情况下,可以从容应对。

缺点

  • 采用无意义字符串,没有排序,无法保证趋势递增。
  • UUID使用字符串形式存储,数据量大时查询效率比较低
  • 存储空间比较大,如果是海量数据库,就需要考虑存储量的问题。

 5.2 数据结构

索引(有顺序)

1.二叉树

(根节点左边子节点小于根节点,右边子节点大于根节点)

缺点:查询慢,最坏情况当查6节点时基本遍历整张表,

2.红黑树(平衡树)

红黑树:当单边存储过大时旋转平衡

缺点:数据量太大时深度太高,查找慢

3.B树

每一个叶子节点默认大小16K

4.B+树

6.网络通信

        6.1 IO/NIO

        6.2.TCP/IP

三次握手:

  • 第一次握手:客户端将标志位SYN置为1,随机产生一个值seq=J,并将该数据包发送给服务器端,客户端进入SYN_SENT状态,等待服务器端确认。
  • 第二次握手:服务器端收到数据包后由标志位SYN=1知道客户端请求建立连接,服务器端将标志位SYN和ACK都置为1,ack=J+1,随机产生一个值seq=K,并将该数据包发送给客户端以确认连接请求,服务器端进入SYN_RCVD状态。
  • 第三次握手:客户端收到确认后,检查ack是否为J+1,ACK是否为1,如果正确则将标志位ACK置为1,ack=K+1,并将该数据包发送给服务器端,服务器端检查ack是否为K+1,ACK是否为1,如果正确则连接建立成功,客户端和服务器端进入ESTABLISHED状态,完成三次握手,随后客户端与服务器端之间可以开始传输数据了。

四次握手:

  • 中断连接端可以是客户端,也可以是服务器端。
  • 第一次挥手:客户端发送一个FIN=M,用来关闭客户端到服务器端的数据传送,客户端进入FIN_WAIT_1状态。意思是说"我客户端没有数据要发给你了",但是如果你服务器端还有数据没有发送完成,则不必急着关闭连接,可以继续发送数据。
  • 第二次挥手:服务器端收到FIN后,先发送ack=M+1,告诉客户端,你的请求我收到了,但是我还没准备好,请继续你等我的消息。这个时候客户端就进入FIN_WAIT_2 状态,继续等待服务器端的FIN报文。
  • 第三次挥手:当服务器端确定数据已发送完成,则向客户端发送FIN=N报文,告诉客户端,好了,我这边数据发完了,准备好关闭连接了。服务器端进入LAST_ACK状态。
  • 第四次挥手:客户端收到FIN=N报文后,就知道可以关闭连接了,但是他还是不相信网络,怕服务器端不知道要关闭,所以发送ack=N+1后进入TIME_WAIT状态,如果Server端没有收到ACK则可以重传。服务器端收到ACK后,就知道可以断开连接了。客户端等待了2MSL后依然没有收到回复,则证明服务器端已正常关闭,那好,我客户端也可以关闭连接了。最终完成了四次握手。

linux系统部署jenkins详细教程_linux下搭建jenkins-CSDN博客

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值