JAVA 学习笔记 三

文章目录

redis

redis的特性


redis的使用场景

  1. 消息队列:使用 LIST 或 PUB/SUB 机制来实现消息传递和队列功能。
  2. 实时分析:利用 Sorted Sets 和 HyperLogLog 进行实时数据分析和计数。
  3. 会话存储:存储用户会话数据,例如登录状态和用户偏好。
  4. 分布式锁:利用 Redis 的 SETNX 命令实现分布式锁,以确保资源的互斥访问。
  5. 排行榜:使用 Sorted Sets 创建和管理排行榜或评分系统。
  6. 计数器:使用 INCR 命令实现高效的计数器功能,例如访问计数。
  7. 数据结构存储:利用 Redis 提供的各种数据结构(如 HASH、SET、LIST 等)来存储复杂数据类型。

哪里用到的redis,时效

  • 数据库存储 存储登录信息 token 30分钟 实现value的序列化,存储的对象
  • 缓存 路由转发,接口匹配 redismanager默认30天
    工作流暂存 10分钟:为了缓解数据库压力,开始的流程是异步进程,但是要全量进程的结果
  • 幂等性的实现 在消费消息时,将消息的uuid存储到redis中,防止重复消费

redis数据结构

String 动态字符串,类似于ArrayList

List 双向链表

Hash 数组加链表 等价于Java语言的HashMap

Set HashMap 只不过所有value都指向同一个对象

ZSet 压缩链表或者跳表

Stirng 底层实现

动态字符串sds

sds结构一共有五种header定义,目的是为了满足不同长度字符串使用,节省内存。

header主要包括:

  • len长度
  • alloc字符串最大容量,不包括header和最后的空终止字符
  • flags标志位,第三位表示类型,其余五位未使用
  • buf:字符数组
  • encoding
    • int:可以使用long类型的整数表示的会用long型来存储
    • raw:长度大于44字节的字符串,使用sds存储
    • embstr:长度小于等于44字节的字符串,效率比较高,且数据都保存在一块内存区域。

ZSet的实现方式:

ziplist压缩链表:

  • 元素数量小于128
  • 每个元素长度小于64

skiplist跳跃链表:不满足上述条件就采用跳表,具体来说组合了map和skiplist

  • map用来存储 member到score的映射, 时间复杂度为O(1)
  • skiplist按照从小到大存储分数,每个元素的值都是[score,value]对

跳表就是在有序节点上增加多级索引

n个节点,第一层索引为n/2,第二层索引为n/4,第k层索引为n/2^k

空间换时间的折半查找

redis排行榜 zset

添加

zadd key score value

ZADD broadcast:20210108231 1 lisi

加分

zincrby key increment member

ZINCRBY broadcast:20210108231 2 lisi

排名

ZRANGE broadcast:20210108231 0 -1 WITHSCORES

redis遍历key

keys pattern 一次性匹配所有key,当key比较多时,对内存消耗和redis都是隐患

SCAN cursor [MATCH pattern] [COUNT count] 2.8.0版本之后加入

scan只会返回少量元素,每次调用用上次调用返回的游标,以此延续迭代过程,返回为0标识迭代结束。

count表示从数据集返回多少个匹配元素

redis的淘汰策略

过期键淘汰策略是定期删除和惰性删除
定期删除 是指:redis服务器定期操作redis.c/serverCron函数执行时,redis.c/activeExpireCycle会被调用。actvieExpire函数在规定时间内,分多次遍历服务期内的多个数据库,从过期字典中检查一部分key的过期时间并删除。

current_db记录当前检查数据库,函数处理2号数据库时间超限,返回后下次检查会从3号数据库开始检查。所有数据库检查完毕current_db重置为0,然后再次开启一轮的检查工作。
惰性删除是指用户请求,此时会检查过期,过期清除不会返回

大量key堆积,内存耗尽如何处理?

内存淘汰机制:

缓存击穿,缓存雪崩

  • 缓存穿透:缓存和数据库中都没有数据,多次重复访问导致数据库崩溃
    解决
    • 业务层校验:对于不合规的入参,直接返回
    • 不存在数据设置短过期时间
    • 布隆过滤器
  • 缓存击穿:热点key失效同时,大量请求进入,从而全部到达数据库,压垮数据库
    解决
    • 永不过期
    • 定时更新:过期时间1h,每到59min去更新
    • 互斥锁:redis根据key获取到的value为空时,先加锁,去数据库加载,加载完毕,释放锁。其他线程请求发现获取锁失败,则睡眠一段时间。
  • 雪崩:缓存大面积失效,或者Redis宕机,大量请求进入数据库,压垮数据库
    解决
    • 设计有效期均匀分布:避免缓存设置相近的有效期,可以设置有效期时增加随机值,或者统一规划有效期,使得过期时间均匀分布。
    • 缓存预热:流量大时,提前访问一遍,将数据存储到redis中并且设置不同的过期时间
    • 保证Redis的高可用

redis的锁机制

redis一般用作缓存,多读少写,只支持乐观锁

Redis事务命令主要包括 WATCH, EXEC, DISCARD, MULTI。

事务使用MULTI开启,这时可以执行多条命令,Redis在这些事务中加入命令,当用户执行Exec命令时才真正的执行队列当中的命令。执行discard,丢弃队列中的命令。

Watch命令是Exec执行的条件,watch的key没有修改则执行事务,否则事务不会被执行。

Watch命令可以被调用多次,一个watch命令可以监控多个key。watch命令调用则开启监视功能,直到exec命令终止。

Redis的watch命令给事务CAS机制,如果key在执行exec前有变动,则整个事务被取消。

事务中,采用watch加锁,unwatch解锁,执行EXEC命令或者Discard命令后,锁自动释放,不需要进行unwatch操作。

redis分布式锁

参考:Redis实现分布式锁的7种方案

分布式锁需要保证:

1.互斥性:只能有一个客户端获得锁

2.安全性:锁只能被持有该锁的客户端删除

3.死锁:锁超时释放,避免死锁

4.容错:当redis部分节点宕机,客户端仍能获取锁和释放锁

1.一种实现

setnx k v; 成功返回1 失败返回0;

getset k v;返回key的旧值;

expire k secondsl;给key设置超时时间

del key [key ...]

1.1setnx key 当前时间+过期时间

1.2. 失败获取锁失败,成功 expire 超时时间

1.3.执行业务 del key

问题:如果获取锁成功未设置超时时间的时候进行重启,会产生死锁。

(如果不是kill线程,而是shutdown可以用springBean的predestory注解,进行删除key操作)

优化:获取锁失败后,查看当前key的value值,如果不为空,并且当前时间大于该值,说明当前锁失效,通过getset获取值。如果getset获取的值,和一开始的旧值相同,则获取锁成功。

问题:多节点时间需要尽可能的保持一致。getset即便失败也会延长之前锁的时间。

2.使用lua脚本

保证setnx和expire的原子性
3.set扩展命令

SET key value[EX seconds][PX milliseconds][NX|XX]

  • NX :表示key不存在的时候,才能set成功,也即保证只有第一个客户端请求才能获得锁,而其他客户端请求只能等其释放锁,才能获取。
  • EX seconds :设定key的过期时间,时间单位是秒。
  • PX milliseconds: 设定key的过期时间,单位为毫秒
  • XX: 仅当key存在时设置值

问题:业务没执行完,锁就释放了;锁被别的线程误删。
4.SET EX PX NX + 校验唯一随机值,再删除

还是会存在业务没有执行完成,锁释放的问题。
5.Redisson框架

开源框架Redisson

加锁后启动一个watchdog线程,每隔10s检查是否持有锁,持有锁就延长,防止锁过期提前释放。

6.redlock+redisson

redis节点全为master,避免master加锁后未同步到slave然后宕机导致加锁失败的情况

按顺序向5个master节点请求加锁

根据设置的超时时间来判断,是不是要跳过该master节点。

