常见知识点总结:

一、Java基础

1.1、HashMap相关

  • 基本数据结构(1.7和1.8)

数组+链表/数组+链表+红黑树,转换时机

  • 红黑树的定义(为什么不能是其他树)

基本定义:是一种只含有红黑结点并能自平衡的二叉查找树(左旋、右旋、变色),再插入和删除破坏树的平衡结构时,会进行自旋到平衡

基本性质

  • 性质1:每个节点要么是黑色,要么是红色。

  • 性质2:根节点是黑色。

  • 性质3:每个叶子节点(NIL)是黑色。

  • 性质4:每个红色结点的两个子结点一定都是黑色。

  • 性质5:任意一结点到每个叶子结点的路径都包含数量相同的黑结点。

  • 性质5.1:如果一个结点存在黑子结点,那么该结点肯定有两个子结点

  • 扩容机制(2倍,为什么)

无参构造初始大小16,加载因子0.75,2的幂次,超过长度*负载因子时会2倍扩容,好处:计算索引位置时,
避免了一些Hash冲突,如果当前位置有元素(替换或生成链表,取决于key的值),当链表长度大于8

  • hash碰撞定义如何解决 不同的值有不同的Hashcode
    可参考文章

  • 引申(同类,并发,实现区别,包括ConcurrentHashMap,HashTable)

    多线程,扩容的时候线程不安全 HashTable,全部synchronized,
    1.8之前用了可重入锁,
    1.8之后用了无锁,解决的ConcurrentHashMap ConcurrentHashMap

    在JDK1.7版本中,ConcurrentHashMap的数据结构是由一个Segment数组和多个HashEntry组成,
    Segment数组的意义就是将一个大的table分割成多个小的table来进行加锁,也就是上面的提到的锁分离技术,
    而每一个Segment元素存储的是HashEntry数组+链表,这个和HashMap的数据存储结构一样

    JDK1.8的实现已经摒弃了Segment的概念,而是直接用Node数组+链表+红黑树的数据结构来实现,
    并发控制使用Synchronized和CAS来操作,整个看起来就像是优化过且线程安全的HashMap,
    虽然在JDK1.8中还能看到Segment的数据结构,但是已经简化了属性

  • put 方法执行机制

先是

  public V put(K key, V value) {
   
        return putVal(hash(key), key, value, false, true);
    }

再是

    /**
     * Implements Map.put and related methods
     *
     * @param hash hash for key
     * @param key the key
     * @param value the value to put
     * @param onlyIfAbsent if true, don't change existing value
     * @param evict if false, the table is in creation mode.
     * @return previous value, or null if none
     */
    final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
                   boolean evict) {
        Node<K,V>[] tab; Node<K,V> p; int n, i;
        if ((tab = table) == null || (n = tab.length) == 0)
            n = (tab = resize()).length;
        if ((p = tab[i = (n - 1) & hash]) == null)
            tab[i] = newNode(hash, key, value, null);
        else {
            Node<K,V> e; K k;
            if (p.hash == hash &&
                ((k = p.key) == key || (key != null && key.equals(k))))
                e = p;
            else if (p instanceof TreeNode)
                e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);
            else {
                for (int binCount = 0; ; ++binCount) {
                    if ((e = p.next) == null) {
                        p.next = newNode(hash, key, value, null);
                        if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st
                            treeifyBin(tab, hash);
                        break;
                    }
                    if (e.hash == hash &&
                        ((k = e.key) == key || (key != null && key.equals(k))))
                        break;
                    p = e;
                }
            }
            if (e != null) { // existing mapping for key
                V oldValue = e.value;
                if (!onlyIfAbsent || oldValue == null)
                    e.value = value;
                afterNodeAccess(e);
                return oldValue;
            }
        }
        ++modCount;
        if (++size > threshold)
            resize();
        afterNodeInsertion(evict);
        return null;
    }

1.2、内存模型

  • 基本内存模型和数据共享区(和JDK版本有关系)

1.8之前

1.8之后

  • 关于类加载过程

  • 堆内存细分?

1.3、GC

1、吞吐量:即单位时间内的处理能力。 2、最大暂停时间:因执行GC而暂停执行程序所需的时间。
3、堆的使用效率:鱼与熊掌不可兼得,堆使用效率和吞吐量、最大暂停时间是不可能同时满足的。即可用的堆越大,GC运行越快;相反,想要利用有限的堆,GC花费的时间就越长。
4、访问的局部性:在存储器的层级构造中,我们知道越是高速存取的存储器容量会越小(具体可以参看我写的存储器那篇文章)。由于程序的局部性原理,将经常用到的数据放在堆中较近的位置,可以提高程序的运行效率。

基本算法包括:标记清除算法,复制算法,标记压缩算法

1.4、线程池

1.4.1、基本参数及其含义

    public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue,
                              ThreadFactory threadFactory,
                              RejectedExecutionHandler handler) {
    }

一、corePoolSize 线程池核心线程大小

线程池中会维护一个最小的线程数量,即使这些线程处理空闲状态,他们也不会 被销毁,除非设置了allowCoreThreadTimeOut。这里的最小线程数量即是corePoolSize。

二、maximumPoolSize 线程池最大线程数量

一个任务被提交到线程池后,首先会缓存到工作队列(后面会介绍)中,如果工作队列满了,则会创建一个新线程,然后从工作队列中的取出一个任务交由新线程来处理,而将刚提交的任务放入工作队列。线程池不会无限制的去创建新线程,它会有一个最大线程数量的限制,这个数量即由maximunPoolSize来指定。

