java面试题

一:redis
    1.穿透:原因:当我们使用redis时会先从redis中查询数据是否存在,如果不存在才会去数据库中查询,
    如果数据库中也没有就会频繁访问数据库,这样下次还会继续访问数据库,这就是redis的穿透现象
            解决1:使用布隆过滤器
            解决2:从数据库中查询出来空数据时也缓存到redis中,这样也可以避免穿透现象的发生
            
    2.雪崩:原因:redis中缓存的数据在同一时间同时失效,这样用户在这一时刻大量访问时会造成大量访问数据库,这就是雪崩现象
            解决:1.尽量不要将redis的过期时间设置一样,这样缓存数据就不会再同一时刻全部失效
            解决:2.将redis的过期时间设置为永不过期
    3.redis设置持久化的两种方式:RDB和AOF
    
二:多线程
    1.多线程的好处:为了提高cpu的使用率我们引入了多线程的使用,同一时刻可以执行多个线程,同时处理业务提高cpu使用率
    2.如何实现多线程:1.集成thread类 2.实现runnable接口3.实现callable接口(实现callable接口可以有返回值)
    3.多线程的缺点 1.造成死锁,2.变量共享问题
    4.如何解决变量共享问题:使用synchronized关键字或使用lock
    5.如何解决死锁问题:1.按顺序加锁2.给锁加上时间限制,到达时间后自动释放锁(及定时锁)
    

三:springcloud
    1.Eureka(注册中心) 作用:服务提供者启动后可以将服务注册到注册中心,当消费者启动后直接去注册中心获取服务并可以通过feginClient调用接口
    2.Fegin(声明式调用)作用:我们只需要开启fegin客户端注解,我们就可以使用接口调用的方式进行各个服务之间的调用了
    3.Ribbon(本质上就是一个RestTemplet)作用:我们可以通过项目路径的方式通过RestTemplet.getForObject()方式进行服务之间的调用
    4.gatway(网关)作用:当我们使用微信服务的时候,每个微服务的端口都不一样,如果由前端去对接每一个微服务那么就会导致这个系统的混乱不利于系统之间的维护,
                          那么此时我们可以利用网关,由前端只对接网关,而具体调用那个微服务则由网关进行分发,这样就避免了,前端去对接各个微服务,导致混乱
    5.config(分布式配置中心)作用:如果每个微服务都有一个配置文件的话,配置文件过多,我们每改一个配置文件就得修改其他配置问价,还得重新部署,比较麻烦,
                                   而使用配置中心后我们就可以将配置文件推送到远程(git或者码云上),这样在我们可以直接去码云上直接读取配置文件,还可以实现热部署配置文件不用重启服务
    6.Hystrix(断路器)作用:当我们使用微服务时,各个服务之间进行调用,如果再调用某个服务时,此服务挂掉了,就会导致服务一直等待中,从而影响到整个微服务架构,为了解决这个问题,我们可以使用Hystrix组件,用来就行熔断,进而就不会影响整个微服务架构了


五:mq
    1.消息队列的作用:1.异步,2.肖锋3.解耦
    2.如何保证消息不重复消费?
        1.消息发送者在发送一条消息后发送一个唯一id,然后消费者在消费消息前先根据id去redis中查取数据,如果查到则表明此消息已经消费过了不在重复消费,否则再去消费并记录到redis中   2.也可以建一个消息记录表,消费一条记录就记录一条数据
    3.消息丢失怎么办?
        原因:1.生产者丢失数据   解决:RabbitMQ提供transaction和confirm模式来确保生产者不丢消息。
              2.队列丢失数据     解决:开启持久化磁盘配置,
              3.消费者丢失数据(是因为消费者开启了自动确认消息模式)  解决:开启手动确认消息模式


七:Dubbo

    1.dubbo是一款高性能,轻量级的java Rpc框架,它提供了三大核心能力:面向接口远程调用,负载均衡和服务注册与发现,
            它主要有三个组件provider(服务提供者),zookeeper(注册中心)以及cosumer(消费者)
    
    2.springboot整合dubbo
        1.首先我们需要在服务提供者上加入注入EnableDubboConfiguration
        2.需要在服务提供者的配置文件中配置registry(注册中心地址),当然首先需要安装zookeeper
        3.在消费端的配置文件中也配置registry(注册中心地址)
        4.在消费者的启动类上加入注解EnableDubboConfiguration
        5.如此就可以通过DubboUserCient 进行远程调用提供者提供的接口服务了
        
    