如果大于等于3个节点加锁成功,并且使用的时间小于锁的有效期,即可认定加锁成功啦。

如果获取锁失败,解锁!

持久化方案

redis线程模型

参考 深入学习redis 的线程模型

redis内部采用事件处理器是单线程的,因此redis叫做单线程模型。采用IO多路复用机制同时监听多个socket,将产生的事件的socket压缩到内存队列中,事件分派器根据事件不同的类型选择对应的事件处理器进行处理。

文件事件处理器的结构

  • 多个socket
  • IO多路复用程序
  • 文件事件分派器
  • 事件处理器(连接应答处理器,命令请求处理器,命令回复处理器)

线程模型

多个socket可能并发产生不同的操作,每个操作对应不同的事件,但是IO多路复用程序会监听多个socket,将产生事件的socket放入队列中排队,事件分派器每次从队列中取出一个socket,根据socket对应的事件类型交给对应的事件处理器进行处理。

建立连接

  • redis服务端进程初始化时,将server socket 的AE_READABLE事件与连接应答处理器关联。
  • 客户端socket01向redis进程serverSocket请求建立连接,此时server socket 产生一个AE_READBLE事件,IO多路复用程序监听到server socket产生的事件后,将socket压入队列。
  • 文件事件分派器从队列中获取socket,交给连接应答处理器。
  • 连接应答处理器会创建一个能与客户端通信的socket01,并将socket01的AE_READABLE事件与命令请求处理器关联
    执行一个set请求
  • 客户端发送了一个set key value请求,此时redis中的socket01会产生AE_READABLE事件,IO多路复用程序,将socket01压入队列
  • 此时事件分派器从队列中获取到socket01产生的AE_READABLE事件,由于前面socket01的AE_READABLE事件已经和命令请求处理器关联
  • 事件分派器将命令交给请求处理器来处理。命令处理器读取k v并在自己内存中完成设置
  • 操作完成后,将socket01的AE_WRITEABLE事件与命令回复处理器关联
  • 如果此时客户端准备好了接受数据,那么redis中的socket01会产生一个AE_READABLE事件,同样压入队列中
  • 事件派分器找到相关联的命令回复处理器,由命令回复处理器对socket01输入本次操作的一个结果,比如ok,之后解除socket01的AE_READABLE事件与命令回复处理器的关联。

为什么redis效率高?

1.纯内存操作

2.核心是基于非阻塞的IO多路复用机制

3.C语言实现,语言更接近操作系统,执行速度相对会快

4.单线程反而避免了多线程的频繁上下文切换问题,预防了多线程可能产生的竞争问题。

redis的吞吐量:

单点TPS达到8万/秒,QPS达到10万/秒

qps是指每秒最大能接受的用户访问量,tps是指每秒钟最大能处理的请求数。

部署方式

单机,主从,哨兵

kafka

核心概念

Producer(生产者):负责将消息发送到 Kafka 集群中的某个主题(Topic)。生产者将数据发布到 Kafka 中,可以并行发送数据。

Consumer(消费者):从 Kafka 中消费消息。消费者可以独立工作,也可以作为消费组的一部分,并行消费同一主题的数据。

Broker(代理):Kafka 集群中的每个节点都被称为一个 Broker。Kafka 集群可以由多个 Broker 组成。它负责接收、存储和转发消息。每个 Broker 都管理一部分分区的数据。

Topic(主题):Kafka 中的消息被按主题分类。每个生产者将消息发送到某个主题,消费者可以订阅某个主题并从中消费消息。主题是 Kafka 消息流的一个分类单位。

Partition(分区):Kafka 中的每个主题可以划分为多个分区。每个分区内的消息有序,并且每个分区的数据是由一个 Broker 来管理的。分区使得 Kafka 可以实现水平扩展,提高吞吐量。

Offset(偏移量):每个消息在分区内都有一个唯一的偏移量。消费者通过这个偏移量来追踪自己消费的位置。偏移量是分区内消息的顺序编号。