三、keepAliveTime 空闲线程存活时间

一个线程如果处于空闲状态,并且当前的线程数量大于corePoolSize,那么在指定时间后,这个空闲线程会被销毁,这里的指定时间由keepAliveTime来设定

四、unit 空间线程存活时间单位

keepAliveTime的计量单位

五、workQueue 工作队列

新任务被提交后,会先进入到此工作队列中,任务调度时再从队列中取出任务。jdk中提供了四种工作队列:

①ArrayBlockingQueue:基于数组的有界阻塞队列,按FIFO排序。新任务进来后,会放到该队列的队尾,有界的数组可以防止资源耗尽问题。
当线程池中线程数量达到corePoolSize后,再有新任务进来,则会将任务放入该队列的队尾,等待被调度。如果队列已经是满的,
则创建一个新线程,如果线程数量已经达到maxPoolSize,则会执行拒绝策略。

②LinkedBlockingQuene: 基于链表的无界阻塞队列(其实最大容量为Interger.MAX),按照FIFO排序。
由于该队列的近似无界性,当线程池中线程数量达到corePoolSize后,再有新任务进来,会一直存入该队列,
而不会去创建新线程直到maxPoolSize,因此使用该工作队列时,参数maxPoolSize其实是不起作用的。

③SynchronousQuene:一个不缓存任务的阻塞队列,生产者放入一个任务必须等到消费者取出这个任务。也就是说新任务进来时,不会缓存,
而是直接被调度执行该任务,如果没有可用线程,则创建新线程,如果线程数量达到maxPoolSize,则执行拒绝策略。

④PriorityBlockingQueue: 具有优先级的无界阻塞队列,优先级通过参数Comparator实现。

六、threadFactory 线程工厂

创建一个新线程时使用的工厂,可以用来设定线程名、是否为daemon线程等等

七、handler 拒绝策略

当工作队列中的任务已到达最大限制,并且线程池中的线程数量也达到最大限制,这时如果有新任务提交进来,该如何处理呢。
这里的拒绝策略,就是解决这个问题的,jdk中提供了4中拒绝策略:

①CallerRunsPolicy:该策略下,在调用者线程中直接执行被拒绝任务的run方法,除非线程池已经shutdown,则直接抛弃任务

②AbortPolicy:该策略下,直接丢弃任务,并抛出RejectedExecutionException异常。

③DiscardPolicy:该策略下,直接丢弃任务,什么都不做。

④DiscardOldestPolicy:该策略下,抛弃进入队列最早的那个任务,然后尝试把这次拒绝的任务放入队列

1.4.2、实际操作应注意的

1.核心线程满了,接下来进队列,队列也满了,创建新线程,直到达到最大线程数,之后再超出,会进入拒绝rejectedExecution

1.4.3、JUC下基本线程池

五种基本线程池使用场景

1.4.4、Spring线程池使用

1.5、并发,锁

  • synchronized重量级锁

二、Spring/Springboot,基础框架系列知识点

2.1、Bean 生命周期

2.2、SpringBean执行机制

2.3、JPA+QueryDsl相关

2.4、Mybatis相关(1,2级缓存)

本地缓存和二级缓存,范围不同,本地缓存是sqlSession级别,二级缓存基于nameSpace,多表的时候,出现脏数据

三、微服务相关知识点

3.1、微服务基本架构方式

3.1.1、 AlibabaCloud(nacos+sentinel) / Dubbo

3.1.2、 SpringCloud(eureka+feign+hystrix+apollo+zuul+gateway+ribbon)

  • 相关组件源码
  • 相关组件使用及场景
  • 链路追踪

eureka 的相关注册发现源码
feign源码实现
hystrix断路器配置
ribbon负载均衡策略

几种均衡策略包括

  • RandomRule 随机策略 随机选择server

  • RoundRobinRule 轮询策略 按照顺序选择server(ribbon默认策略)

  • RetryRule 重试策略 在一个配置时间段内,当选择server不成功,则一直尝试选择一个可用的server

  • BestAvailableRule 最低并发策略 逐个考察server,如果server断路器打开,则忽略,再选择其中并发链接最低的server

  • AvailabilityFilteringRule 可用过滤策略 过滤掉一直失败并被标记为circuit tripped的server,过滤掉那些高并发链接的server(active connections超过配置的阈值)

  • ResponseTimeWeightedRule 响应时间加权重策略 根据server的响应时间分配权重,响应时间越长,权重越低,被选择到的概率也就越低。响应时间越短,权重越高,被选中的概率越高,这个策略很贴切,综合了各种因素,比如:网络,磁盘,io等,都直接影响响应时间

  • ZoneAvoidanceRule 区域权重策略 综合判断server所在区域的性能,和server的可用性,轮询选择server并且判断一个AWS Zone的运行性能是否可用,剔除不可用的Zone中的所有server

apollo架构和使用

四、MQ

四大MQ,包括Kafka,ActiveMQ,RabbitMQ,RocketMQ

4.1、Kafka

4.1、ActiveMQ

4.1、RabbitMQ

4.1、RocketMQ

五、搜索引擎/Nosql

包括ES,Solr,Redis,MongoDB

5.1、Redis相关

5.1.1、 基本使用场景

  • 分布式锁实现、优缺点,和注意事项
  • 缓存
  • MQ
  • 排行榜

六、数据库

6.1、基础知识

  • 索引类型和方法
  • SQL优化(执行计划+索引+SQL优化)

七、数据结构和算法