Java查漏补缺--知识点

1、面试知识点

1.1、说说映射和反射

反射和映射–简书
反射是一种机制,映射是一种关系。

反射在运行状态下,对于任意一个类,知道这个类的所有属性和方法;对于任意对象,能够调用它的任意方法和属性。
反射机制的功能:运行时判断任意一个对象所属的类;运行时构造任意一个类的对象;运行时调用任意一个对象的方法生成动态代理。

映射:一种特殊的对应关系,

1.2 进程和线程的区别
  • 进程:进程是程序的一次执行过程,是一个动态概念,是程序在执行过程中分配和管理资源的基本单位,每一个进程都有一个自己的地址空间,至少有 5 种基本状态,它们是:初始态,执行态,等待状态,就绪状态,终止状态。
    在这里插入图片描述
    图片来源
  • 线程: 线程是CPU调度和分派的基本单位,它可与同属一个进程的其他的线程共享进程所拥有的全部资源。
  • 联系:线程是进程的一部分,一个线程只能属于一个进程,而一个进程可以有多个线程,但至少有一个线程。
  • 区别:进程是操作系统资源分配的基本单位,而线程是任务调度和执行的基本单位
1.3 抽象类和接口区别

接口:可以多继承;所有方法都是抽象的;方法的类型为public static;成员变量类型为public static final无静态方法;无构造方法;不能实例化。

抽象类:只能单继承;抽象类中也可以有非抽象方法;方法可用public protected修饰;变量用任意修饰符;可以有静态方法;有构造方法;通过子类间接实例化。

1.4 wait,sleep,notify,notifyall
  • sleep():睡眠时(被挂起时),仍保持对象锁,占有该锁,,属于Thread类,任何地方使用,需要捕获异常
  • wait():睡眠时(被挂起时),释放占有的锁,属于Object类,只能同步块中使用,不需要捕获异常
  • notify:随机唤醒一个线程
  • notifyAll:唤醒全部线程
1.5 Object类有哪些方法?★
  • clone()
  • getClass()
  • toString()
  • finalize()
  • equals()
  • hashcode()
  • wait()
  • notify()/notifyAll()/
1.6 面向对象的三大特征和五大基本原则
  • ★三大基本特征
  1. 封装
    将对象的属性和方法私有化,同时提供被外界访问的属性方法。目的是增强安全性和简化编程
  2. 继承
    使用已存在的类作为基础来建立新类,可以使用父类功能也可以重写,不能够选择继承
  3. 多态
    程序定义的引用变量,只有在程序运行时才能够确定会指向那个实例对象,调用哪个类的方法。优点包括:消除类型之间的耦合关系、可替换性、可扩充性、接口性等等。
  • ★五大基本原则
  1. 单一职责原则
    一个类应该有且只有一个改变他的理由,意味着一个类应该只有一项工作,即类实现的功能要单一
  2. 开放封闭原则
    对象或实体应该对扩展开放,对修改封闭。
    对修改封闭即是我们对模块进行扩展时,勿需对源有程序代码和DLL进行修改或重新编译文件
  3. 里氏替换原则
    子类型必须能够替换掉它们的父类型。简单地说,这是因为子类型继承了父类,所以子类可以以父类的身份出现。
  4. 接口隔离原则
    不应强迫客户端实现一个它用不上的接口,或是说客户端不应该被迫依赖它们不使用的方法,使用多个专门的接口比使用单个接口要好的多!
  5. 依赖倒置原则
    高层次的模块不应该依赖于低层次的模块,他们都应该依赖于抽象。具体实现应该依赖于抽象,而不是抽象依赖于实现。

2、AQS锁★——队列同步器AbstractQueuedSynchronizer

AQS参考:
AQS是一个抽象类不可以被实例化。它内部提供了一个FIFO的等待队列,用于多个线程等待一个事件(锁)。它有一个重要的状态标志——state,该属性是一个int值,表示对象的当前状态(如0表示lock,1表示unlock)。通过CAS来改变它(state标志)的值。

独占锁:ReentrantLock、ReentrantReadWriteLock.WriteLock
共享锁:ReentrantReadWriteLock.ReadLock、CountDownLatch、CyclicBarrier、Semaphore

AQS运行的流程★★★:

  1. 线程A,B,C想要抢占一个资源做操作;
  2. 线程A先得头筹获得了对象的锁。在它持有资源的同时,其他线程就会被阻塞,依次加入到同步队列中去,顺序为B,C;
  3. 每一个Node入队都会自旋检查自己前一个节点是不是signal状态,如果是signal(唤醒)状态,就阻塞自己,等待唤醒;如果不是,就自旋【尝试获取锁,获取不到就尝试将它变成signal状态】这个过程;
  4. 当线程A执行完毕后,它会释放锁,然后唤醒同步队列的头结点,这时候头结点B就会去获取锁;
  5. 当B获得锁之后,他发现之前线程A的操作让当前资源队列的元素为空,而它要做的操作是一个take()操作。无法执行,会一直阻塞。要怎么办呢?
  6. 这时候就会把它添加到条件队列当中,然后释放锁,让其他线程获取资源,直到满足线程B执行操作的条件为止;
  7. 释放锁之后,唤醒了同步队列的头结点C,此时C获得了资源。它对着资源队列执行了put()操作;
  8. 此时,条件队列中的节点B将被唤醒,从条件队列转移到同步队列的队尾中去;
  9. 等线程C执行完put()操作,释放锁,然后唤醒了同步队列中的第一个节点B;
  10. 然后线程B执行take()操作。并发结束。