八:solr
    1.什么是solr? solr是一个全文搜索引擎
    2.solr采用了倒排索引的方式来进行查询数据,首先用户可以将文档或者数据库中的数据读取到然后通过分词器将文档进行分词,最后用户输入关键词后我们可以采用相同
    的分词器根据分好的词查询出对应的文档内容返回给用户,以前的方式就好像我们查找某个数据需要将全文从上到下全部扫描一遍,而通过倒排索引的方式就好比我们根据
    部首偏旁直接定位到某个数据,而不需要扫面整张表可以大大提高查询速度

九:shiro
    shiro是一个轻量级的安全认证框架,它主要用来做登陆的认证和权限的拦截。
    首先shiro主要由三个模块组成;subject,SecurityManager以及Realm,其中subject代表当前用户,SevurityManager用来管理所有subject,Realm用于进行权限的认证和授权需要我们
    自己实现其中的Authentication(用来做用户登陆)和Authorization方法(权限的认证)。
    springboot集成shiro时,我们先创建一个shiroConfig类,在这个类里面我们可以定义哪些接口必须登陆后才能访问,哪些接口不需要登陆就可以访问以及那些接口需要授权后才能访问
    当用户进行登录时我们直接调用SecurityUtils.getSubject().login()方法就可以直接判断用户是否已经登陆了
    
十:jvm
    1.介绍一下jvm的类加载器?
        jvm类加载器主要分为启动来加载器,扩展类加载器,应用类加载器,和自定义类加载器,
        jvm在将java文件加载到java虚拟机时会先从启动类加载其中加载文件,如果启动类加载起中没有再去扩展类加载器中加载,如果也没有再去应用类加载器中,这种形式
        也叫双亲委派模型,好处就是避免重复加载相同的类
        
    2.介绍一下jvm的内存结构?
        jvm主要分为:方法区,栈,堆,
        
        堆主要用来存放对象的,他是线程共享区域,jdk1.7以前堆分为新生代,老年代以及永久代,jdk1.8以后堆分为了新生代,老年代以及元空间
        新生代又分为Enden区以及from和to区,刚创建的对象会进入新生代的Enden区,大部分的对象就再此阶段就会被yongGc给回收掉,幸存对象会进入
        from或to区,from和to区是大小完全相等的两个区域,一个有值另一个必定没值,当对象的调用次数达到一定的阈值以后就会将对象转到老年代,当老年代的
        空间不足时就会触发fullGc来进行回收对象
        
        栈是线程私有的,他的生命周期与线程相同,先进后出。
        
    3.介绍一下垃圾回收算法?
        3.1如何确定哪些对象需要回收?
            1.引用计数法:假设有一个对象A,任何对象对A的引用,都会是引用计数器+1,当引用失败是就会-1,当值为0时,就说明此对象需要被回收了。(缺点:循环引用改的对象永远无法被回收,所以java中没有采用此方法)
            2.可达性分析算法:通过一系列的称为"GcRoot"的根对象为起始节点集,从这些节点开始向下搜索,搜索过程所走过的路径称为"引用链",当引用链断开时说明此对象可以被回收了
            
        3.2如何回收对象?
            1.标记-复制法:复制算法的核心就是讲一块区域一分为二,每次只使用其中的一块,当进行垃圾回收时将正在使用的对象复制到另一块内存空间中,
            然后清除这块空间,最后进行角色互换。新生代的from和to区就是使用的这种算法。
            
    4.垃圾收集器有哪些?
        1.并行垃圾收集器
        2.G1(jdk1.8以后才支持)
        3.ZGC(jdk11以后支持)
        


十二:设计模式(策略模式,单例模式,工厂模式,代理模式,装饰者模式,享元模式)

        代理模式+工厂模式:实际应用场景,我在做消息服务时由于我们需要对接多家消息服务商(阿里和腾讯),为了确保服务的扩展
        我首先定义了一个接口里面定义了一个发送短信的接口,然后定义了两个实现类实现此接口,然后定义了一个代理类,
        然后在配置文件中配置了key-value形式的配置文件,用来对应两个实现类的类名,然后读取此配置文件,可以根据key的值获取value
        然后再通过工厂模式即可创建对应的对象然后即可调用不同消息服务商的发送短信接口进行发送短信,使用此方法我们可以方便的进行扩展
        而不需要大量的修改源码
        
        享元模式:我们在登陆过程中需要对用户的进行加密,但是这里有个问题就是我们每次用到用的信息时,我们就得解析token获取获取用户信息
        这样不但麻烦而且会产生大量的内存开销,为了解决这个问题我们引入了享元模式,首先我们在进行用户的登陆时

十三:docker

        docker的常用命令:docker pull; docker images;docker ps;docker run;

十四:linux

        linux的常用命令: cd  tar-zxvf  ps-ef|grep  java-jar mkdir LL kill clear vim等