ZooKeeper:Kafka 使用 ZooKeeper 来管理和协调集群的元数据,如 Broker 信息、消费者组的偏移量等。ZooKeeper 作为一个集群管理工具,确保 Kafka 集群的高可用性和一致性。

使用消息队列的原因

1.流量削峰(消息过多,处理有限) 落库采用异步消息的方式,减缓数据库压力

2.服务解耦(接口故障不影响生产和消费)消息发出去,发消息的应用down了,也不会影响后序微服务的消费

3.异步(提高响应速度,用户无感知)

kafka 如何解决消息重复

  • 生产者:生产者发送的消息没有收到正确的broker响应,导致producer重试。

    以及 ack=all 以及 retries > 1 。ack=0,不重试。可能会丢消息,适用于吞吐量指标重要性高于数据丢失,例如:日志收集

    启动kafka的幂等性,设置: enable.idempotence=true幂等生产者的原理:每个生产者都有唯一Pid,发次发送消息会累加seq。broker为每个topic的每个分区都维护了一个当前当前写成功的消息最大PID-seq,消息落盘+1,当收到小于当前最大PID-seq时就会丢弃该消息。

  • 消费者:

    offset手动提交,业务成功处理后,提交offset

    幂等性:多次操作结果一致

    获取消息的唯一id,会将id存入redis,记录为处理中,以后的消息就不会进行重复处理

kafka如何保证消息不丢失

1.生产者发送给服务器

acks机制 0 发送就成功,1 生产者收到leader分区的响应则认为成功 -1 当所有ISR中的副本全部收到消息,生产者才认为是成功的

2.服务器通过副本保存消息

3.消费者,关闭自动提交,在接收到消息,进行业务处理完毕后再提交偏移量

kafka什么时候进行rebalance

参考Kafka的Rebalance机制可能造成的影响及解决方案

每当有新的消费者加入或者订阅的topic数发生变化,会触发rebalance(再均衡:在同一个消费组当中,分区的所有权从一个消费者转到另一个消费者)机制,Rebalance顾名思义就是重新均衡消费者消费。

过程如下:

1.所有消费者向coordinator发送请求,请求加入comsumer group。一旦所有成员都发送了请求,Coordinator会从中选择一个consumer作为leader,并将组员信息发给leader

2.leader分配消费方案,指定哪个消费者消费哪些topic的哪些分区。发给coordinator,coordinator发送给消费者,组内成员知道自己该消费哪些分区了。

coordinator:每个consumer group会选择一个服务器作为自己的coordinator,负责监控整个消费者组内各个分区的心跳,以及判断是否宕机和开启rebalance的

partition:每个topic分区,备份在不同的服务器上

如何选择coordinator?

对groupid进行hash,然后对_consumer_offsets的分区数量进行取模,默认分区数量为50,可以配置。

发生的时机:

1.分区数量增加。

2.对topic的订阅发生变化

3.消费者组成员的加入或者离开。

影响:1.重复消费;2.集群不稳定;3.影响消费速度

kafka 消息积压怎么办

参考

1.修复消费者,然后停掉所有消费者

2.临时建立10倍或者20倍的queue数量(新建topic,分区是原来的10倍)

3.写一个临时分发消息的consumer,消费挤压数据不作处理,均匀写入临时建好10数量的queue中

4.征用10倍的机器来部署consumer,每一批consumer消费一个临时queue的消息

5.这种做法相当于临时将queue资源和consumer资源扩大10倍,以10倍速度来消费消息

6.消费完成之后,回复原有的部署架构,重新用原来的consumer机器来消费消息。

kafka分区和消费者的关系

1.生产者中的分区合理消费,消费者的线程对象和分区保持一致,多余的线程不会进行消费

2.消费者默认即为一个线程对象

3.消费者服务器数*线程数 = partition个数

分区数量

分区多可以增加吞吐量

