高级JAVA知识整理

作者: Coder_L | 来源:发表于2020-09-23 18:51 被阅读0次

    1.Java 类的加载流程是怎样的?什么是双亲委派机制?

    类加载的主要任务:根据一个类的全限定名读取该类的二进制字节流到JVM内部,然后转换为一个对应的java.lang.Class对象实例。

    类从被加载到JVM中到卸载总共经历7个阶段:加载、验证、准备、解析、初始化、使用卸载。

    加载:类加载阶段是由类加载器根据类文件全限定类名,来读取这个类文件的二进制字节流到JVM中,并存储在内存的方法区中,然后将其装换为一个对应的java.lang.Object对象实例。

    验证:验证是否符合class文件规范;检查final类是否有子类;检查final方法是否被子类重写;检查父类和子类声明方法是否兼容等。

    准备:为类中static变量分配内存空间并初始化;被final修饰的静态变量会直接赋予原值。

    解析:将常量池中所有符号引用转换为直接饮用,得到类、字段或者方法在内存中的指针或偏移量,以便直接调用。

    初始化:赋值static变量,执行static块;先初始化父类再初始化子类。

    双亲委派:当某个类加载器需要加载类文件时,会首先把这个任务委托给他的上级类加载器,递归这个操作。如果上级的类加载器无法加载时,将这个任务退回给下一级类加载器。判断任何一级加载器加载过类文件直接返回。作用是保证每个类文件只被加载一次。

    2.简述 MVC 与 MVVM 的区别,MVVM 的优点是什么?

    VM:在前端页面中,把Model用纯JavaScript对象表示,View负责显示,两者做到了最大限度的分离,把Model和View关联起来的就是ViewModel。

    区别:MVC和MVVM的区别并不是VM瓦全取代C,只是在MVC的基础上增加了一层VM,弱化了C的概念,VM存在的目的在于抽离C中展示的业务逻辑,而不是替代C,ViewModel负责把Model的数据同步到View显示出来,还负责把View的修改同步回Model。

    优点:

    低耦合:MVVM模式中,数据是独立于UI,VM只负责处理和提供数据。

    自动同步数据:VM通过双向数据绑定把V和M连接起来,V和M两者可以自动同步。

    可重用:可以封装视图逻辑,其他V也可以重用。

    独立开发:可以独立开发VM,设计人员可专注于页面设计。

    可测试:VM处理数据和业务逻辑,V关注UI,方便单独测试。

    3.简述 Netty 线程模型,Netty 为什么如此高效?

    Netty是一款基于NIO(Nonblocking I/O,非阻塞I/O)开发的网络通信框架,对比与BIO(Blocking I/O,阻塞I/O),并发性能得到很大提升。

    阻塞IO通信模式 非阻塞IO通信模式

    NIO的单线程处理连接的数量比BIO高很多,原因就是Selector。

    当建立一个连接后,第一步是接收完客户端发过来的全部数据,第二步是服务端处理完请求业务之后返回response给客户端。NIO和BIO的区别主要在于第一步。

    BIO中,等待客户端发数据过程是阻塞的,造成一个线程只能处理一个请求,而机器支持的最大线程数有限,所以并发能力差。

    NIO中,一个线程接收数据不会阻塞,而是将请求交给Selector,Selector会不断遍历socket状态,一旦建立完成就会交给线程处理请求,这样能让一个线程处理多个请求。

    4.HashMap 实现原理,为什么使用红黑树?

    HashMap是使用频率最高的处理键值对的数据结构,无序、允许插入null的key和value。

    HashMap基于数组+链表实现,使用拉链法处理碰撞,在JDK8中,当链表长度大于8(默认值)时转为红黑树,当长度小于6转为链表。

    HashMap有一个Node<K,V>[] table字段,即哈希桶数组,数组元素是Node对象

    哈希桶会在首次使用时初始化,默认大小是16,并根据需要调整大小,大小总为2的n次幂。如果构造函数传入大小不是2的n次幂,那么初始化时会根据算法得出最接近且大于这个值的2的次幂的值。

    HashMap属性字段

    影响HashMap性能的主要参数是:初始容量和负载因子。当数组元素数量超过容量值,会发生扩容,容量为原来的两倍,并对key重新散列。

    初始容量过小会多次触发扩容和 rehash,所以预分配一个足够大的容量更加有效

    负载因子默认值是 0.75f,它是对时间和空间成本的一个很好的平衡,一般不用修改,较高的值会减少空间开销,但会增加查找的成本

    不管多么合理的散列算法,也免不了链表过长的情况,从而影响 HashMap 的性能,所以,JDK8 在链表长度大于 8 时,将其转为红黑树,以利用红黑树快速增删改查的特点。

    先了解一下二叉树

    二叉树

    (1)左子树上所有结点的值均小于或等于它的根结点的值。

    (2)右子树上所有结点的值均大于或等于它的根结点的值。

    (3)左、右子树也分别为二叉排序树

    二叉树查找原理:找到数组中间位置元素v,将数组分为>v和<v两部分,然后将v和要查找的数进行比较,小于找左边,大于找右边,直至找到元素,查找次数是目标元素所在二叉树的层数。

    红黑树

    红黑树是一种自平衡的二叉树。自平衡就是对HashMap链表可能很长最初的优化,平衡能保证单侧树不会过长,导致查询效率低,这也是相比于二叉树的优势。

    红黑树

    性质:

    1.包含二叉树的性质。

    2.节点只能是红色或黑色。

    3.根结点是黑色。

    4.每个叶节点是黑色(NIL节点,空节点)。

    5.从每个叶节点到根结点路径上,不会出现两个相连的红色节点。

    6.从任意节点到叶子节点的所有路径上,黑色节点数量相同。

    红黑树通过“变色”和“旋转”维护其平衡。

    HashMap中怎么使用红黑树

    JDK7中HashMap利用链表解决冲突,这可能导致链表过长,由于每次put/set都会遍历链表,导致效率下降。

    HashMap中的红黑树节点用TreeNode类

    TreeNode

    TreeNode和Entry都是Node的子类,也就说Node可能是链表结构,也可能是红黑树结构。

    5.Java 中接口和抽象类的区别

    定义

    抽象类:抽象类必须用abstract修饰,子类必须实现抽象类中的抽象方法,如果未实现的,那么子类叶必须用abstract修饰。抽象类的默认权限是public,也可以声明为protected,如果定义private,那么子类无法继承。抽象类不能实例化。

    接口:接口中的变量隐式的使用public static final修饰,并且必须初始化。方法隐式的使用public abstract修饰,只能是public否则会编译报错。从JDK8开始接口中方法允许有默认实现。

    区别

    1.抽象类只能继承一次,但是可以实现多个接口。

    2.接口和抽象类必须实现其中所有方法,抽象类中如果有为实现的方法,那么子类必须也定义为抽象方法。抽象类中可以有具体方法。

    3.接口中的变量必须用public static final定义,并且必须初始化,实现类不能修改,也不能重新定义。

    4.接口中的方法只能是public abstract,不能是static,接口中的方法不允许实现类重写,抽象类可以有static方法。

    6.成员变量和方法的区别?

    成员变量作用域整个类,类当中任何方法都可以访问。方法作用域也是整个类,其他方法可以调用,但是方法中定的变量作用域只在方法内。

    7.CAS 实现原理是什么?

    在计算机科学中,比较和交换(Compare And Swap)是用于实现多线程同步的原子指令。它将内存中的值与给定的值对比,相同情况下将内存中的值修改为新值,否则更新失败。比如线程1更新时发现,线程2修改过内存中的值,那么线程1会读取内存中的最新值(volatitl类型)然后再更新,这保证线程1不会死循环。

    8.ThreadLocal 实现原理是什么?

    ThreadLocal俗称线程本地变量。ThreadLocal为每个线程维护了一份变量,每个线程可以访问自己的变量副本,不涉及变量线程之间共享。

    ThreadLocal维护了一个ThreadLocalMap,是Thread的一个属性,key是ThreadLocal变量,value是线程本地的数据。

    由于ThreadLocalMap维护的Entry继承自WeakReference<ThreadLocal>,也就是说ThreadLocal自身的回收不受ThreadLocalMap的这个弱引用的影响。但是Entry被ThreadLocalMap强引用,所以Entry不能被GC。ThreadLocalMap的expungeStaleEntry这个方法,这个方法在ThreadLocalMap get、set、remove、rehash等方法都会调用到。方法有两个作用:第一将remove的Entry置空,第二找到已经被GC的ThreadLocal,然后清理掉ThreadLocalMap对Entry的引用。这样Entry就会被后续GC回收。

    如果数据初始化好之后,一直不调用get、set等方法,这样Entry就一直不能回收,导致内存泄漏。所以一旦数据不使用最好主动remove。

    9.Java 常见锁有哪些?ReentrantLock 是怎么实现的?   

    乐观锁和悲观锁

    对于同一个数据的并发操作,悲观锁认为自己在使用数据的时候一定有其他线程来修改数据,因此在获取数据的时候会先加锁,确保数据不会被别的线程修改。Java中,synchronized和Lock实现的都是悲观锁。

    乐观锁认为自己在使用数据的时候,不会有其他线程修改数据,所以不会添加锁,只是在更新数据的时候去判断之前有没有别的线程修改了这个数据。如果没有被更新,当前线程将自己修改的数据成功写入。如果数据被修改了,则可能报错或者发起重试。乐观锁在Java中是通过无锁编程实现,最长采用的是CAS算法,Java原子类中的递增操作就是通过CAS自旋实现的。

    悲观锁适合写操作多的场景,乐观锁适合读操作多的场景。

    自旋锁和适应性自旋锁

    自旋锁和非自旋锁

    自旋锁本身有一定缺陷,它不能代替阻塞。自旋锁虽然避免了切换线程的开销,但是会占用处理器的时间。如果锁被占用的时间很短,自旋等待的效果就会很好。如果锁被占用的时间很长,那自旋的线程只会浪费CPU资源。所以自旋等待的时间必须有一定的限度,如果自旋超过了一定次数(默认10次,可以用-XX:PreBlockSpin来更改)没有成功获的锁,就应当挂起线程。

    CAS实现的原理也是资源锁,AtomicInteger中进行自增操作,代码中的do-while循环就是自旋操作,如果修改失败则通过循环来执行自旋,知道修改成功。

    JDK6中引入了适应性自旋锁。自适应意味着自旋等待次数不固定,而是由前一次在同一个锁上的自旋时间及锁的拥有者的状态来决定。如果在同一个兑现锁上,自旋等待成功获取锁,并且线程正在运行中,那么虚拟机认为这次自旋获得锁很可能成功,所以允许自旋等待更长时间。如果自旋很少成功获得锁,那么以后尝试获得锁很可能放弃自旋,直接将阻塞线程,避免浪费CPU资源。

    无锁、偏向锁、轻量级锁、重量级锁

    这四种锁是指锁的状态,专门针对synchronized。

    无锁:所有线程都能访问并修改同一个资源,但同时只有一个线程能修改成功,参考CAS原理;

    偏向锁:当一段同步代码一直被一个线程锁访问,不存在线程竞争,那么该线程就会自动获得锁降低获取锁的代价。

    轻量级锁:当有线程竞争时,偏向锁会升级为轻量级锁,其他线程会通过自旋形式尝试获取锁,不会阻塞,从而提高性能。

    重量级锁:如果自旋一定次数还未获得锁,轻量级锁就会升级重量级。将拥有所以外的所有线程阻塞。

    公平锁和非公平锁

    公平锁:多个线程按照申请锁顺序来获取锁,线程直接进入队列中排队,队列中的第一个线程才能获得锁。公平锁的优点是不会让线程一直等待下去,缺点是整体吞吐效率比非公平锁低,等待队列中第一个线程以外的线程都要阻塞,CPU唤醒阻塞线程的开销比非公平锁大。

    非公平锁:多个线程加锁时直接尝试获取锁,获取不到才到等待队列的队尾等待。如果此时刚好能获得锁,那么这个线程可以无需阻塞直接获得锁,所以非公平锁有可能出现后申请锁得线程先获得锁。优点是可以减少唤起线程的CPU开销,整体吞吐效率高,缺点是处于等待队列的线程可能会饿死,或者很久才能获得锁。ReentrantLock默认是非公平锁,可通过构造函数参数设置公平锁。

    可重入锁和非可重入锁

    可重入锁:又名递归锁,是指在同一个线程在外层方法获得锁的时候,再进入该线程的内层方法会自动获得锁(前提是锁对象必须是同一个对象或者class),不会因为之前获得过还没释放而阻塞。Java中ReentrantLock和synchronized都是可重入锁,可重入的在一定成都可避免死锁:

    可重入锁避免死锁

    在上面的代码中,类中的两个方法都是被内置锁synchronized修饰的,doSomething()方法中调用doOthers()方法。因为内置锁是可重入的,所以同一个线程在调用doOthers()时可以直接获得当前对象的锁,进入doOthers()进行操作。

    如果是一个不可重入锁,那么当前线程在调用doOthers()之前需要将执行doSomething()时获取当前对象的锁释放掉,实际上该对象锁已被当前线程所持有,且无法释放。所以此时会出现死锁。

    非可重入锁相反。

    独享锁和共享锁

    独享锁:也叫排他锁,是指该锁一次只能被一个线程所持有。如果线程T对数据A加上排它锁后,则其他线程不能再对A加任何类型的锁。获得排它锁的线程即能读数据又能修改数据。JDK中的synchronized和JUC中Lock的实现类就是互斥锁。

    共享锁:是指该锁可被多个线程所持有。如果线程T对数据A加上共享锁后,则其他线程只能对A再加共享锁,不能加排它锁。获得共享锁的线程只能读数据,不能修改数据。ReentrantReadWriteLock有两把锁:ReadLock和WriteLock,读锁和写锁的加锁方式不一样。读锁是共享锁,写锁是独享锁读锁的共享锁可保证并发读非常高效,而读写、写读、写写的过程互斥,因为读锁和写锁是分离的。

    10.GC回收算法

    标记-清除法:标记没用的对象,然后一个一个回收

        缺点:标记和清除两个过程效率不高,产生内存随便导致大对象需要非配内存空间时无法找到连续内存而需要进行一次GC

    复制法:将内存空间平均分成两份,当一块区域用完之后,将有用的对象复制到另一块区域,然后把已使用的区域一次性清理

        缺点:内存空间变小

    标记-整理法:标记处没用的对象,让活着的对象向一边移动,然后直接清理掉边界以外的垃圾

        有点:解决了标记-清除法导致的内存碎片问题和存活率较高时复制算法效率低的问题

    分代回收法:根据对象存活周期的不同将内存划分为几块,一般是新生代和老年代,新生代基本用复制算法,老年代采用标记-整理算法。

    11.hashMap 1.7 / 1.8 的实现区别

    ·put时出现hash冲突,1.7把数据存放在链表里,1.8是先存放在链表中,链表长度超过8转为红黑树

    ·1.7的扩容条件是数组长度大于阈值且存在hash冲突,1.8扩容条件是数组长度大于阈值或链表转为空黑树

    使用 hashmap 时,一开始最好指定下长度,毕竟扩容时,需要重新根据 key 计算数组下标,还是很影响效率的。

    12.Java 如何高效进行数组拷贝

    JDK中提供了一个高效的API来实现数组复制。

    native方法

    System.arraycopy(array, 0, arraydst, 0, size);

    System.arraycopuy()函数是native函数,通常native函数的性能要优于普通函数

    13.简述 Spring 的初始化流程

    加载流程是:初始化环境 --> 加载配置文件 --> 实例化Bean --> 调用Bean显示信息

    a、加载Spring配置信息,并标记配置文件的资源。

    b、读取配置文件资源,然后进行解析。解析配置文件中每一个<bean>标签。

    d、进行Bean实例化操作,完成Bean属性的设置。

    e、对完成属性设置的Bean进行后续加工,直接装配出一个准备就绪的Bean。

    14.简述 synchronized,volatile,可重入锁的不同使用场景及优缺点

    synchronized:适用于同步代码执行时间较长;优点是线程不会进行自旋,不占用CPU资源;缺点是线程阻塞,响应时间长

    volatile:单例模式的双重检查;线程能直接读取内存中最新的数据;不能保证线程安全

    可重入锁:用在定时任务,如果定时任务执行时间超过下次计划执行时间,确保只有一个线程正在执行;优点是有公平和非公平两种模式,还可以避免死锁;缺点是需要在finally块中释放锁

    15.Java 线程间有多少通信方式?

    a 、通过synchronized实现:两个线程锁定同一个对象,线程1执行对象的A方法,线程2执行对象的B方法,线程2等线程线程1执行完A方法才能执行

    锁定的对象

    b、通过while循环实现:两个线程锁定同一个对象,线程1修改对象的属性,线程2检查对象属性

    c、通过wait/notify实现:生产者消费者例子。生产者往容器中添加,消费者从容器中往外拿,当容器满了停止生产开始消费,当容器空了停止消费开始生产。

    d、管道通信:通过管道,将一个线程中的消息发送给另一个。java.io.PipedInputStream 和 java.io.PipedOutputStream

    16.hashmap 和 hashtable 的区别是什么?

    1.继承的父类不同:HashTable继承自Dictionary类,而HashMap继承AbstractMap。但二者都实现了Map接口。

    2.线程安全性不同:HashTable这是线程安全的,其方法是Synchronized修饰的,HashMap是线程不安全的,可以用Collections.synchronizedMap()包装。因为多线程并发put元素,或导致数据覆盖问题。

    3.是否提供contains方法:HashMap值提供containsKey和containsValue方法,HashTable多提供了contains方法,但与containsValue功能相同。

    4.key和value是否允许null:HashMap允许一个key为null,允许多个value为null;HashTable不存于存在key或value为null,编译通过,但运行或报空指针。

    5.遍历方式实现不同:HashMap、HashTable都使用了Iterator,但HashTable还使用了Enumeration的方式 。

    6.hash值不同:HashTable直接使用key的hashCode。而HashMap重新计算hash值

    7.内部实现使用的数组初始化和扩容方式不同:HashTable初始容量默认11,HashMap默认16;HashTable不要求容量是2的次幂,HahsMap要求;Hashtable扩容时,将容量变为原来的2倍加1,而HashMap扩容时,将容量变为原来的2倍。

    17.synchronized 关键字底层是如何实现的?它与 Lock 相比优缺点分别是什么?

    实现:Java对象的锁信息存在对象头里,因此Java识别对象是否持有锁是通过检查对象头中的锁标志来判断。monitor(监视器)存在与对象头中,当尝试获取锁是,判断锁计数器是否等于0.等于0获取锁然后锁计数器加1,释放锁时锁计数器减1.

    对比:

    synchronized:优点是实现简单,自动上锁释放锁;缺点是悲观锁,效率低

    Lock:提供了读写锁、公平锁、非公平锁,更灵活;缺点是需要手动释放锁

    18.简述 Redis 中如何防止缓存雪崩和缓存击穿

    缓存穿透:查询一个本身不存在数据库的数据,这样每次查询都会访问到数据库,这样会对数据库造成很大压力。

    避免:可以将数据库不存在的值也加入缓存,存储空值并设置过期时间。

    缓存击穿:查询一个数据,恰巧这个数据在redis中失效了,会访问数据库,如果请求量很大,会给数据库造成很大压力。

    避免:比如针对热点数据短时间内访问量较大数据,适当设置大一点过期时间。

    缓存雪崩:在某一时间段,缓存集中过期失效或者重启缓存服务,所有的请求都会访问到数据库。

    避免:可以根据业务数据不同,设置不同有效期,甚至可以对同一类数据设置有效期是加入随机参数,这样可以避免同一时间全部数据或同一类数据全部过期。

    19.简述 Redis 持久化中 rdb 以及 aof 方案的优缺点

    RDB:将Redis中缓存的数据定时记录到磁盘上的dump文件中。可以配置单位时间修改若干key进行持久化。

    优点:定时fork一个子进程,现将数据写入临时文件,成功之后再替换之前文件,效率更高

    缺点:如果在定时持久化之前服务器宕机,会导致从上次持久化现在时间点数据丢失

    AOF:将Redis的操作日志追加到文件中。发生修改数据时、每秒、从不同步三种策略。

    优点:数据安全性高,当文件过大时还会进行rewrite操作来压缩文件,先写入最新的keys数据到临时文件,最终替换aof文件;文件内容清晰易懂

    缺点:同等数据量AOF恢复数据比RDB慢

    20.数据库有哪些常见索引?数据库设计的范式是什么?

    索引类型:

    唯一索引:在创建唯一索引时要不能给具有相同的索引值。

    主键索引:在我们给一个字段设置主键的时候,它就会自动创建主键索引,用来确保每一个值都是唯一的。

    聚集索引:我们在表中添加数据的顺序,与我们创建的索引键值相同,而且一个表中只能有一个聚集索引。

    普通索引:它的结构主要以B+树和哈希索引为主,主要是对数据表中的数据进行精确查找。

    全文索引:它的作用是搜索数据表中的字段是不是包含我们搜索的关键字,就像搜索引擎中的模糊查询。

    三大范式:三大范式只是一般设计数据库的基本理念

    第一范式:每一列属性都是不可再分的属性值;两列的属性相近或相似或一样,尽量合并属性一样的列;

    第二范式:每一行的数据只能与其中一列相关,即避免同一列出现重复数据,比如维护一个人的订单信息,每行是一个订单,那么人员信息每行都一样,需要拆开成订单表和人员信息表;

    第三范式:数据不能存在传递关系,即每个属性都跟主键有直接关系而不是间接关系。比如Student表(学号,姓名,年龄,性别,所在院校,院校地址,院校电话),这样一个表结构,就存在上述关系。 学号--> 所在院校 --> (院校地址,院校电话)。这样的表结构,我们应该拆开来,如下:(学号,姓名,年龄,性别,所在院校)--(所在院校,院校地址,院校电话)。

    21.Redis 如何实现分布式锁?

    满足条件:任意时刻是能有一个节点持有锁;锁只能被持有的节点删除;持有锁节点宕机不影响其他节点获取锁。

    实现:setNX,只在key不存在时设置;设置key的过期时间;在catch或者finally块中释放锁。

    22.简述 Redis 的哨兵机制

    目的:为了解决在主从复制架构中出现宕机的情况。

    Redis的Sentinel系统用于管理多个Redis服务器,系统执行三项任务

    ·监控:Sentinel会不断的定期检查你的主服务器和从服务器是否运行正常;

    ·提醒:当被监控的某台服务器出现故障,Sentinel可以通过API向管理员或者其他应用程序发送通知;

    ·自动故障迁移:当一个主服务器不能正常工作时,它会在从服务器中选择一个升级为新的主服务器,并让其他从服务器都改为复制新的主服务器;当客户端连接已经故障的服务器时,集群也会向客户端返回新的主服务器地址(此操作需要客户端连接sentinel节点,而不能连接固定ip端口的主机,否则不能实现自动切换)。

    23.简述数据库中的 ACID 分别是什么?

    A:原子性:事务中各项操作,要么全做要么全不做,任何一项操作的失败都会导致整个事务的失败

    C:一致性:事务结束后系统状态是一致的;参考守恒定律,5个账户互相转账,账户总余额不能变

    I:隔离性:并发执行的事务彼此无法看到对方的中间状态

    D:持久性:事务完成后所做的改动都会被持久化,即使发生灾难性的失败

    24.什么情况下会发生死锁,如何解决死锁?

    条件:

    互斥:同一时间内资源仅能被一个线程占有;

    不可剥夺:线程占有资源未释放前不能被其他线程占有;

    占有和等待:线程已经占有了一个资源,但又请求新的资源,但是新的资源被其他线程占有

    循环等待:前三个条件的结果。

    避免:

    线程有顺序加锁

    线程加锁有条件释放,不能无限占有

    25.Cookie和Session的关系和区别是什么?

    作用:http请求是无状态的,一旦请求数据提交完毕就会关闭请求,再次提交数据需要再发起请求,所以服务器无法追踪和判断请求管理,确定身份,而cookie和session可以帮助服务器确定用户身份。

    cookie:第一次登陆时,服务器会返回一段数据(cookie)给浏览器,浏览器会把cookie保存起来,再次发送请求会携带cookie发送给服务器,1以让服务端确认用户身份。

    session:session存在服务端,而cookie则是存储在客户端本地。第一次登陆服务器会存储session同时生成一个session_id,通过http响应头返回给浏览器,然后浏览器会把session_id保存在cookie中,下一次请求,浏览器会发送session_id到服务器,服务器通过session_id获取到对应数据来判断用户的身份。

    26.Redis 有几种数据结构?Zset 是如何实现的?

    数据类型:

    String:最基本的数据类型,一个key对应一个value。

    Hash(哈希):是一个HashMap,指值本身是一种键值对结构,如value={{field1,value1},......fieldN,valueN}}

    链表:List就是链表(redis使用的是双端链表),是有序的,value可以重复,可以通过下标取出对应的value值,左右两边都能进行插入和删除操作。

    Set(集合):集合类型也是用来保存多个字符串的元素,但和列表不同的是集合中:1.不允许有重复元素,2.集合中元素无序,不能通过索引下标获取,3.支持集合间的操作,可以去多个集合的交集、并集、差集

    zset(有序集合):去集合区别是元素可以排序,为每个元素设置一个分数,作为排序的依据。有序集合的元素不允许重复,但是分数可以重复。

    27.Redis 序列化有哪些方式?

    JDKSerializationRedisSerializer:redis默认的序列化方式。序列化的对象需要实现Serializer接口。

    Jackson2JsonRedisSerializer:如果存储对象为json的话推荐使用,不仅可以将对象序列化,还可以将对象转为json字符串保存到redis中,被序列化对象不需要实现Serializable接口。序列化结果清晰,容易阅读,存储字节少,速度快。

    StringRedisSerializer:如果key-value都是string的话,将RedisTemplate序列化方式改为Jackson2JsonRedisSerializer,StringRedisTemplate序列化方式不需要改。

    28.MySQL 为什么使用 B+ 树来作索引,对比 B 树它的优点和缺点是什么?

    区别:

    优点:

    IO次数少:B+树的非叶节点不存储数据信息,因此在内存页中能存粗更锁的key,一次查询IO次数等于B+树的高度

    遍历更加方便:B+树的叶子节点都是相连的,因此对于整棵树的遍历只需要一次线性遍历叶子几点。由于数据顺序排列且相连,便于区间查找和搜索。而B树需要对每一层递归遍历,相邻的元素可能在内存中不相邻。

    缺点:

    B树每个节点都存key和value,如果访问量高的数据接近根节点,那么查询更迅速。

    使用B+树的理由:

    B+树查询磁盘的IO次数更少,且查询效率更稳定,由于叶子节点数据排列有序且相连,便于区间查找。

    29.简述 CAP 理论

    CAP原理指的是,在分布式系统中这三个要素最多只能同时实现两个。因此在进行分布式系统设计是,必须作出取舍。而对于分布式系统,分区容忍性是基本要求,否则就失去了价值。因此设计分布式系统,就是在一致性可高可用性之间做取舍。对于大多数Web应用,其实并不去要强一致性,因此牺牲一致性换取高可用性,是目前多数分布式系统产品的方向。

    一致性(Consistency):数据在多个副本之间是否能够保持一致。(当一个系统在一致状态下更新后,应保持系统中所有数据仍处于一致的状态)

    高可用性(Availability):系统提供的服务必须一直处于可用状态,对每个操作的请求必须在有限时间内返回结果。

    分区容错性(Tolerance of network Partition):分布式系统在遇到网络分区故障时,仍然需要保证对外提供一致性和可用性的服务,除非整个网络发生故障。

    为什么只能同时满足两个:

    例如,有ABC三台服务器,value初始都收0,A服务器收到了修改value=1的请求,这是C服务器发生故障。为了满足分区容错,此时服务对外必须提供服务。

        如果满足一致性,则A服务器的修改将不会提交成功,因为C服务器故障不能完成修改

        如果满足高可用性,则允许AB服务器修改value=1

    30.简述 HTTPS 的认证过程

    1.服务器生成一对公钥和私钥

    2.把公钥放到证书里发送给客户端,私钥自己保存

    3.客户端首先向一个权威的服务器检查证书的合法性,如果证书合法,客户端会产生一段随机数,这个随机数就是通信密钥,用公钥加密这段随机数,然后发送到服务器

    4.服务器解密获取通信密钥,然后双方就用通信密钥进行加密揭秘通信

    31.

    相关文章

      网友评论

        本文标题:高级JAVA知识整理

        本文链接:https://www.haomeiwen.com/subject/ztwoyktx.html