十五:分布式事物

    1.什么是分布式事物?  
                首先我们知道在单一架构中有事物这个概念,比如我们在一个方法中操作多张表的数据时,如果再此过程中发生异常,那么我们就需要使用事物进行回滚
                但是如果是在分布式架构中,由于我们调用了别的服务,所以我们就没办法进行回滚了,此时我们就需要引入分布式事物来进行不同服务之间的事物回滚
                
                比如当我们进行下单操作时,我们除了要向订单服务的数据库中插入数据,还需要调用营销服务扣除优惠券以及调用支付服务进行支付,此时由于我们是跨服务并且
                跨库的所以就必须要用到分布式事物了。
                          
    2.如何实现分布式事物? 
                1.XA 方案  原理:XA方案及两阶段提交,他有一个事务管理器,负责协调多个服务器,事务管理器先问问各个数据库是否ok,如果全部ok则提交事物,其中有一个
                           不ok,则回滚事物。适合单块应用里跨库的解决,不常用,因为效率比较低
                2.TCC 方案 原理:TCC 的全称是:Try、Confirm、Cancel。
                            try阶段:这个阶段是对各个服务的资源做检测以及对资源进行锁定或者预留
                            Confirm阶段:这个阶段说的是各个服务中的实际操作
                            Cancel阶段:这个阶段就是任何一个服务如果出错,则在这里进行补偿,或者说回滚了
                            
                3.最终一致性方案:原理:使用RocketMQ的最终一致性来解决
                                    1、A服务先发送个Half Message给Brock端,消息中携带 B服务 即将要+100元的信息。

                                    2、当A服务知道Half Message发送成功后,那么开始第3步执行本地事务。

                                    3、执行本地事务(会有三种情况1、执行成功。2、执行失败。3、网络等原因导致没有响应)

                                    4.1)、如果本地事务成功,那么Product像Brock服务器发送Commit,这样B服务就可以消费该message。

                                    4.2)、如果本地事务失败,那么Product像Brock服务器发送Rollback,那么就会直接删除上面这条半消息。

                                    4.3)、如果因为网络等原因迟迟没有返回失败还是成功,那么会执行RocketMQ的回调接口,来进行事务的回查。
                                    
                4.seata的AT模式和XA方案基本相同,不过他要比XA方案的效率高很多,因为AT模式在执行完本地操作后就直接提交了事务不需要进行等待被调用者
                后再进行提交事物,那么他是如何进行回滚的呢?分支事物在进行事物提交时会先保存一个快照日志,这个快照日志会记录一下修改以前的信息,
                如果事物回滚了会从这个快照日志中读取出修改前的数据进行回滚
                
                    seata原理:seata内部主要有三个组件来实现全局事务和分支事物的关系和过程,分别为:TC(事务协调器)维护全局事务的运行状态
                               负责协调全局事务的提交和回滚。TM控制全局事务的边界,负责开启一个全局事务,并最终发起全局提交或全局回滚的决议
                               RM:控制分支事物,负责分支注册,状态汇报,并接收事务协调器的指令,驱动分支事务的提交或回滚
                               


十六:分布式锁
        1.分布式锁主要是用来解决分布式服务中多台机器对同一数据的重复操作而出现的问题。
        比如集群架构中的定时任务,两台机器上有一个相同的定时任务,A机器执行过定时任务后,B机器也执行了此定时任务,这时就会产生两条数据,造成数据混乱而此时
        我们就需要引入分布式锁了
        
        2.分布式锁的实现方式:1.数据库中的分布式锁 2.redis的分布式锁 3.zookper的分布式锁
        
        我采用的是redis的分布式锁,他有一个setIfAbsent方法可以用来实现分布式锁,注意一定要设置过期时间,防止未释放锁时产生死锁
        
        


十七:介绍一下什么是事物?
    举个简单的例子,a去银行给b转钱,当a把钱转出去后,由于网络或者什么原因导致b灭有收到钱,如果没有事物进行控制的话,a的钱少了,但是b的钱却没多
    这样用户肯定不答应,为了解决这个问题所以引入了事物的概念,当a操作成功后,不管什么原因导致b没收到钱,那么就需要将a的钱给人家退回去,这就是事物。
        


十八:hashMap原理

    1.hashmap本质上就是一个数组+链表的数据结构(jdk1.8以后为了提高查询效率当长度>8时会由链接转为红黑树的数据接口)
    当我们创建一个hashmap时其实就是创建了一个数组,当我们向map中存储数据时,会先算出key的hashcode值,算出的值就是此数据在
    此数组的下标位置,如果有两个key的hashcode中相同,则会转变为链表的形式进行存储,这样就解决了hash碰撞的问题
    


