技术成长之路-Java高级篇

前言

前一篇《技术成长之路-Java基础篇》我们主要对于各种公司的面试题考点关于Java基础做了一个简单总结,这一节我们讲一下更深层次的问题,依然是,我来写,诸君思考!

面试题篇

依然以面试题入手,针对问题,解决问题,然后做出总结!

阿里面试题

多线程

线程和进程的本质:

为什么出现进程?
·批处理操作系统
·A/B的顺序和阻塞执行
·进程
·线程

在这里插入图片描述

  1. 如何让多线程顺序执行
使用join()方法

T1 =New thread{
Sout(1);
});
T2 =New thread{
Sout(2);

});
T3 =New thread{
Sout(3);

});
T1.join();
T1.start();
T2.join();
T2.start();
T3.join();
T3start();
控制台输出:(永远顺序执行)
1
2
3

在这里插入图片描述
Join()方法,为什么可以让多线程顺序执行?

在这里插入图片描述
在Join()源码,使用线程锁将使用wait将当前线程阻塞,我们知道,wait为阻塞,那么什么时候notify唤醒呢?答案是,在jvm里notify

  1. wait 和 notify为什么要加线程锁
  2. sleep 和 wait的区别
  3. 线程锁的实现原理
    Synchronized:jvm实现

类锁
全局锁
对象锁
5. Synchronized原理分析
6. wait 和 notify原理分析
7. 线程生命周期
线程有多少种状态
New 初始
Runnable os调度
Blocked 阻塞
Waiting 等待
Time_waiting 超时等待
Terminated 终止
在这里插入图片描述

  1. 如何终止一个线程
    Flag()(设置一个成员变量,通过更改成员变量的变化来终止线程)
    Interrupt()返回ture/false

不建议使用stop()

  1. synchorize和lock的区别
  2. 分布式锁的实现方式
  3. Spring bean 是怎么管理的?
    单例:spring的运行周期,都不会回收
    得益于ioc,因为采用注册式的单例,始终在map中保存的实例的引用地址
    GC
    只有当ioc容器不被销毁,ioc中的单例bean就永远存在
  4. Spring中的bean是不是线程安全的?
    是不是线程安全,要看具体bean

知识点篇

RabbitMQ

  1. 消息队列的作用与使用场景?

异步:批量数据异步处理。例:批量上传文件,比如代发代扣文件。

削峰:高负载任务负载均衡。例:电商秒杀抢购。

解耦:串行任务并行化。例:退货流程解耦。

广播:基于Pub/Sub实现一对多通信。

  1. 多个消费者监听一个生产者时,消息如何分发?
    1、Round-Robin(轮询)

默认的策略,消费者轮流、平均地收到消息。

2、Fair dispatch (公平分发)

如果要实现根据消费者的处理能力来分发消息,给空闲的消费者发送更多消息,可以用basicQos(int

prefetch_count)来设置。prefetch_count的含义:当消费者有多少条消息没有响应ACK时,不再给这个消费者发送消息。

  1. 无法被路由的消息,去了哪里?
    如果没有任何设置,无法路由的消息会被直接丢弃。

无法路由的情况:Routing key不正确。

解决方案:

1、使用 mandatory=true 配合 ReturnListener,实现消息回发。

2、声明交换机时,指定备份交换机。

  1. 消息在什么时候会变成Dead Letter(死信)?
    1、消息被拒绝并且没有设置重新入队:(NACK || Reject ) && requeue == false

2、消息过期(消息或者队列的TTL设置)

3、消息堆积,并且队列达到最大长度,先入队的消息会变成DL。

可以在声明队列时,指定一个Dead Letter Exchange,来实现Dead Letter的转发。

  1. RabbitMQ如何实现延迟队列?
    利用TTL(队列的消息存活时间或消息存活时间),加上死信交换机。

当然还有一种方式就是先保存消息到数据库,用调度器扫描发送(时间不够精准)。

  1. 如何保证消息的可靠性投递?

在这里插入图片描述

  • 确保投递到服务端Broker

  • 保证正确地路由

  • 消息的持久化存储

  • 消费者应答ACK

  • 消费者回调

  • 补偿机制

  1. 消息幂等性

首先,Broker本身没有消息重复过滤的机制。

1、生产者方面,可以对每条消息生成一个msgId,以此控制消息重复投递。



//消息属性

AMQP.BasicProperties properties = new AMQP.BasicProperties.Builder()
.messageId(String.valueOf(UUID.randomUUID()))
.build();
//发送消息
channel.basicPublish("", QUEUE_NAME, properties, msg.getBytes());

2、消费者方面,消息体(比如json报文)中必须携带一个业务ID,比如银行的交易流水号,消费者可以根据业务ID去重,避免重复消费。

  1. 网关/接入层:其他限流方式。

服务端(Broker):配置文件中内存和磁盘的控制;队列长度无法实现限流。

消费端:prefetch_count。

  1. 如何保证消息的顺序性?