分区过多:

  • 客户端服务端需要的内存变多,客户端生产者有个参数batchsize,默认16kb。为每个分区缓存消息,满了打包发送。
    分区越多,消费者获取数据所需的内存就增多。同时消费者线程数要匹配最大分区数,线程切换开销很大。
    服务器端维护许多分区界别的缓存。
  • 文件句柄的开销:每个分区在底层文件系统都有属于自己的目录。分区越多,要同时打开的文件句柄数就越多。
  • 降低高可用性:kafka通过副本来保证高可用。分区多,服务器上的副本就多,服务器挂掉,在副本之间进行重新选举的消耗就大。

目标吞吐量TT,消费者吞吐量TC,生产者吞吐量TP,分区数= TT/max(TP,TC)

分区和消费者的关系是多对一

一个分区只能对应一个消费者的原因是保证消息顺序性。

因此消息挤压,部署多台消费者实例是不能加快消费的,最多增加到和分区数量一致,超过的组员只会占有资源二不起作用。

消费者分区分配策略

1.range策略

  • 将消费者按名称排序,分区按照数字排序
  • 分区总数/消费者,除得尽均匀分配,除不尽位于前面的消费多负责分区

2.roundrobin 轮询

为了保证均匀分配,需要满足两个条件

1.同一个消费者组里每个消费者订阅的主题必须相同

2.同一个消费者里面所有消费者的num.streams必须相等

3.sticky分配策略

主要实现两个目的,如果发生冲突,优先实现第一个

1.分区分配尽可能均匀

2.分区的分配尽可能的与上次分配的保持相同

0.11.X版本引入,最复杂最优秀

区别于轮询,在消费者挂掉之后,不会全部分区重新轮询分配,而是将挂掉消费者消费的分区进行重新分配。

其他微服务组件

eureka特性

  • cap

    Consistency(一致性)

    Availability(可用性)

    Partition tolerance(分区容忍性)

    任意组合,不能兼得 eureka ap zk cp

    注册慢:ap特性,client延迟注册 30s;server 响应缓存 30s;server 缓存刷新 30s

  • 自我保护机制: eureka会检查最近15分钟服务正常心跳占比,低于85%出发自我保护模式,不剔除服务。但是服务也会过期,eureka在启动完成后,每隔60s检查服务健康状态,如果被保护的服务过一段时间默认90s还没有恢复就会把服务剔除。

    在此期间高于85%,自动关闭自我保护机制。

    自我保护原因:避免因为网络通信故障降低可用性。

    一般开发关闭,因为开发经常重启。生产开启。生产环境相对稳定,让eureka管理。

  • 服务注册:启动注册,发送主机名,端口号等

  • 服务续约:30s一次,90s没收到进行服务剔除

  • 服务下线:client优雅退出发送cancel命令,server接到命令删除节点

  • 获取注册列表:第一次全量更新,后续增量更新,30s一次

eureka注册中心机制

参考高频面试之Eureka

注册中心,包括服务发现,治理等功能。

@EnableEurekaServer作为注册中心,@EnableEurekaClient作为服务的提供者或消费者。

  • 注册服务
    EurekaClient将服务信息封装成Intanceinfo对象,通过EurekaHttpClient调用register方法发送post请求执行服务注册;
    EurekaServer提供了基于Jersey的Rest风格接口,在ApplicationResource类中提供了addInstance方法来接受注册信息。如果注册信息通过校验,将服务信息保存到本地注册表。数据结构为双层HashMap,key为应用名,内层map,Key是应用实例信息编号,value是InstanceInfo
    EurekaClient接受并解析注册结果,判断httpResponse的statusCode,如果是204则代表注册成功
    调用replicateToPeers方法将此次注册信息复制到对等的Eureka节点
  • 定时任务
    • 拉取服务器注册实例
      任务通过ScheduledExecutorService来实现任务调度,执行周期默认为60秒一次
      获取方式有两种,全量获取和增量获取。第一次全量获取,后序增量获取;获取到服务器注册实例信息后,保存或更新到本地
      • 续约
        任务通过ScheduledExecutorService来实现任务调度,执行周期默认为30秒一次
        通过Renew方法发起续约请求。将appname,appid以及intanceinfo作为参数,通过EurekaHttpClien发送Http请求
        EurekaServer通过renewLease()方法接受续约请求
        根据AppName从注册表获取对应的服务信息,并更新一些属性如renewsLastMin,lastUpdateTimestamp
        EurekaServer返回结果200或者204
        EurekaClient接受续约结果;如果是404重新发起,如果是200则表示续约成功,更LastSuccessHeartBeatTimestamp变量
      • 剔除服务
        通过 JDK 自带的 Timer 来实现任务调度,通过 evict() 方法执行具体的操作
        首先判断是否开启了实例自我保护机制,如果开启自我保护,则不做任何操作
        如果未开启,根据 lastUpdateTimestamp 收集已过期的服务,加入到List集合中
        通过 internalCancel() 方法,在该方法中从 registry 中剔除已经过期的实例。具体的剔除过程会通过打乱过期服务列表,并通过 Random 随机剔除,保证服务器剔除的均匀性