3、JVM调优


6、MQ–消息队列相关知识点

6.1、为什么用MQ——优点

解耦、异步、削峰

1、解耦:将消息写入消息队列中,需要消息的应用可以起队列中订阅,避免调用接口失败导致整个进程失败
在这里插入图片描述
解决办法
在这里插入图片描述

  • 订单系统:用户下单后,订单系统完成持久化处理,将消息写入消息队列,返回用户订单下单成功
  • 库存系统:订阅下单的消息,采用拉/推的方式,获取下单信息,库存系统根据下单信息,进行库存操作
  • 假如:在下单时库存系统不能正常使用。也不影响正常下单,因为下单后,订单系统写入消息队列就不再关心其他的后续操作了。实现订单系统与库存系统的应用解耦

2、异步:一些非必要的逻辑以同步方式运行太耗时间,将消息写入消息队列,以异步方式运行,加快响应速度
···
用户登陆注册:
串行方式:将注册信息写入数据库成功后,发送注册邮件,再发送注册短信。以上三个任务全部完成后,返回给客户端
并行方式:将注册信息写入数据库成功后,发送注册邮件的同时,发送注册短信。以上三个任务完成后,返回给客户端。与串行的差别是,并行的方式可以提高处理的时间
在这里插入图片描述

···
3、削峰:常用于秒杀或抢购活动中,将所有消息写入消息队列中,系统按照数据库承受能力拉去消息,避免流量过大导致系统挂掉,允许短暂高峰积压
在这里插入图片描述

6.2、MQ的缺点

1、系统可用性降低:加入消息队列后,需要考虑消息丢失或MQ挂掉情况
2、系统复杂性提高:加入消息队列后,要保证消息没有被重复消费,处理消息丢失情况,保证消息传递顺序性
3、一致性问题:对于MQ异步,如何保证消息被正确消费者消费

6.3、如何保证MQ高可用

MQ高可用

普通集群模式(无高可用性):普通集群模式,意思就是在多台机器上启动多个 RabbitMQ 实例,每个机器启动一个。你创建的 queue,只会放在一个 RabbitMQ 实例上,但是每个实例都同步 queue 的元数据(元数据可以认为是 queue 的一些配置信息,通过元数据,可以找到 queue 所在实例)。你消费的时候,实际上如果连接到了另外一个实例,那么那个实例会从 queue 所在实例上拉取数据过来。

镜像集群模式:这种模式,才是所谓的 RabbitMQ 的高可用模式。跟普通集群模式不一样的是,在镜像集群模式下,你创建的 queue,无论元数据还是 queue 里的消息都会存在于多个实例上,就是说,每个 RabbitMQ 节点都有这个 queue 的一个完整镜像,包含 queue 的全部数据的意思。然后每次你写消息到 queue 的时候,都会自动把消息同步到多个实例的 queue 上。保证任何一个机器宕机,数据都不会丢失。

Kafka 的高可用性(纯分布式):Kafka 一个最基本的架构认识:由多个 broker 组成,每个 broker 是一个节点;你创建一个 topic,这个 topic 可以划分为多个 partition,每个 partition 可以存在于不同的 broker 上,每个 partition 就放一部分数据。

这就是天然的分布式消息队列,就是说一个 topic 的数据,是分散放在多个机器上的,每个机器就放一部分数据。

Kafka 0.8 以前,是没有 HA(High Availability,高可用性) 机制的,就是任何一个 broker 宕机了,那个 broker 上的 partition 就废了,没法写也没法读,没有什么高可用性可言。在0.8以后,提供了HA机制,就是副本机制,每个partition数据会同步到其他机器上,形成多个副本,然后由多个副本推选出一个leader,生产者消费者和leader打交道,leader会将数据同步到所有其他副本上。

6.4、如何保证MQ消息不被重复消费

原因:消费者在消费消息的时候,消费完毕后就发送一个确认消息给消息队列,MQ知道消息被消费了,就会删除该消息,由于网络故障等原因,使得确认消息没有传到MQ中,不知道该消息已被消费。

解决办法:

1、拿到这条消息是insert操作,直接做一个唯一主键,就算出现重复消费,会导致主键冲突,不会产生脏数据
2、给消息分配一个全局ID,只要消费过一次,将<ID,message>以K-V写入redis中,每次消费前先去查询是否消费过该消息
6.5、如何保证消费的可靠性传输

三个角度分析:生产者弄丢数据、消息队列弄丢数据、消费者弄丢数据
RabbitMQ提供transaction机制通过回滚rollback操作

6.6、如何保证消息的顺序性?

保证生产者 – MQServer – 消费者是一对一对一的关系:一个消费者绑定一个queue,把需要保证顺序的数据,依次发送到同一个queue中。

6.7、MQ的使用场景
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值