比如新增门店、绑定产品、激活门店这种对消息顺序要求严格的场景。

一个队列只有一个消费者的情况下才能保证顺序。

否则只能通过全局ID来实现。

1、每条消息有一个msgId,关联的消息拥有同一个parentMsgId。

2、可以在消费端实现前一条消息未消费,不处理下一条消息;也可以在生产端实现前一条消息未处理完毕,不发布下一条消息。

  1. RabbitMQ的集群模式和集群节点类型?

集群模式有两种:

普通模式:默认模式,以两个节点(rabbit01、rabbit02)为例来进行说明。对于Queue来说,消息实体只存在于其中一个节点rabbit01(或者rabbit02),rabbit01和rabbit02两个节点仅有相同的元数据,即队列的结构。当消息进入rabbit01节点的Queue后,consumer从rabbit02节点消费时,RabbitMQ会临时在rabbit01、rabbit02间进行消息传输,把A中的消息实体取出并经过B发送给consumer。所以consumer应尽量连接每一个节点,从中取消息。即对于同一个逻辑队列,要在多个节点建立物理Queue。否则无论consumer连rabbit01或rabbit02,出口总在rabbit01,会产生瓶颈。当rabbit01节点故障后,rabbit02节点无法取到rabbit01节点中还未消费的消息实体。如果做了消息持久化,那么得等rabbit01节点恢复,然后才可被消费;如果没有持久化的话,就会产生消息丢失的现象。

镜像模式:把需要的队列做成镜像队列,存在与多个节点属于RabbitMQ的HA方案。该模式解决了普通模式中的问题,其实质和普通模式不同之处在于,消息实体会主动在镜像节点间同步,而不是在客户端取数据时临时拉取。该模式带来的副作用也很明显,除了降低系统性能外,如果镜像队列数量过多,加之大量的消息进入,集群内部的网络带宽将会被这种同步通讯大大消耗掉。所以在对可靠性要求较高的场合中适用。

节点分为两种:
1)内存(RAM):保存状态到内存(但持久化的队列和消息还是会保存到磁盘)。

2)磁盘节点:保存状态到内存和磁盘。

一个集群中至少需要需要一个磁盘节点。

  1. 创建队列和交换机的方法?
    1、代码中通过 channel接口创建,channel.queueDeclare() channel.exchangeDeclare()

2、由Spring容器创建:配置文件,包括.xml和Java配置类

3、Web管理界面

4、命令行

5、HTTP API

可以重复创建相同属性的对象(交换机/队列),会直接返回成功。

属性不同会报错,所以要修改属性,只能先删除。

一般由消费者创建这些对象,遵循谁使用谁申请的原则。

生产者只需要知道交换机名称和Routing key就可以了。

  1. rpm安装方式,配置文件在哪里?
    在这里插入图片描述

点节点名称进去

在这里插入图片描述
默认是/etc/rabbitmq/rabbitmq.config

如果后面是not found,就是要自己创建。

MQ同步数据比ETL同步数据的优势在哪里?

1、实时性比ETL高,因为ETL不可能一直在跑

2、耦合性低,避免了一个应用直接去访问另一个应用的数据库,只需要约定接口字段即可。
13. SpringBoot中如何开启自动ACK?各种模式的含义是什么?
在Spring Boot工程里面开启RabbitMQ消费者消息的自动确认:\

spring.rabbitmq.listener.direct.acknowledge-mode=none 
spring.rabbitmq.listener.simple.acknowledge-mode=none

如果消费者监听类使用了自定义容器(例如vip工程里面的demo),需要设置为自动ACK RabbitConfig类里面的

SimpleRabbitListenerContainerFactory:


factory.setAcknowledgeMode(AcknowledgeMode.NONE);

NONE:自动ACK

MANUAL:手动ACK

AUTO(默认方式,在AbstractMessageListenerContainer的构造函数里面指定了):如果方法未抛出异常,则执行完毕后发送ack。如果方法抛出异常,并且不是AmqpRejectAndDontRequeueException则发送nack,并且重新入队列。如果抛出异常时AmqpRejectAndDontRequeueException则发送nack不会重新入队列。

  1. 手动ACK的情况下,prefetch默认是多少条?
    没有默认值。如果没有设置prefetch,队列默认会把所有消息都发给消费者,在消费者没有应答ACK的情况下,发了多少,就有多少Unacked。

在这里插入图片描述
如果prefetch是1,那么只要一条消息没有收到消费者的ACK,后续的消息都不会发送到这个消费者,造成消息堵塞。

在这里插入图片描述
15. SpringBoot中,bean还没有初始好,消费者就开始监听取消息了,导致空指针异常,怎么让消费者在容器启动完毕后才开始监听?

RabbitMQ中有一个auto_startup参数,可以控制是否在容器启动时就启动监听。

全局参数:

spring.rabbitmq.listener.auto-startup=true	##默认是true

自定义容器(VIP工程消费者的RabbitConfig.java),容器可以应用到消费者:

// 默认是true

factory.setAutoStartup(true);

消费者单独设置(Spring AMQP 2.0以后的版本才有):

@RabbitListener( queues = "${com.gupaoedu.thirdqueue}" ,autoStartup = "false")

另外可以参考一下动态管理监听的方法:

浅谈spring-boot-rabbitmq动态管理的方法

RabbitMQ异常监控及动态控制队列消费的解决方案

JVM

Spring FrameWork

(spring.io.com)官方api提供9大组件

  • Ioc
    Java bean
    Setter、gettter method
    Java beans(规范)
    内省
    基础核心特性(反射)
    附加特性:引用(reference)
    Reference
    Softreference
    Weakreference
    phantomreference

    Beaninfo
    Beandescreptor
    Propertydescriptor
    事件:propertychangeevent
    监听器:propertychangelistener
    Methoddescriptor
    一:Ioc
    应用不关心依赖组件的来源,通过一定di方式查找
    抄袭了javaee 概念,javaee容器(ejb容器,jsf容器)
    ejb容器
    bean模式
    Local
    容器bean
    Remote
    Rmi
    Bean类型
    会话(session bean)
    无状态bean
    有状态bean
    持久化bean(persistence bean)
    Hibernate
    消息驱动bean(java messaging bean)
    Jms
    Activemq,kafka
    二:Di(依赖注入)
    ~java ee
    jndi(java naming and directory interface)
    1 javax.naming.context
    名称
    Javax.naming.context#lookup(java.lang.string)
    Javax.naming.context#lookup(java.naming.name)
    Ejb
    1javax.ejb.@ejb
    ~依赖查找(dependency lookup)
    1 id 别名,名称查找
    BeanFactory #getbean(string):object
    2 类型查找
    Beanfactory #getbean(Class):T
    3 注解查找
    ListableBeanFactory#getBeanWithAnnotation(Class)
    4 factorybean查找
    Factorybean#getobject()
    5 objectfactory查找
    Objectfactory#getobject()
    ~依赖注入(dependency injection)
    方法
    Spring @autowired
    Java @resource
    Java ee @inject
    途径
    1 属性注入
    2 方法注入
    3 构造器注入
  • Event
    核心模式:观察者模式
    Spring事件:applicationevent
    Java.util.eventobject
    spring事件监听器:applicationlistener
    Java.util.eventlistener
    spring事件广播器:applicationeventMuliticaster
    simpleApplicationEventMuliticater

bean生命周期管理之一
事件(包装)数据变化

  • Resource
    Url资源管理
    协议
    1 获取协议:java.net.url#getProtocol
    2 协议处理
    HTTP:sun.net.www.protocol.http.handler
    FTP:sun.net.www.protocol.ftp.handler
    HTTPS:sun.net.www.protocol.https.handler
    FILE:sun.net.www.protocol.File.handler
    EMAIL:sun.net.www.protocol.Emai.handler

ClassLoader(class path)资源管理
资源
获取当前classloader资源:java.lang.classloader # getResource(String)
获取当前classloader所有资源:java.lang.classloader # getResources(String)
获取当前classloader资源inputstream:java.lang.classloader # getResourceAsStream(String)

Spring 资源管理
资源定位:classpath:/META-INF/abc.properties
多资源定位:classpath*:/META-INF/abc.properties

Resource接口
Url ,File和 classloader 封装实现
语义:
资源定位(url,File)
资源流(inputstream)
实现类:
ClasspathResource
GetURL() -> classloader #getResource(string)
Getinputstram() -> classloader #getResourceAsStream(string)
加载器
Resourceloader
获取resource:resourceloader # getResource(String)
默认实现:defaultResourceLoader
前缀= “classpath:”-》ClasspathResource
否则 -》 fileUrlResource 或 UrlResource
协议扩展
Protocolresolver
通过路径解析出resource

  • i18n
    1 Java i18n

Java标准接口 resourcebundle
<java1.6 :乱码,解决方案 native2 as cci
Java1.6: ResourceBundle.Control
Java1.8: ResourceBundleControlProvider
Java 1.6
2 spring messagesource
messageFormat
Hello,{0}-> 0 = “world” -> hello,world
实现类
ResourceBundleMessageSource

  • Validation
    Java bean validation(jsr -308)

Spring validation
Sring validator + bean validation:LocalValidatiorFactoryBean
使用场景
标准 java bean校验
Springmvc校验
form校验,@requestBody 校验,可以自定义
Spring boot外部化配置
@configurationPorperties

  • Data banding
    使用场景
    Spring 自定义绑定
    Spring mvc参数绑定
    Spring boot 外部化配置
    @configurationproperties
  • Type conversion
    常见类型转换
    自定义转换

使用场景
Spring boot 外部化配置
@configurationproperties

  • Spel
  • Aop

NIO、BIO、AIO

HashMap底层

并发编程

300行SpringMVC框架

分布式任务调度

漫谈技术架构、技术选型

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值