Eureka

feign ribbon eureka

feign在调用时会被ribbon拦截,RibbonLoadBalancerClient中构建了一个ILoadBalancer来确定应用名对应的真实ip,

内部调用eureka的服务发现获取服务发现缓存的服务信息。

更新是在RibbonClientConfiguration创建定时任务30s一次

eureka和nacos的区别

限流算法

一致性哈希

一致性哈希相较于普通哈希具有更好的可扩展性和容错性。

哈希是对节点个数取模,在进行扩容或者节点下线时,需要重新映射所有数据。

一致性哈希是对2^32取模,将哈希值空间映射到虚拟的闭环上,称为哈希环。取模所得值,进行顺时针寻找到的第一个节点为哈希环中的位置。节点扩容和下线时只需要迁移相邻节点的数据。

当分布不均衡时,采用虚拟节点来解决问题。

无状态的服务,消费降级

linux命令

cat 文件 | grep 关键字 | wc -l

参考 Linux系统中统计文件中某个字符出现次数命令详细教程

  • 不分大小写统计
    grep -o -i 'a' aaa.txt | wc -l
  • 统计多个文件中某个字符出现次数总和
    grep -o -i 'a' aaa.txt bbb.txt | wc -l

其他

分布式锁

1.数据库

在数据库中以资源唯一号为主键插入数据,处理完成后删除数据

问题:

  • 释放锁失败会导致死锁,需要定时任务定时清理
  • 锁的可靠性依赖数据库,建议设置备库,避免单点
  • 锁是非阻塞的,因为插入失败会报错;如果需要阻塞式的设置for,while循环等
  • 非可重入的锁,需要在数据库中添加字段获取主机信息,匹配的话重新分配给他。

乐观锁:查询数据和版本号,进行更新,更新成功加锁成功

问题:

  • 对表增加额外字段,增加数据库冗余
  • 并发量高的时候,会导致大量请求失败,以及大量请求对数据库的压力。

适合并发量不高,且操作不频繁的场景

悲观锁:增加排它锁 select for update;更新数据。

问题: 每次请求都会都会产生额外的加锁开销并且阻断等待锁的获取,高并发的情况下,容易造成大量请求阻塞,影响可用性。

2.缓存 redis redlock和redission实现,所有节点均为master,加锁轮询请求,超过半数即为加锁成功,否则加锁失败

3.zookeeper:

zk是一个为分布式提供一致性服务的开源软件。

它内部是一个分层的文件系统目录结构,规定同一个目录下只能有一个唯一文件名。

基于zookeeper实现分布式锁的步骤:

  1. 创建一个目录myLock
  2. 线程A获取锁就在myLock下创建临时顺序节点
  3. 获取目录下所有子节点,找到比自己小的,如果不存在,获得锁
  4. 线程B获取所有节点,判断不是最小节点,设置监听比自己小的节点。
  5. A处理完毕后,删除节点,线程B监听到变更事件,判断自己是不是最小节点,如果是则获得锁。
    可以使用zookeeper第三方库Curator客户端
    问题:
  • 性能没有缓存高,每次加锁释放锁都需要动态的创建,销毁临时节点来实现锁功能。zk中创建和删除节点都需要通过leader来执行,同步到fllower上。
  • zookeeper也可能有并发问题。当获取锁的客户端和zk的session连接断了,就会删除临时节点,其他线程就会获得锁。不常见是因为zk有重试机制,Curator客户端支持多种重试策略的配置。