十九:ssm框架

    1.简介ssm框架?  ssm及springmvc+spring+mybatis,是一个开源的轻量级的企业应用行的框架,sptringmvc用于请求的转发和试图解析,spring用于业务的处理,mybatis用于和数据进行交互
    2.spring的核心?spring的两大核心IOC(控制反转)AOP(面向切面编程)
    3.spring的注入方式有哪些?1.构造注入2.接口注入3.set注入
    4.springmvc的执行流程?
        用户发起请求---前端控制器----前端控制器----处理器映射器---处理器映射器根据用户的请求匹配相应的处理器----处理器返回ModelAndView-----前端控制器---视图解析器-------前端控制器---渲染视图----前端
    
二十:乐观锁和悲观锁?

    1.什么是乐观锁?
        乐观锁就是会在表中添加一个version字段,当一个事物要操作这个表中的数据时会先将这条数据读取出来包括version字段,
        修改过数据后将version字段+1,此时如果另一个事物才操作是也是先将数据和version字段读取出来,此时再提交时会将version字段和数据库的version作对比
        发现两个不一样,说明数据已经变了,则不在允许此次操作
    
    2.什么是悲观锁?
        悲观锁就是用户在操作数据库时会将整个表进行锁定,在此期间任何人都不能操作此表的数据,只有上个用户将事物释放的时候,其他人才可以修改这张表
        
        悲观锁有一个很大的问题就是由于只有上个事物把锁释放之后其他事物才可以继续访问,所有对于高并发来说很不友好,所以尽量不要采用悲观锁

二十一:并发包

        1.ConcurrentHashMap:线程安全的hashmap,ConcurrentHashMap会划分出多个segment来存储key-value,这样在put是就会只锁某一个segment,避免锁住整个segment,从而能减少并发时的阻塞
        2.CopyOnWriteArrayList :线程安全且在读操作时无锁的ArrayList(可能在遍历的过程中读到一些刚刚被删除的对象 增删改上锁、读不上锁)
        3.CopyOnWriteArraySet :添加不重复数据


二十二:高并发 
        1.如何解决高并发?
            1.页面静态化
            2.多线程
            3.分库分表
            4.缓存
            5.集群(负载均衡)
            

二十三: nginx
        1.nginx的作用?  1.反向代理(prox_pass) 2.负载均衡(upstream)
        2.负载均衡算法:1.轮询,2.权重,3.IP hash(可以解决session不共享问题)
        
        
二十四:jdk1.8的新特性
        1.函数式编程
        2.lamaba表达式
        3.最重要的streamApi流式编程(可以大大简化代码,)map用来处理数据,filter用来过滤数据等
        4.异步编程:CompletableFuture
        
        
二十五:mybatis和mybatisPlus的区别?

        mybatisPlus在不改变mybatis的基础上做的升级,使用mybatis时虽然很方便,可以自己编写sql,灵活度很高但是有时候一个
        简单的单表查询也需要专门写一个sql来实现,这就不免有点麻烦了,而mybatisPlus就解决了这个问题,我们如果只是对单表
        进行增删改查的操作时完全没必要去专门在Mapper中编写sql,而是可以使用mybatisPlus的自带的增删改查方法就可完成,大大
        简化了sql的编写,我的理解就是MybatisPlus就是讲hibbernate和mybatis的有点进行了整合。


二十六:mybatis的一二级缓存?

        介绍mybatis的一二级缓存:
            1.一级缓存:指的是mybatis中sqlsession对象的缓存,当我们执行查询以后,查询的结果会同时存入到SqlSession为我们提供的一块区域中,当我们再此以同样的sql
            进行查询时,他会先去sqlSession中查询是否有,有的话直接拿出来用,当sqlSession失效时,mybatis的一级缓存也会消失,当调用sqlsession的添加,修改,删除操作时
            就会清空mybatis的一级缓存
            2.二级缓存是sqlsessionFactory级别的缓存,由sqlsessionFactory创建的sqlsession都共享一个二级缓存
        

二十七:sql优化?

    1.不用select * 查询,指定列名
    2.避免使用子查询用join链接查询
    3.建索引,但是不要乱建索引,经常修改的字段不要建索引
    4.分库分表
        4.1 垂直分表:把主键和一些常用的字段放到一张表中,主键和另一些字段放到另一张表中
        4.2 水平分表:如订单表可以根据时间分成两张表,
    
    5.增加冗余列,在多张表中添加相同的列,避免联合查询
    6.增加派生列,增加的列来自其他表的计算结果,避免使用函数
    7.重新组表,将经常联合查询的表组成一张新表,减少联合查询
    5.使用EXPLEAN关键字分析sql语句

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值