首页 / 面试 / 实战得来的java面试知识经验总结
实战得来的java面试知识经验总结
内容导读
互联网集市收集整理的这篇技术教程文章主要介绍了实战得来的java面试知识经验总结,小编现在分享给大家,供广大互联网技能从业者学习和参考。文章包含35192字,纯文字阅读大概需要51分钟。
内容图文
前言
重点动手做,永远是学习的最好的方式!
文章目录
- 前言
- 1.mysql左右连接和内连接的关键字是什么
- 2.聚合函数有哪些
- 3.ArrayList 和 LinkedList 的区别
- 4. ArrayList的扩容机制
- 5. ArrayList线程安全吗
- 6.线程的创建方式
- 7.线程的5种状态
- 8.线程池中的哪些参数
- 9.线程池的拒绝策略
- 10.线程池的执行流程
- 11.单例模式一般是怎么实现的
- 12.你项目里的数据都是从哪里来的,怎么获取的。
- 13.你在项目里还有个推荐这一功能,你是怎么实现的?
- 14.接口和抽象类的区别
- 15.面对对象的3个特征
- 16.面向对象(OOP)的五个原则:
- 17.Java8 对接口的改变
- 18.重载和重写的区别
- 19.JVM的内存结构
- 19.1类加载的5个过程:
- 20.JVM中的类的加载器主要有三种:
- 21.强引用,软引用和弱引用的区别
- 22.垃圾收集算法:
- 23.正向代理和反向代理的区别
- 24.nginx负载均衡策略
- 25.如何防止 SQL 注入攻击呢?,
- 26.事务的4种隔离级别、四大特性和并发问题
- 27..drop,delete与truncate的区别
- 28.MySQL数据库优化的方式
- 29.索引底层的数据结构是什么
- 30.静态变量和实例变量的区别
- 31.Spring Bean的生命周期总共分为4个阶段,接口方法有哪些?
- 32.常用日志框架
- 33.Object类有哪些方法
- 34.一条SQL的执行过程
- 35.springBoot和SpringMVC的区别
- 36.元空间和永久代的区别
- 37.你spring cloud注册中心用的是什么?做过集群吗?
- 38.说下你对eureka的理解
- 39.分布式事物是如何去处理的
- 40.熔断和降级
- 41.redis是主要用来做什么的呢!
- 42.缓存是怎么去保证缓存与数据库的双写一致性
- 43.这么保证缓存里面都是热点数据
- 44.缓存雪崩或者缓存穿透的问题怎么解决的
- 45.你得消息中间件主要是用在什么地方
- 46.怎么实现接口幂等性
- 47.你经常用到的哪些设计模式
- 48.悲观锁与乐观锁
- 49.synchronized-重量级锁
- 50.编程式事务和声明式事务的区别
- 51Nginx 的健康监测机制
- 52数据库压力大时,怎么实现高可用
- 53 数据库数据如何备份(数据备份策略)
- 54数据库的优化策略
- 55.什么是redeis
- 56.几种加密算法
- 57.懒汉式和饿汉式区别
- 58.依赖注入的方式
- 59.什么是redis
- 60.zookeeper怎么实现分布式锁
- 61.springboot有什么好处
- 62.经常用到的注解有哪些
- 63.参数接收注解
- 64.springboot自动配置:
- 65.mybtis里面的一级缓存和二级缓存
- 66.熔断器的默认触发阈值是20次请求,休眠时间默认是5秒,默认50%的触发熔断
- 67.session机制(客户端和服务端运行在同一台服务器上,协议、域名、端口号一样)
- 68.token机制(前后端分离)
- 69.redis的持久化机制(RDB持久化机制,AOF持久化机制)
- 70. hashCode()方法和equal()方法的区别
- 71.java栈内存溢出的原因
- 72.锁的实现原理
- 73.synchronize锁升级过程
- 74.10亿个怎么去重,怎么找出最大的10个
- 75.怎么去重
- 76.一致性hash算法
- 77.为什么要用线程池
- 78.java中线程池的实现原理
- 79.MyBatis中#{}和${}的区别
- 80.springboot 和spring springmvc有什么区别
- 81.Synchronized关键字加在方法上和加在静态代码块上有什么区别?
1.mysql左右连接和内连接的关键字是什么
内连接查询 关键字:inner join on
左连接查询 关键字:left join on / left outer join on
右连接 关键字:right join on / right outer join on
2.聚合函数有哪些
聚合函数(常用于GROUP BY从句的SELECT查询中)
AVG(col)返回指定列的平均值
COUNT(col)返回指定列中非NULL值的个数
MIN(col)返回指定列的最小值3+
MAX(col)返回指定列的最大值
SUM(col)返回指定列的所有值之和 300541
GROUP_CONCAT(col) 返回由属于一组的列值连接组合而成的结果
3.ArrayList 和 LinkedList 的区别
首先 ArrayList的底层是数组,是一块连接的空间,所以他查询快,但是删除,插入慢!
LinkedList 的底层是链表 不是一块连接的空间,所以他删除,插入快,但是查询慢
这个说法可以说对,也可以说不对, 如果元素量少的话,这个说话没问题,但是元素数量多
的话,ArrayList效率更快些,他可以通过索引直接操作,LinkedList还得一个一个来。
4. ArrayList的扩容机制
ArrayList在新增的时候会判断一下新增加的元素会不会超过ArrayList原本的容量
如果超过的话就调用grow方法,将容量扩大1.5倍,在调用System.arraycopy方法将
原数组复制到新数组里面。
5. ArrayList线程安全吗
ArrayList线程不是安全的,ArrayList是通过Collections.synchronzedList方法,
没有使用到synchronized关键字。
6.线程的创建方式
第一种为继承Thread类;
第二种为实现Runnable接口,创建线程时必须创建Thread类的实例,
第三种为实现Callable接口
线程启动用start()方法;
7.线程的5种状态
1.就绪 2.待运行 3.运行 4.阻塞 5.终止
8.线程池中的哪些参数
7个参数
corePollSize:核心线程数
maximumPoolSize:最大线程数
keepAliveTime:空闲的线程保留的时间。
TimeUnit:空闲线程的保留时间单位。
BlockingQueue<Runnable>:阻塞队列,存储等待执行的任务
ThreadFactory:线程工厂,用来创建线程
Handler:线程池的拒绝策略。
9.线程池的拒绝策略
4种
1.Abort(阿波t) 策略 JDK4种策略中默认的策略,这个策略触发的时候会抛出异常。
2.CallerRuns(扩累runs)策略 就是直接运行任务。
3.Discard(DSK)策略 直接丢掉这个任务
4.DiscardOldest(DSKO得思)策略 就是丢弃任务队列中的第一个任务,然后将新任务添加进去
10.线程池的执行流程
任务提交给线程池中,先判断核心线程池有没有满,如果满的话就递交到任务队列中,
如果任务队列满的话,就判断最大线程池有没有满,如果没满的话就新建线程执行,
如果最大线程池也满的话,就执行线程池的拒绝策略
11.单例模式一般是怎么实现的
一般写双重检查锁的模式,配合关键字volatile进行实现
12.你项目里的数据都是从哪里来的,怎么获取的。
从一些网站上面爬下来的,是对webmagic框架来进行二次开发网页爬取的
过程就是先分析网页上的数据,如果是静态的话,就直接用xpath表达式定位到我想要的数据
然后直接爬下来,如果是动态数据的话,就用谷歌的网页分析工具分析他的接口,然后对接口里的
内容再进行二次开发,最后把数据保存到数据库里面
13.你在项目里还有个推荐这一功能,你是怎么实现的?
用百度地图的API,然后实现这个周边的推荐
14.接口和抽象类的区别
抽象类的关键字是abstract,接口的关键字是interface。
接口和抽象类都不能被实例化
接口里都是抽象方法,抽象类里不止抽象方法还有普遍方法
接口不能有构造器,抽象可以有
抽象类只有单继承,接口就可以实现多继承。
15.面对对象的3个特征
封装,继承,多态
16.面向对象(OOP)的五个原则:
单一职责原则(SRP)、
开放封闭原则(OCP)、
里氏替换原则(LSP)、
依赖倒置原则(DIP)、
口隔离原则(ISP)。
17.Java8 对接口的改变
1.增加了default方法和static方法,这两种方法完全可以有方法体
2.default方法属于实例,static方法属于接口
3.接口中的静态方法不会被继承,接口中的静态变量会被继承
18.重载和重写的区别
重载是发生在一个类里,方法名相同,方法参数不同,
重写的前提是必须存在继承关系,子类中将父类的成员方法的名称保留,重写成员方法的内容。
19.JVM的内存结构
按线程来讲可以分为2个部分,一个是线程独占,一个是线程共享
线程共享的有方法区,堆。线程独占的话有 2个栈,本地方法栈和虚拟机栈,程序计数器。
19.1类加载的5个过程:
加载、验证、准备、解析、初始化
20.JVM中的类的加载器主要有三种:
启动类加载器:又称为引导类加载器,由C++编写,无法通过程序得到,主要负责加载JAVA中的一些核心类库
拓展类加载器:主要加载JAVA中的一些拓展类,是启动类加载器的子类
应用类加载器:又称为系统类加载器,主要用于加载CLASSPATH路径下的类,是拓展类加载器的子类
21.强引用,软引用和弱引用的区别
强引用:当内存空间不足时,强引用的对象不管怎么样都不会被回收
软引用:当内存空间不足的时候,软引用的对象就会被垃圾回收器回收掉。软引用可用来实现内存敏感的高速缓存。
弱引用:就是弱引用的对象一旦被垃圾回收器扫描到,不管内存空间足不足,都会回收掉
22.垃圾收集算法:
1.标记-清除(Mark-Sweep)算法:标记出所有需要被回收的对象,清除就是回收被标记的对象所占用的空间,有一个缺点他会产生碎片
2.复制(Copying)算法:将可用内存按容量划分为大小相等的两块,每次只使用其中的一块
当这一块的内存用完了,就将还存活着的对象复制到另外一块上面,然后再把已使用的内存空间一次清理掉
3.标记-整理(Mark-Compact)算法:这个算法和标记-清除算法一样,但是在完成标记之后,它不是直接清理可回收对象,
而是将存活对象都向一端移动,然后清理掉端边界以外的内存
4.分代收集(Generational Collection)算法:分代收集算法是目前大部分JVM的垃圾收集器采用的算法,
它的核心思想是根据对象存活的生命周期将内存划分为若干个不同的区域。
23.正向代理和反向代理的区别
正向代理就是我们平常使用的那种代理软件的效果,我们将自己的请求发给代理服务器,
然后再由代理服务器发送给目标服务器;
反向代理,顾名思义,方向相反,当代理服务器收到请求后,依照某种规则,转发给不同的服务器。
24.nginx负载均衡策略
5种
1、轮询(默认):每个请求按时间顺序逐一分配到不同的后端服务器,如果后端服务器down掉,能自动剔除。
2、权重:指定轮询几率,weight和访问比率成正比,用于后端服务器性能不均的情况。
3.IP绑定 ip_hash:每个请求按访问ip的hash结果分配,这样每个访客固定访问一个后端服务器,可以解决session的问题。
4、fair(第三方):按后端服务器的响应时间来分配请求,响应时间短的优先分配。
5、url_hash(第三方):按访问url的hash结果来分配请求,使每个url定向到同一个后端服务器,后端服务器为缓存时比较有效。
25.如何防止 SQL 注入攻击呢?,
(1)对用户的输入进行校验.
(2) 永远不要使用动态拼装 SQL.
(3) 永远不要使用管理员权限的连接数据库。
(4) 不要把机密信息明文存放,请加密或者 hash 掉密码和敏感的信息。
(5) 应用的异常信息应该给出尽可能少的提示。
26.事务的4种隔离级别、四大特性和并发问题
隔离级别:
1.序列化(Serializable):级别最高,一个事务的所有子事务全部执行完之后其他事务才能执行
2.可重复读(Repeatable read):读取了一条数据,这个事务不结束,别的事务就不可以改这条记录
3.读已提交(Read committed)(最常用):能够读到那些已经提交的数据
4.读未提交(Read uncommitted):能够读取到没有被提交的数据(无法解决任何问题)
四大特性:1.原子性 2.隔离性 3.一致性 4.持久性
并发问题:脏读 幻读 不可重复读(把事务隔离级别调整)
27…drop,delete与truncate的区别
drop直接删掉表 truncate删除表中数据,再插入时自增长id又从1开始 delete删除表中数据,可以加where字句。
28.MySQL数据库优化的方式
1.尽可能根据主键查询,尽可能少用关联查询.
2.创建索引
3.添加缓存
4.定期进行数据转储
5. 分库分表
29.索引底层的数据结构是什么
B+树
30.静态变量和实例变量的区别
在语法定义上的区别:静态变量前要加static关键字,而实例变量前则不加。
在程序运行时的区别:
实例变量属于某个对象的属性,必须创建了实例对象,才能使用这个实例变量。
静态变量不属于某个实例对象,而是属于类,不用创建任何实例对象,静态变量就可以被使用了
31.Spring Bean的生命周期总共分为4个阶段,接口方法有哪些?
一阶段:Bean的实例化和DI(dependency injection)
二阶段:检查Spring Awareness
三阶段:创建bean生命周期回调
四阶段:销毁bean生命周期回调
BeanFactoryAware接口方法
BeanNameAware接口方法
DiposibleBean接口方法
InitializingBean接口方法
32.常用日志框架
最常用的是 SLF4J,即简单日志门面(Simple Logging Facade for Java)
1.Log4j
2.Logback
3.Log4j2
33.Object类有哪些方法
1.clone方法:保护方法,实现对象的浅复制
2.getClass方法:final方法,获得运行时类型。
3.toString方法:该方法用得比较多,一般子类都有覆盖。
4.finalize方法:该方法用于释放资源,很少使用。
5.equals方法:该方法是非常重要的一个方法。一般equals和==是不一样的,但是在Object中两者是一样的。子类一般都要重写这个方法。
6.hashCode方法:该方法用于哈希查找,重写了equals方法一般都要重写hashCode方法。
7.wait方法:wait方法就是使当前线程等待该对象的锁,当前线程必须是该对象的拥有者,也就是具有该对象的锁。
8.notify方法:该方法唤醒在该对象上等待的某个线程。
9.notifyAll方法:该方法唤醒在该对象上等待的所有线程。
34.一条SQL的执行过程
1、连接:sql客户端与服务器建立连接
2、查询缓存:如果有缓存的话就直接返回结果,没有的话则进入下一步
3、语法解析器和预处理:对SQL语句进行内部解析,看有没有什么问题,检查语句是否合法
4、查询优化器:选择一种合适的执行计划
5、执行SQL
35.springBoot和SpringMVC的区别
1、springMVC是Spring的一个模式,是一个Web框架,提供了一个轻度耦合的方式来开发Web应用;
2、SpringBoot是习惯优于配置,降低了项目搭建的难度;
3、springMVC需要使用到TomCat服务器,SpringBoot的话是内嵌了Tomcat服务器的;
Spring 是一个“引擎”;
Spring MVC 是基于Spring的一个 MVC 框架 ;
Spring Boot 是基于Spring4的条件注册的一套快速开发整合包。
36.元空间和永久代的区别
元空间使用本地内存,永久代使用JVM的内存
在过去类大多是静态的,很少会被卸载和收集,他们就被称为“永久的”,
而存放这些“永久的”区域就叫永久代!jdk8之后就没有了
元空间是因为这里面存储的是类的元数据信息。
元数据(Meta Date),关于数据的数据或者叫做用来描述数据的数据或者叫做信息的信息。
37.你spring cloud注册中心用的是什么?做过集群吗?
spring cloud注册中心用的是eureka。
做过集群啊,因为这个中心如果是单点的话,他会存在那个单点故障嘛!他挂掉的话整个
微服务系统都会用不了。我之前做过双节点互相注册的方法来解决这个单点故障嘛,实现高可用这种状态嘛!
38.说下你对eureka的理解
eureka是springcloud的微服务体系的注册中心嘛,主要起到的作用是服务注册,发现,
一些服务的健康检查等,他里边主要有俩种组件,一种是服务端,一个是客服端。
其他的微服务都会用到eureka的客服端注册到eurrka的服务,由eureka servce维持连接
eueeka有三种角色组成,一个是eureka的服务中心,一个是服务的消费者和服务的提供者
eueeka-server他是一个独立的部署单元,他用rest API的形式为这个服务实例提供注册,管理查询等一些操作。
39.分布式事物是如何去处理的
分布式事物是一个比较复杂的也是一个比较棘手的问题吧,先说分布式事物之前呢我想说一下
我们普通的事物,我们普通的事物都是有一组操作,组成一个工作单元。这个工作单元呢要么全部执行成功,
要么就是失败以后全部进行回滚操作,举个列子,就比如说我们经常用到的电商平台的下单操作,
下单的时候我们要创建订单和扣除或者是锁定这个库存,这俩个操作呢要么就是全部成功,要么就是全部失败,
失败过几天回滚,这个就是普通的事物。在说下这个分布式事物啊,就拿刚刚那个订单的例子啊,
在分布式系统里边呢,可能这个创建订单的操作,在那个订单的微服务中,然后库存的操作呢,在那个库存的微服务中
就是这个操作呢是由多个系统或者是服务来协同完成的,就是一次事务操作呢涉及多个系统,他是通过网络协同完成的过程,
我们举的这个例子呢就是说一个分布式我们可以看做是多个分布式子事务来组成的!
关于分布式系统呢,他有这个cap和base俩个经典的理论。cap呢就是指一致性,可用性和分区容错性,这三个单词首字母缩写
一个分布式不可能同事满足这三个基本要求,所以最多只能满足其中的俩项。这个就是cap
base呢就是在cap的基础上逐步演化过来的,是基本可用,软状态和最终一致性这三个组成的,
base他的核心思想呢就是无法做到强一致性,但是呢每个应用都可以根据自身的业务特点采用适当方式来达到这个最终的一致性
分布式事物呢我们之前采用的是bytetcc这么一个开源的分布式事务框架。他的主要思想呢就是tcc,就是try confirm cancel这三个字的缩写
就是从在调用接口实现一组业务操作的时候呢,不是说直接完成那个业务操作,而是先完成try的操作,这个操作一般是去锁定某个资源或者是
设定一个预备的状态,是冻结还是冻结一部分数据 的一个中间状态吧,大概就是这个类型的操作吧。
然后这个try完成以后就会分俩种情况,第一种就是比较理想的情况下,就是所有的微服务执行自己的try操作都能执行成功,这个时候呢这个分布式框架他就会
继续推动我后续的执行。还有一种如果出现了异常,执行的时候报错了,这个事物框架他就能感知到!然后他就对整个tcc分布式事务进行回滚
这就是我对分布式还有我们之前分布式事务的一个处理!
CAP理论的话,本人的体会就是订单系统,对于订单系统来说,用户端的一致性需要保证强一致性,
但是对于后台或者商家来说的话,这个订单的状态只要保证最终一致性就行,时间差值在可接受范围内就OK。
40.熔断和降级
熔断:就是在这个分布式这个微服务这种架构呢,通常来说一组操作呢,会有多个微服务进行协同来完成,他会形成一个调用链
这个调用连呢,如果说处于下游的一些服务因为种种问题造成的这个响应时间较长或者是超时,或者说不可用。
那么上游服务为了保证自己整体的可用性和稳定性,就不再继续调用目标服务,直接返回,快速释放资源。如果目标服务情况好转则接着调用。
降级:有分为2种场景,一种是当下游的服务因为某种原因响应过慢时,下游服务会主动的停掉一些不太重要的业务,释放出服务器资源,增加响应速度
另一种呢,就是当下游的服务不可用的时候,上游主动调用本地的一些降级逻辑,避免卡顿,迅速的返回给用户。
41.redis是主要用来做什么的呢!
redis是我们主要用来做缓存,缓存一些就是说不经常改变的一些热点数据,
用来提高常用接口的访问效率。
42.缓存是怎么去保证缓存与数据库的双写一致性
在数据库更新的时候,采用的一个双删的策略
就是在执行数据库操作的时候先删除一遍缓存,然后再写数据库,
在过一段时间再去删一遍缓存,目的就是避免一个场景,就是比如说我们有一个请求
去执行写操作,在这个操作之前先删了缓存,这个时候呢又有一个请求去查询,他会先查缓存,
而且查的这个数据呢不存在,如果不存在的时候,他就会去数据库查询,但是呢我之前的那个操作还没有完成
这边查询到的那个数据呢肯定是原来的那个旧数据,这个时候呢第二个请求就会把原来的那个旧值写入到
缓存里边,第一个写的请求呢会更新数据库里边的数据,这个时候就会出现脏数据的这么个情况!
43.这么保证缓存里面都是热点数据
关于热点数据这一块,我们就说在查询的时候吧,就是每查询一次,redis就会命中一次,然后给热点数据
增加一段过期时间。如果说是被频繁查询的数据呢,他的过期时间肯定会变得比较长,他就不会在初始化的过期时间
里失效嘛,如果说就是被经常查询的老数据呢,他的那个初始化就是设定的那个过期时间就会失效,淘汰。
他的那个数据就被会保存下来。就相当于你主动去刷新了他的过期时间。
44.缓存雪崩或者缓存穿透的问题怎么解决的
缓存雪崩:就是缓存在同一时间大面积的失效了,所有的请求都落到数据库上,数据库处理不了就会崩掉。
缓存穿透:就是请求缓存中不存在的数据,导致所有的请求都落到数据库上,数据库处理不了就会崩掉。
如果说redis是单级缓存,再搭建一个集群,避免单机故障,保证redis服务的高可用。
另一个呢,就是我们通过加锁或者队列控制读数据库写缓存的线程数量,比如说一个key允许一个线程操作,
其他线程去等待。还有就是通过缓存机制先去跟新缓存,在即将发生大并发访问之前的手动触发
加载缓存,设置不同的过期时间,如这个缓存失效的时间呢尽量的均匀一些,不要集中到一个时间点去实现
这个就是缓存雪崩的处理
如果是低频的话,就把数据库中查询的数据,缓存到redis里,如果是高频的话就设置过滤器!
而缓存穿透的呢,主要是采用布隆过滤,就是讲可能查询的数据以hash的形式去存储,在控制层先进行校验,
不符合的呢则丢弃避免对数据库这个查询压力过大。还有一个呢就是缓存一个空对象,我们在数据库里边
也查不到的时候及时返回一个空对象,在redis中缓存起来同时也会设置一个过期时间,以后在访问这个数据的
时候就直接从缓存中获取就不会再去给数据库造成压力了。
45.你得消息中间件主要是用在什么地方
他有可能是针对一些企业的注册啊或者用户注册啊用的比较多。就是说注册完以后还需要发邮件短信通知
那就是说注册流程走完之后呢,先往消息中间件里边发送消息,然后后续的邮件啊短信啊都是来订阅这个消息。
46.怎么实现接口幂等性
接口幂等性就是用户同一个操作呢他发起了多次请求或者重复请求的这种情况呢,他的结果要求必须一致性的
我们就是做这个接口幂等性,举个列子就是说我们在电商平台,用户购买商品以后他去支付,支付成功在返回
支付结果的时候,因为网络抖动出现了一些异常。这个时候呢钱已经扣了,如果用户再去点击按钮的话会进行二次扣款
如果再付款成功的话就会出问题了!这就是没有实现幂等性!
如果要实现幂等性的话,可以通过代码逻辑来判断实现,就是通过订单的ID来标定订单的唯一,付款的时候要检测
这个id的订单是不是已经支付过了,那第二次在调用的时候,他就不会再扣款直接返回成功的结果。
还有一个就是可以通过 Token 的机制实现防止重复提交。
47.你经常用到的哪些设计模式
其实设计模式用的也比较多,最常用的是MVC设计模式啊
还有一些就是比如说工厂模式啊,单例模式啊,代理模式啊还有一些方法模式等
我就简单说下这个MVC设计模式,MVC设计模式就是由模型(Model),视图(view)和控制层(Controller)组成的一个模式
首先,用户通过游览器发送请求到控制层模块中,也就是服务器中,然后服务器通过分析请求,判断客户的需求
调用Model模型,处理数据库的增删改查,返回结果给视图,然后视图把返回来的结果进行渲染到页面中响应给浏览器
浏览器在返回动态的内容给用户。
代理模式呢就是给一个对象提供一个代理,由这个代理对象就是控制原对象的引用,然后代理模式是能协调这个调用者和被调用者
他在一定程度上降低了系统的耦合度
48.悲观锁与乐观锁
悲观锁:你就是每次拿数据的时候总是担心别人会修改,所以每次拿数据的时候都会上锁,这样别人想拿这个数据就会阻塞,直到你
不再使用了,他才能拿到数据。就像共享资源每次只给一个线程使用,其他线程阻塞,用完后再把资源转让给别的其他线程。
一般多用于写的操作。
Java中synchronized和ReentrantLock等独占锁就是悲观锁思想的实现
乐观锁:就跟悲观锁相反,每次拿数据的时候总是认为别人不会修改,所以不会上锁,但是在更新的时候会先判断一下有没有人
去更新了你这个数据有没有被修改。乐观锁一般多用于读的应用类型,这样可以提高吞吐量,
可以使用版本号机制和CAS算法实现。还有数据库里的condition机制也是乐观锁的实现。
49.synchronized-重量级锁
我记得synchronized,很久之前很多人都称他为“重量级锁”,Java1.6以后引入了其他的锁,
偏向锁和轻量级锁,主要是为了减少锁和释放锁带来的性能消耗。
ynchronized的底层实现主要依靠 Lock-Free 的队列,基本思路是 自旋后阻塞,竞争切换后继续竞争锁,
稍微牺牲了公平性,但获得了高吞吐量。在线程冲突较少的情况下,可以获得和CAS类似的性能;
而线程冲突严重的情况下,性能远高于CAS
CAS算法即即compare and swap(比较与交换),是一种有名的无锁算法,CAS算法涉及到三个操作数
需要读写的内存值 V 进行比较的值 A 拟写入的新值 B
当且仅当 V 的值等于 A时,CAS通过原子方式用新值B来更新V的值,否则不会执行任何操作,一般情况下是一个自旋操作,即不断的重试。
50.编程式事务和声明式事务的区别
编程式事务指的是在代码里面显式的开启事务,并关闭事务。这种做法控制粒度更细,但是对代码的侵入性更大。
声明式事务是通过注解或者xml的形式,通过aop的方式,为我们的逻辑层加上事务。
51Nginx 的健康监测机制
当后台的服务器出现宕机的现象,当时 nginx 中的配置文件并没有改变时,请求依然会
发往故障的机器.需要人为的维护配置文件,这样的操作不智能.那么采用健康检测机制.可以
实现故障的自动的迁移.
52数据库压力大时,怎么实现高可用
1.用数据库代理服务器搭建数据库的读写分离进行分流.读取从库数据,写数据在主库
可用的数据库代理服务器有 Amoeba 和 Mycat
由于大量的用户的数据库操作都需要通过数据库来完成.造成数据库负载过高.因为数
据库操作中查询的操作占很大的比重.
2.数据库实现双机热备.
53 数据库数据如何备份(数据备份策略)
1. 冷备份:定期将数据库中的文件进行数据备份.
2. 热备份:搭建数据库主从结构,当主库数据发生改变时,从库根据主库的日志进行备份.
3. 双机热备:数据库互为主从,数据库代理服务器对主库进行心跳检测,实现数据的高
可用,为了防止主库宕机后发生雪崩现象
54数据库的优化策略
1.尽可能根据主键查询,尽可能少用关联查询.
2.创建索引
3.添加缓存
4.定期进行数据转储
5. 分库分表
55.什么是redeis
开源的数据存储系统,可以用做数据库,缓存和消息中间件。
56.几种加密算法
1.AES 2.RSA 3.CRC 4.MD5
57.懒汉式和饿汉式区别
懒汉式是当程序第一次访问单例模式实例时才进行创建(延迟加载),就是等你调用的时候才创建。
饿汉式是典型的空间换时间,当类装载的时候就会创建类实例,不管你用不用,先创建出来,
然后每次调用的时候,就不需要判断了,节省了运行时间。
58.依赖注入的方式
构造器注入:通过将@Autowired注解放在构造器上来完成构造器注入,默认构造器参数通过类型自动装配
接口注入:通过将@Autowired注解放在构造器上来完成接口注入。
方法参数注入:通过将@Autowired注解放在方法上来完成方法参数注入。
59.什么是redis
redis是一个开源的,遵守BSD协议的,一个高效的KEY-VALUE数据库
60.zookeeper怎么实现分布式锁
分布式锁他的原理很简单啊,就是多个进程或者多个服务去访问同一个数据,去访问的时候
就是说我在访问的时候或者操作的时候加上锁,另一个就不能操作,只能等我操作完了才能查。
就是说多个访问的时候都会在zookeeper上面产生节点,然后基于zookeeper的选举机制,谁先拿到
数据,他就用锁,后面的就只能等他操作完
61.springboot有什么好处
对主流开发框架的无配置集成
独立运行的Spring项目
SpringBoot帮助开发者快速启动一个Web容器
SpringBoot继承了原有Spring框架的优秀基因
SpringBoot简化了使用Spring的过程
降低耦合,简化开发
62.经常用到的注解有哪些
@Bean:bean对象交给spring管理
@Autowired:自动为属性注入一个值
@EnableZuulServer:过滤器
@EnableEurekaclient:表示开启eureka客服端
@EnableEurekaserver::开启Eureka注册中心服务端
@EnableHystrix:开启熔断降级服务
63.参数接收注解
@RequestBody
@RequestHeader
@PathVariable(支持一个属性value,类型是为String)
@CookieValue
@Validated
64.springboot自动配置:
在主启动类上有个注解@springbootApplication,你按住ctrl鼠标左键点击他,他里面有一大堆的
注解,其中有一个注解叫@EnableAutoconfiguration,这个注解就是开启自动配置的意思,你在
点击他 他里面有个@Imput,他里面有很多关键功能,他其中有一个就是扫描META-INF文件下的jar包
总结:springboot通过根据配置文件自动装配所属依赖的类,再用动态代理的方式注入到spring容器里面
65.mybtis里面的一级缓存和二级缓存
我的理解是一级缓存是属于对象的,就是sqlsession级别的缓存,操作数据库时需要构造sqlsession对象
在这个对象里有一个数据结构(hashMap)用来存储数据,不同的对象之间缓存的数据时不共享的。
(只需要在mybatis的配置文件中开启二级缓存,并且在mapper.xml里面打上cache标签就可以了)
我没用过mybtis的二级缓存,我觉得mybtis的二级缓存比较鸡肋,如果你用mybtis的话他本身就没有
一级缓存那么友好,他里面会有一个级联的那种感觉。所以我没有用到mybtis的二级缓存,我用的是
redis来做这个缓存。
redis缓存和其他缓存的区别
redis实现缓存,他有个名字叫中央缓存。简单来说如果我们做集群的一个项目中同一个服务部被部署多份
比如说如果我用传统的map来存或者mybatis框架自带的缓存啊,他仅仅缓存在本节点的。缓存在本节点以后
下次别人访问另外的节点呢,他是没有缓存的。所以啊我们要把这些缓存缓存到一个公共的地方,最终缓存都是
放在redis里面去。中央缓存,就体现在集中管理缓存,而不是各自的节点进行管理的一个效果,相当于这个缓存
不再依赖JVM了
66.熔断器的默认触发阈值是20次请求,休眠时间默认是5秒,默认50%的触发熔断
67.session机制(客户端和服务端运行在同一台服务器上,协议、域名、端口号一样)
用户在访问服务端的时候会在session对象中存储键值对,“键”用来存储开启这个用户信息的
“钥匙”,在登录成功后,“钥匙”通过cookie返回给客户端,客户端会记录在cookie中。
当客户端再次访问时,会默认携带cookie来实现会话机制
68.token机制(前后端分离)
客户端通过cookie都可以进行存储。再次请求时不会默认携带,需要在请求拦截器位置给请求头中添加认证字段
携带token信息,服务器就可以通过token信息查找用户登录状态。
69.redis的持久化机制(RDB持久化机制,AOF持久化机制)
AOF是存储的指令文件,每一个在redis中执行的命令都会被记录下来,
RDB是一个数据文件,有需要可以直接加载到内存中快速恢复
RDB的恢复速度要高于AOF,恢复数据的完整性来说,AOF要大于RDB。
但是,AOF有可能会丢弃数据,因为在LINUX中的操作并不是直接写到aof文件中,而是
先写到cache中,然后每隔1秒做一个强制刷新动作,就是出现问题了也只会
丢失1秒的数据,建议每次定时备份到其他磁盘
70. hashCode()方法和equal()方法的区别
都是用来对比俩个对象是否相等一致。
一般来说equal比较的 比较全面比较复杂,这样效率就比较低。
而hashcode进行对比,则只是生成一个hash值进行比较就可以了。
equal()相等的两个对象他们的hashCode()肯定相等。
hashCode()相等的两个对象他们的equal()不一定相等,也就是hashCode()不是绝对可靠的。
当需要进行对比的时候你先用hashcode,如果他们的hashcode都不相等,则不需要equal去对比了
当他们的hashcode都相等,你在用equal去进行对比就好了。
这样既能提高了效率也保证了对比的绝对正确性!
71.java栈内存溢出的原因
栈生命周期与线程相同执行的时候会创建一个栈帧,用来存储各种信息,栈溢出就是
方法执行时创建的栈帧超过了栈的深度,一般就是递归调用可能会导致。
解决方案:一般就是调整jvm栈的大小就可以了,一般递归的时候注意下
72.锁的实现原理
lock和synchronize
synchronize用于方法和代码块可以锁对象和类以及方法
lock一般锁某一块代码,并且可以搭配condition使用
synchronize的底层使用互市锁,需要系统调用。
lock的底层使用AQS实现
73.synchronize锁升级过程
偏向锁到轻量级锁在到重量级锁
74.10亿个怎么去重,怎么找出最大的10个
用hash分片,用hash分片可能不均匀,可以用bitmap
用小顶推就可以,量大的话可以做分片或堆排序再进行归并
75.怎么去重
就拿我经常用的AaarysList来说吧,我先遍历一遍,在用高效for循环赋值
给另一个list集合,在用contains()方法去判断是否有相同的元素。
然后在用add()方法给第二个集合就好了。
76.一致性hash算法
我记得他是分到一个16384的槽这样的,一个2的16次方。
77.为什么要用线程池
因为线程池主要是通过重复利用已经创建的线程减少线程创建和销毁造成
的消耗,从而提高响应速度。
78.java中线程池的实现原理
一个新任务提交后,先判断核心线程池有没有满,如果满了的话就提交到
任务队列中,如果任务队列也满了的话,就看最大线程池有没有满,如果没满
就新建线程执行,如果最大线程池满了的话就执行线程的拒绝策略。
79.MyBatis中#{}和${}的区别
1、在MyBatis 的映射配置文件中,动态传递参数有两种方式:
(1)#{} 占位符
(2)${} 拼接符
2、#{} 和 KaTeX parse error: Expected 'EOF', got '#' at position 10: {} 的区别 1)#?{} 为参数占位符 ?,即sq…{} 为字符串替换,即 sql 拼接
1)#{}:动态解析 -> 预编译 -> 执行
2)${}:动态解析 -> 编译 -> 执行
1)#{} 的变量替换是在DBMS(数据库管理系统)中
2)${} 的变量替换是在 DBMS外
(4)
1)变量替换后,#{} 对应的变量自动加上单引号 ‘’
2)变量替换后,${} 对应的变量不会加上单引号 ‘’
(5)
1)#{} 能防止sql 注入
2)${} 不能防止sql 注入
80.springboot 和spring springmvc有什么区别
对于我来说 就是创项目的时候快一些,因为我原来做一个springmvc的项目的时候,就不说创建项目了,
光配置这个项目就要配置很久,久了配置很可能会搞忘了,现在他就直接用maven管理。
spring是基础,springboot在他的基础上演化过来的,就是不用再配置那么多的xml配置。
81.Synchronized关键字加在方法上和加在静态代码块上有什么区别?
Synchronized关键字加在方法上,获取到的锁就是当前对象实例的锁,
Synchronized关键字加在静态代码块上,获取到的锁就是当前类对象的锁
HashMap的数据结构和工作原理
整体是一个数组;
数组每个位置是一个链表;
链表每个节点中的Value即我们存储的Object;
第一步:通过 hash 算法算出hash 值
第二步:通过计算出的hash 值去调用方法,计算当前对象应该存储在数组的哪个位置
第三步:判断是否需要扩容,如果不需要,则继续;如果需要,则进行数组扩容,将数组长度扩容为原来的2倍。
第四步:将当前对应的 hash值存储到数组或者链表中,简单来说,先来的往后退。
扩容机制:
HashMap 使用 “懒扩容” ,只会在 PUT 的时候才进行判断,然后进行扩容。
将数组长度扩容为原来的2 倍
将原来数组中的元素进行重新放到新数组中
Token 的身份验证方法
客户端请求登录
服务端收到请求,验证
验证成功后,服务端会签发一个 Token,再把这个 Token 发送给客户端
客户端收到 Token 以后可以把它存储起来,放在 Cookie 里
客户端每次向服务端请求资源的时候需要带着服务端签发的 Token
服务端收到请求,先去验证客户端请求里面带着的 Token,如果验证成功,就向客户端返回请求的数据
单点登录的三种方法
最简单的单点登录实现方式,是使用cookie作为媒介,存放用户凭证。用户登录父应用之后,
应用返回一个加密的cookie,当用户访问子应用的时候,携带上这个cookie,授权应用解密cookie并进行校验,
校验通过则登录当前用户。
通过JSONP实现 对于跨域问题,可以使用JSONP实现
通过页面重定向的方式 最后一种介绍的方式,是通过父应用和子应用来回重定向中进行通信,实现信息的安全传递。
在做单点登录的时候,我是用hash这种数据结构来存储用户信息,以cookieId作为key,
设置30分钟为缓存过期时间,能很好的模拟出类似session(撒生)的效果。
MD5的实现
注册的时候
1)用户提供账号和密码
2)系统为用户随机生成一个Salt值;
3)在将Salt值和用户密码连接到一起,再进行MD5加密;
4)将MD5加密串和Salt值分别存入数据库中。
登录的时候:
用户输入用户名和密码
根据用户名找到与之对应的MD5加密串和盐(Salt)值
在把密码进行加密,用这次加密的和数据库中的对比,相等则密码正确,反之则不对。
在Java中完成MD5加密,MessageDigest(麦生级代级四)类大部分都帮你实现好了
利用MD5加密解密
先用 MD5加码 生成32位md5码 ,在用加密解密算法 执行一次加密,两次解密
在用md5进行加密时,至少要将md5加密两次以上(包含两次),或者再加上盐进行加密
为了更好地保护用户的密码和个人帐户安全,这个时候就需要对MD5摘要结果掺入其他信息,称之为加盐
Java1.8新特性
HashMap------底层数据结构从1.7的数组+链表的形式调整为数组+链表+红黑树
函数式接口—口中只有一个抽象方法,则称之为函数式接口
Lambda-----本质上是改进的匿名方法(Lambda需要函数式接口的支持)
方法引用和构造器引用---------使用操作符“::” 将方法名和对象或类的名字分隔开来。
Stream API----- 从1.8引入的api ,都和集合有关
新时间日期API(没有详细了解过)
接口中的默认方法与静态方法
JDK1.7之前在接口中只能有静态常量和抽象方法,JDK1.8中则可以有default修饰的默认方法
和static修饰的静态方法,函数式接口中可以有多个默认方法和静态方法,但只能有一个抽象方法
集合为什么有迭代器?
这个时候就需要用到迭代器
在不暴露内部的数据,可以直接外部遍历。
如果说没有使用迭代器,遍历一个数组的方法是使用索引,而访问一个链表又必须使用while循环
就是这俩种你还得事先知道集合的内部结构,访问代码和集合本身就紧耦合,无法将访问逻辑从集合类和
代码中分离出来,每一种集合对应一种遍历方法,客服端代码无法复用。
更恐怖的是,如果以后需要把ArrayList更换为LinkedList,则原来的代码必须全部重写!
具体的功能有通过航班号进行航班搜索,通过出发点和目的地进行航班搜索,实时展现航班的航线
通过点击航线上的小点推荐旅游景点和吃饭娱乐的地方,
前端用的框架是echart.js
后端用的框架是springboot
爬虫用的框架是webmagic
数据库用的mysql
数据怎么来的!
从一些网站上面爬下来的,是对webmagic框架来进行二次开发网页爬取的
过程就是先分析网页上的数据,如果是静态的话,就直接用xpath表达式定位到我想要的数据
然后直接爬下来,如果是动态数据的话,就用谷歌的网页分析工具分析他的接口,然后对接口里的
内容再进行二次开发,最后把数据保存到数据库里面
面试官 你好 我叫xxx 毕业于湖南大学 原来的公司呢主要是做电子政务的项目比较多,主要业务方向是这个时尚监管和药监的
业务,之前也做过一些电商平台的项目,技术栈的话,我对现在比较主流的springMVC springboot,mybtis框架啊,这些比较了解,
数据库方面的话用的mysql比较多,oracle也了解一些。
详细的介绍工作内容:
最近一个项目呢做的是一个旅游平台的项目,我主要负责的是搜索和推荐模块,具体功能有通过航班号进行航班搜索,通过目的地
和出发点进行航班搜索,还有就是通过点击航线上和目的地附近的小点进行推荐景点和吃饭娱乐的地方。
前端框架用的是echart.js
后端用的是springboot,
爬虫用的是webmagic
数据库用的是mysql。
你们公司是做什么的?
主要是做电子政务方面的项目, 比如说 电子商务,信息化技术,智慧商城等。
你遇到的最大难题是什么
分布式事务
分布式事物是一个比较复杂的也是一个比较棘手的问题吧,先说分布式事物之前呢我想说一下
我们普通的事物,我们普通的事物都是有一组操作,组成一个工作单元。这个工作单元呢要么全部执行成功,
要么就是失败以后全部进行回滚操作,举个列子,就比如说我们经常用到的电商平台的下单操作,
下单的时候我们要创建订单和扣除或者是锁定这个库存,这俩个操作呢要么就是全部成功,要么就是全部失败,
失败过几天回滚,这个就是普通的事物。在说下这个分布式事物啊,就拿刚刚那个订单的例子啊,
在分布式系统里边呢,可能这个创建订单的操作,在那个订单的微服务中,然后库存的操作呢,在那个库存的微服务中
就是这个操作呢是由多个系统或者是服务来协同完成的,就是一次事务操作呢涉及多个系统,他是通过网络协同完成的过程,
我们举的这个例子呢就是说一个分布式我们可以看做是多个分布式子事务来组成的!
关于分布式系统呢,他有这个cap和base俩个经典的理论。cap呢就是指一致性,可用性和分区容错性,这三个单词首字母缩写
一个分布式不可能同事满足这三个基本要求,所以最多只能满足其中的俩项。这个就是cap
base呢就是在cap的基础上逐步演化过来的,是基本可用,软状态和最终一致性这三个组成的,
base他的核心思想呢就是无法做到强一致性,但是呢每个应用都可以根据自身的业务特点采用适当方式来达到这个最终的一致性
分布式事物呢我们之前采用的是bytetcc这么一个开源的分布式事务框架。他的主要思想呢就是tcc,就是try confirm cancel这三个字的缩写
就是从在调用接口实现一组业务操作的时候呢,不是说直接完成那个业务操作,而是先完成try的操作,这个操作一般是去锁定某个资源或者是
设定一个预备的状态,是冻结还是冻结一部分数据 的一个中间状态吧,大概就是这个类型的操作吧。
然后这个try完成以后就会分俩种情况,第一种就是比较理想的情况下,就是所有的微服务执行自己的try操作都能执行成功,这个时候呢这个分布式框架他就会
继续推动我后续的执行。还有一种如果出现了异常,执行的时候报错了,这个事物框架他就能感知到!然后他就对整个tcc分布式事务进行回滚
这就是我对分布式还有我们之前分布式事务的一个处理!
你对分布式了解吗
从字面上来说就是将我们不同的业务分散到不同的地方,比如说我们最简单的分布式就是把我们的数据库服务和一些web服务
就是提供给用户访问的一些东西,然后把他部署到不同的机子上面,这个也叫分布式。还有就是现在比较流行的分布式呢,叫
微服务的一个架构。所谓微服务呢,他是分布式里的一种就是把同一个系统中的业务拆分成单独的服务,
然后把这些单独的服务交给团队独立去去运行,独立去部署和运维
我在说下我对分布式里的微服务的了解吧
我个人对微服务的理解是这样的,在以前的系统中呢,我们都是单体应用这么一个架构嘛 然后慢慢可能觉得这么单体架构的性能遇到瓶颈了吧
然后我们就茶用多应用,然后底层还是一个数据库,但是这样的话系统还是没有完全解耦嘛,然后就逐步演化成这个微服务了
微服务前几年用的比较多的是那种水平垂直分布的链式调用,就是所有的请求都是从网关进来,然后网关去转发到下面不同的服务去调用
就是业务系统调用a a-b b-c 这么一个调用方式
现在比较流行的是哪个聚合式调用,好像是阿里和一些大公司炒出来的把。他的调用方式呢是 业务系统调用a a响应返回,然后在调用b 掉用c
这么一个水平拆分的调用方式吧
那你说一下springcloud里的几个组件
服务注册中心eureka Ribbon 负载均衡 Hystrix 断路器 zul 网关 还有个配置中心fonfigure
注册中心eureka 他主要承担的作用就是把我们各种服务注册到这里面去,然后要调用他的,要先从这里面来拿
服务。
Ribbon就是做负载均衡调用的,主要的作用呢就是从服务中心里拿到
一堆服务列表,然后比如说我要拿其中的一个服务,拿到他有可能不止一个,这个时候我就要按照一定的
负载均衡策略完成调用,这个操作就是交给ribbon或者feign去完成的。
Hystrix 断路器 主要是做熔断和降级以及限流的
configure 配置中心 就是不同微服务都可能有配置,他是分散的不好管理 就统一了配置中心configure
zuul网关 就是有N多个微服务 这些微服务最终还是要给前端调用的,如果说是一个服务就有一个地址
他是非常不好管理的,这个时候呢就是让网关统一地址,还有就是对访问的微服务做统一鉴权等等操作
事务的注解只能在public上,如果注解不在这些上面则注解会失效但不会报错。
事务的注解开启配置,必须放在listener里加载,其他则失效。
如果使用了spring+mvc则重复扫描问题可能引起事务失败。
response request
@RequestParam也可用于其它类型的请求,例如:POST、DELETE等请求。
@RequestBody接收的参数是来自requestBody中,即请求体。
在GET请求中,不能使用@RequestBody。
在POST请求,可以使用@RequestBody和@RequestParam,但是如果使用@RequestBody,对于参数转化的配置必须统一。
如果使用@RequestParam来接受参数,可以在接受参数的model中设置@DateFormat指定所需要接受时间参数的格式。
另外,使用@RequestBody接受的参数是不会被Servlet转化统一放在request对象的Param参数集中,@RequestParam是可以的。
综上所述,一般情况下,推荐使用@RequestParam注解来接受Http请求参数。
内容总结
以上是互联网集市为您收集整理的实战得来的java面试知识经验总结全部内容,希望文章能够帮你解决实战得来的java面试知识经验总结所遇到的程序开发问题。 如果觉得互联网集市技术教程内容还不错,欢迎将互联网集市网站推荐给程序员好友。
内容备注
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 gblab@vip.qq.com 举报,一经查实,本站将立刻删除。
内容手机端
扫描二维码推送至手机访问。