参考堆的应用 -- Top-K问题(巨详细)

堆是二叉树,一般的二叉树用链表存储,用数组存储会浪费空间,但是堆是完全二叉树,用数组存储。

已知父节点下标n, 他的右节点为2n+2,左节点2n+1

已知子节点n,他的父节点为(n-1)/2

大根堆和小根堆

大根堆:根节点大于左右孩子节点

小根堆:根节点小于左右孩子节点

优先级队列

java提供这种数据结构,每次添加或者删除元素,都会变成小跟堆。

java 复制代码
// 默认得到一个小根堆
PriorityQueue<Integer> smallHeap = new PriorityQueue<>();
smallHeap.offer(23);
smallHeap.offer(2);
smallHeap.offer(11);
System.out.println(smallHeap.poll());// 弹出2,剩余最小的元素就是11,会被调整到堆顶,下一次弹出
System.out.println(smallHeap.poll());// 弹出11

 // 如果需要得到大根堆,在里面传一个比较器
 PriorityQueue<Integer> BigHeap = new PriorityQueue<>(new Comparator<Integer>() {
     @Override
     public int compare(Integer o1, Integer o2) {
         return o2 - o1;
     }
 });

top-K问题

数组,找出前三个最小元素

1.排序

2.放入小跟堆

3.在大根堆中放三个元素,循环数组每次往里放一个数据,弹出最大的数据,最后堆里就是结果。

堆的向下调整算法、堆的向上调整算法、堆的实现、Topk问题

数据格式标准化

xml到标准对象 thoughtworks.xstream 流

json到标准对象 hutools工具,底层反射调用set方法

javaBean

java语言中的可重用组件。

满足:1.类是公共的;2.有一个无参的公共构造器;3.有属性,且有对应的get和set方法。

其他开发者通过JSP,Servlet 其他JavaBean,applet程序或者应用来使用这些对象。用户可以认为JavaBean提供了一种随时随地复制粘贴的功能。

javaBean的任务就是一次性编写,任何地方执行,任何地方重用。

synchronized在哪用到

createMaxNo 开启数据库事务,sf for update 增加数据库排他锁

同一个应用有一个缓存,加同步锁,避免并发重复增加步长,造成浪费。

应用之间由数据库的排他锁协调。

ConditionalOnMissingBean注解

在beanFactory中没有指定的bean才能匹配,主要用来做自动配置,当没有指定类的时候,使用默认配置

确保使用注解的bean在指定bean的后面运行,否则会失效。

ConditionalOnBean

指定类存在时,实例化当前Bean

ConditionalOnClass

指定类名在类路径上存在,实例化当前Bean

ConditionalOnMissingClass

指定类名在类路径上不存在,实例化当前Bean

actuator

找到HealthContributor类型bean进行健康注册,健康检查的时候检查这些bean

redis池化

JedisPoolConfig

相关推荐
Zsh-cs2 小时前
Maven
java·maven
BD_Marathon2 小时前
Spring系统架构
java·spring·系统架构
Hello.Reader2 小时前
Flink ML Bucketizer 连续特征分桶(多列映射、splitsArray、handleInvalid)+ Java 示例解读
java·算法·flink
糕......2 小时前
Java IO流:数据传输的艺术与机制
java·开发语言·网络·学习
栗少2 小时前
the-science-of-storytelling
学习
a程序小傲2 小时前
蚂蚁Java面试被问:分布式Session的实现方案
java·分布式·面试
a努力。2 小时前
京东Java面试:如何设计一个分布式ID生成器
java·分布式·后端·面试
好奇龙猫2 小时前
【人工智能学习-AI-MIT公开课-第6.博弈,极小化极大化,α-β】
人工智能·学习