记录一次跳槽java面试中遇到的问题

1、nginx是用来做什么的?
反向代理,负载均衡。当网站的访问量达到一定程度后,单台服务器不能满足用户的请求时,需要用多台服务器集群可以使用nginx做反向代理。并且多台服务器可以平均分担负载,不会因为某台服务器负载高宕机而某台服务器闲置的情况。

2、spring的依赖注入是什么?有几种注入方式?Set注入是怎么注入的?
依赖注入( Dependecy Injection )和控制反转( Inversion of Control )是同一个概念, 具体的讲:当某个角色 需要另外一个角色协助的时候,在传统的程序设计过程中,通常由调用者来创建被调用 者的实例。但在 spring 中 创建被调用者的工作不再由调用者来完成,因此称为控制反转。创建被调用者的工作由 spring 来完成,然后注入调用者 因此也称为依赖注入。 spring 以动态灵活的方式来管理对象 
注入的三种方式:set注入和构造注入和接口注入。 设置注入的优点:直观,自然 构造注入的优点:可以在构造器中决定依赖关系的顺序!
Set方式的注入可以注入的内容有:
1.基本类型(8中基本类型+字符串)的装配
2.对象类型的装配
3.集合的装配
Spring管理bean就是tomcat启动的时候通过扫描(comment-scan)注解比如扫描某个包下的有@service的类加载到spring容器中
在Spring中,注入依赖对象可以采用手工装配或自动装配,在实际应用开发中建议使用手工装配,因为自动装配会产生许多未知情况,开发人员无法预见最终的装配结果。
手工装配依赖对象又分为两种方式:
一种是在XML文件中,通过在bean节点下配置;如上面讲到的使用属性的setter方法注入依赖对象和使用构造器方法注入依赖对象都是这种方式。
另一种就是在java代码中使用注解的方式进行装配,在代码中加入@Resource或者@Autowired
重点:在Spring IOC编程的实际开发中推荐使用注解的方式进行依赖注入。

3、AOP的面向切面
将那些与业务无关,却为业务模块所共同调用的 逻辑或责任封装起来,比如事务管理、权限验证,便于减少系统的重复代码,降低模块间的耦合度,并有利于未来的可操作性和可维护性

4、一个service中调用另一个service的方法时的事务控制问题
配置通知,传播行为<tx:method name="save*" propagation="REQUIRED" />,当一个seivice中调用另一个service时在使用SPRING的事务控制时,事务一般都是加在SERVICE层的,这个时候如果一个SERVICE调用另一个SERVICE时有可能会出现事务控制问题,比如第二个SERVICE抛出了异常,第一个SERVICE却正常提交了

在事务传播为propagation="REQUIRED"的时候,如果SERVICE中抛出检查型异常( throw new FileNotFoundException("fjkdl"); ),其它的事务可以正常提交,但是如果SERVICE抛出运行时异常( throw new RuntimeException("runtime e");),则所有的SERVICE共享同一事务(会回滚)。
 如果我们改下配置,如下:
<tx:method name="add*" propagation="REQUIRED" rollback-for="java.lang.Exception"/>  
 这个时候,无论SERVICE里抛出运行时异常还是检查型异常,将共享同一事务,也就是说只要有异常,事务将自动回滚。

Spring中事务传播类型:七种
常见的有两种
REQUIRED:支持当前事务,如果当前没有事务,就新建一个事务。这是最常见的选择。 
SUPPORTS:支持当前事务,如果当前没有事务,就以非事务方式执行。 

5、java的反射是什么?
JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法,并且构造这个类的对象;对于任意一个对象,都能够调用它的任意一个方法,并且判定这个对象所属的类;这种动态获取的以及动态调用对象的方法的功能称为java语言的反射机制。

6、java虚拟机是什么?为什么java有虚拟机,c没有虚拟机?
(1)可以理解为是执行java字节码文件的机器(虚拟机进程);
(2)因为java语言写的代码是.java文件,编译后是字节码文件,字节码不能直接在cpu上运行,所以需要用到虚拟机把字节码文件转换成二进制文件,而C语言编译的文件就是二进制文件,所以可以直接在cpu上运行。

7、Java面向对象有几种规则?
Java面向对象的6大原则:开闭原则、里氏代换原则、依赖倒换原则、接口隔离原则、单一职责原则或聚合复用原则、迪米特法则或最少知识原则

8、linux常见命令

答案就不写了

9、堆和栈都是存放什么信息的?String str = new String(“hello”);说一下这串代码里面的的哪些信息放在哪里?
类的静态成员变量和类的信息(方法)是放在方法区中,类的成员变量是放在堆中。
方法中定义的引用如str是存放在栈中,new String(“hello”)对象都存放在堆中,hello是存放在字符串的常量池中(方法区中)。

10、java的序列化与反序列化是什么?为什么要序列化和反序列化?
Java序列化是指把Java对象保存为二进制字节码的过程,Java反序列化是指把二进制字节码重新转换成Java对象的过程。
需要把Java对象通过网络进行传输的时候。因为数据只能够以二进制的形式在网络中进行传输,因此当把对象通过网络发送出去之前需要先序列化成二进制数据,在接收端读到二进制数据之后反序列化成Java对象。

11、一般跟多线程有关的都需要锁、锁有几种?为什么要用到锁? 
锁有synchronized与Reentrantlock(重入锁),平常的程序当中由于是单线程去处理的,因此不会出现变量资源同时被多个线程同时访问修改,程序的运行是顺序的。然而多线程的环境中就会出现变量资源同时被多个线程获取,同时去做修改的状况。

Reentrantlock拥有和synconized的区别:
Reentrantlock拥有和synconized相同的并发性和内存语义,此外还多了锁投票,定时锁等候和中断锁等候的功能
(1)线程A和B都要获取对象O的锁定,假设A获取了对象O锁,B将等待A释放对O的锁定, 如果使用 synchronized,如果A不释放,B将一直等下去,不能被中断
如果 使用ReentrantLock,如果A不释放,可以使B在等待了足够长的时间以后,中断等待,而干别的事情
(2)synconized是虚拟机层面上的,由虚拟机来自动释放锁,lock是通过代码来实现的,只能手动释放锁,在finaly代码块中释放。
(3)在资源竞争不是很激烈的情况下,Synchronized的性能要优于ReetrantLock,但是在资源竞争很激烈的情况下,Synchronized的性能会下降几十倍,但是ReetrantLock的性能能维持常态;

12、java中的垃圾回收

为了分代垃圾回收,Java堆内存分为3代:新生代(复制算法),老年代(标记整理算法、标记清除算法)和永久代。
新生代和老年代是在堆中,永久代是在方法区中
新的对象实例会优先分配在新生代,在经历几次Minor GC后(默认15次),还存活的会被移至老年代(某些大对象会直接在老年代分配)。
永久代是否执行GC,取决于采用的JVM。
Minor GC发生在新生代,当Eden区没有足够空间时,会发起一次Minor GC,将Eden区中的存活对象移至Survivor区。Major GC发生在老年代,当升到老年代的对象大于老年代剩余空间时会发生Major GC。
发生Major GC时用户线程会暂停,会降低系统性能和吞吐量。
JVM的参数-Xms和-Xmx用来设置Java堆内存的初始大小和最大值。依据个人经验这个值的比例最好是1:1或者1:1.5。比如,你可以将-Xmx和-Xms都设为1GB,或者-Xmx和-Xms设为1.2GB和1.8GB。
Java中不能手动触发GC,但可以用不同的引用类来辅助垃圾回收器工作(比如:弱引用或软引用)。
垃圾回收总结:一个对象在没有任何强引用指向他或该对象通过根节点不可达时需要被垃圾回收器回收;当垃圾收集器意识到需要进行GC时会触发Minor GC或Major GC,是自动的,无法强制执行

Jvm的一些常见参数
-server:一定要作为第一个参数,在多个 CPU 时性能佳
(配置堆区:有垃圾回收机制)
-Xms:表示 Java 初始堆大小
-Xmx:表示 Java 最大堆大小
-Xss:表示每个 Java 线程堆栈大小
-XX:NewSize:设置新生代内存大小。
-XX:MaxNewSize:设置新生代内存最大值
-xmn:对前两个参数同时配置
(配置非堆区:方法区没有垃圾回收机制,这一块只能靠程序员自己来约束自己)
-XX:PermSize:设置持久代内存大小
-XX:MaxPermSize:设置持久代内存最大值
注意:最大堆内存和最大非堆内存的和不能超出操作系统的可用内存

12、HashMap,HashTable,ConcurrentHashMap,sychronizedMap的原理和区别
HashMap 是线程不安全的:
内部存储使用了一个 Node 数组(默认大小是16),《java并发编程艺术》中说到HashMap 在并发执行 put 操作时会引起死循环,导致 CPU 利用率接近100%。因为多线程会导致 HashMap 的 Node 链表形成环形数据结构,一旦形成环形数据结构,Node 的 next 节点永远不为空,就会在获取 Node 时产生死循环。
HashTable 是线程安全的:
HashTable 源码中是使用 synchronized 来保证线程安全的,比如 get 方法和 put 方法,当一个线程使用 put 方法时,另一个线程不但不可以使用 put 方法,连 get 方法都不可以(当一个线程访问 HashTable 的同步方法时,其他线程如果也要访问同步方法,会被阻塞住)

ConcurrentHashMap是线程安全的:
ConcurrentHashMap 不仅线程安全而且效率高,因为它包含一个 segment 数组,将数据分段存储,给每一段数据配一把锁,也就是所谓的锁分段技术,同时最多可以有16个写线程操作Map,读操作几乎不受限制。(Segment其实是继承能了reentranlock,所以它是一种重入锁)(这是java7中的,java8已经摒弃了 Segment(锁段)的概念,而是启用了一种全新的方式实现,利用 CAS 算法)
SynchronizedMap是线程安全的:
 synchronizedMap() 方法后会返回一个 SynchronizedMap 类的对象,而在 SynchronizedMap 类中使用了 synchronized 同步关键字来保证对 Map 的操作是线程安全的。

最后总结:ConcurrentHashMap性能是优于Hashtable 和 SynchronizedMap (可以用ExecutorService 来并发运行5个线程进行测试)

13、HashMap是如何解决冲突的
使用链接法,将索引值相同的元素存放到一个单链表里,为了解决在频繁冲突时HashMap性能降低的问题,Java 8中做了一个小优化,在冲突的元素个数超过设定的值(默认为8)时,会使用平衡树来替代链表存储冲突的元素

14、ArrayList和LinkedList区别
ArrayList、Vector是实现了基于动态数组的数据结构,LinkedList基于链表的数据结构。 
ArrayList、Vector有下标,所以查询数据快,Vector由于使用了synchronized方法-线程安全,所以性能上比ArrayList要差,inkedList使用双向链表实现存储,按序号索引数据需要进行向前或向后遍历,但是插入数据时只需要记录本项前后项即可,插入数据较快。

15、set集合
Set是最简单的一种集合。集合中的对象不按特定的方式排序,并且没有重复对象。 Set接口主要实现了两个实现类:
HashSet: HashSet类按照哈希算法来存取集合中的对象,存取速度比较快 
TreeSet :TreeSet类实现了SortedSet接口,能够对集合中的对象进行排序。 

16、线程同步的五种方法
(1)Synchronized关键字修饰的方法
(2)Synchronized关键字修饰代码块
(3)使用特殊域变量(volatile)实现线程同步:
在需要同步的变量上加上volatitle进行修饰
private volatile int acount = 100;
资源变量是透明的,多个线程之间共用资源变量,当线程A修改资源变量时,线程B立马就获取到最新的资源变量。
原理:是每次要线程要访问volatile修饰 的变量时都是从内存中读取,而不是从缓存当中读取,因此每个线程访问到的变量值都是一样的。这样就保证了同步
Volatile 变量具有 synchronized 的可见性特性,但是不具备原子特性。
volatile不是线程安全的,因为此时多个线程的执行是无序的,并不能保证多个线程执行的有序性和原子性,所以说它不是线程安全的。
(4)ReentranLock重入锁实现线程同步:
private Lock lock = new ReentranLock();
lock.lock(); 
lock.unlock();
(5)使用ThreadLocal管理变量来实现同步:
private static Threadlocal<integer> accout = new ThreadLocal<Integer>(){
...
}
每一个使用该变量的线程都会获得该变量的副本,副本之间相互独立,每个线程都可以随意修改自己的变量副本不会影响别的线程。
原理:底层其实是用hashmap根据线程标识(key)来存储副本的变量的(value),所以它不是线程安全的


17、实现线程的几种方式
1.继承Thread类
2.实现Runnable接口
3.实现Callable接口通过FutureTask包装器来创建Thread线程(callable的call方法是有返回值)

18、mysql的sql执行时间较长
可用pt-query-digest等工具分析慢查询日志,也可以用explain查看SQL的执行计划

19、mysql的四个存储引擎
(1)、MyISAM存储引擎:特点:不支持事务、也不支持外键,优势是访问速度快,对事务完整性没有要求
(2)、InnoDB存储引擎:
该引擎提供了具有提交、回滚和崩溃恢复能力的事务安全
特点:支持自动增长列,支持外键约束
(3)、Memory存储引擎
(4)、Merge存储引擎:是一组MyISAM表的组合

20、oracle的sql优化 查看执行计划和统计信息
set autotrace on:包含执行计划和统计信息
在执行计划中只需要看cost(代价)
Cost:代价越大,性能就越低
在统计信息中只需要看逻辑读
1042 consistent gets:逻辑读,逻辑读越大,性能越低

21、存储过程和存储函数的区别
不同点:函数有返回值类型,过程没有,函数可以在select语句中直接使用,过程不可以
相同点:两者都可以出参(通过out参数出参)

22、什么样的列适合加索引
在where从句,group by从句,order by从句,on从句中出现的列
索引的字段越小越好
在建立联合索引时,离散度大的列放大联合索引的前面
列中只有1和2不适合建索引

23、Redis提供哪几种数据结构
字符串,散列,列表,集合,有序集合。

24、spring中用到的设计模式
工厂模式:IOC容器
代理模式:AOP
策略模式:在spring采取动态代理时,根据代理的类有无实现接口有JDK和CGLIB两种代理方式,就是采用策略模式实现的
单例模式:默认情况下spring中的bean只存在一个实例

25、什么是多态?
一、继承中的多态
1、存在继承关系
2、子类要重写父类的方法
3、父类数据类型的引用指向子类对象。
父类引用指向子类对象,调用方法时会调用子类的实现,而不是父类的实现,这叫多态。
二、同一个类中
1、方法的重载,相同的方法名对应着不同的方法实现(方法参数不同),这也做多态。
总结:覆盖是父类与子类之间多态性的一种表现,重载是一个类中多态性的一种表现。

26、springmvc是单例还是多例,springmvc是不是线程安全的?
Springmvc默认是单例模式,因为spring的作用域有5个,分别是:singleton(单例模式)、prototype(原型模式)、request、session、globalSession五个。
Springmvc默认是单例模式,所以成员属性会出现线程安全问题、是非线程安全的

27、mybatis和hibenate的区别
hibernate是全自动,而mybatis是半自动
sql直接优化上,mybatis要比hibernate方便很多
hibernate数据库移植性远大于mybatis

28、springmvc的工作原理
1、DispatcherServlet前端控制器接收发过来的请求,交给HandlerMapping处理器映射器
2、HandlerMapping处理器映射器,根据请求路径找到相应的HandlerAdapter处理器适配器(处理器适配器就是那些拦截器或Controller)
3、HandlerAdapter处理器适配器,处理一些功能请求,返回一个ModelAndView对象(包括模型数据、逻辑视图名)
4、ViewResolver视图解析器,先根据ModelAndView中设置的View解析具体视图
5、然后再将Model模型中的数据渲染到View上

29、事务的概念?数据库的事务的四大特性?
事务的概念:
事务指逻辑上的一组操作,组成这组操作的各个单元,要不全部成功,要不全部不成功
数据库的事务的四大特性:
原子性:是指事务是一个不可再分割的工作单元,事务中的操作要么都发生,要么都不发生。
一致性:是指在事务开始之前和事务结束以后,数据库的完整性约束没有被破坏。这是说数据库事务不能破坏关系数据的完整性以及业务逻辑上的一致性。
隔离性:是多个事务并发访问时,事务之间是隔离的,一个事务不应该影响其它事务运行效果
持久性:是在事务完成以后,该事务所对数据库所作的更改便持久的保存在数据库之中,并不会被回滚


30、数据库事务的四个隔离级别:
在事务的并发操作中可能会出现 脏读,不可重复读,幻读
脏读:看到的是老板还没提交事务时的数据。这就是脏读。
不可重复读:银行卡刷卡时出现了一个事务范围内两个相同的查询却返回了不同数据,这就是不可重复读。
幻读:超市购买东西第一次刷卡有钱再次刷卡钱没了,像是产生了幻觉
读未提交:顾名思义,就是一个事务可以读取另一个未提交事务的数据。
什么问题都解决不了
读已提交:顾名思义,就是一个事务要等另一个事务提交后才能读取数据。
能解决脏读问题
可重复读:就是在开始读取数据(事务开启)时,不再允许修改操作(不可重复读对应的是修改,即UPDATE操作)
能解决不可重复读问题,脏读问题
序列化:就是在开始读取数据(事务开启)时,不再允许插入操作(幻读对应的插入操作,即insert操作)
序列化可以解决幻读,不可重复读,脏读问题

绝大多数数据库是的默认事务隔离级别是读已提交
但是mysql的默认事务隔离级别是可重复读

31、货主发布货找车货源,车主抢单的时候是怎么处理并发的?(本人项目中涉及到的并发抢单问题)

采用的是乐观锁,就是在货源表加一个version版本的字段,每次要去修改货源的状态时,首先去查当前订单表中该订单的version值出来,然后进行update这个订单状态(同时修改version值,我的处理是version值+1)的时候再加上where 条件过滤,判断version值是否还是之前获取的version值。如果是之前获取的version值,就可以更改成功,然后再插入一条订单,否则更改失败,返回0,不插入订单,前端接收信息并进行相应的处理(例:该订单已被别人抢单)。

32、Spring Boot特点,为什么要用springboot?
1. 创建独立的Spring应用程序
2. 嵌入的Tomcat,无需部署WAR文件
3. 简化Maven配置
4. 自动配置Spring

5. 全程使用注解,对xml无任何配置

springBoot最大的特点就是当下所倡导的一种理念“习惯优于配置”springBoot它其实并没有用到特别的技术,而是在项目中预先进行了许多习惯性的配置,内嵌tomcat容器,无代码生成并且项目可以没有一个xml配置,全由注解来完成这一切,其本身提供了准企业级开发的配置。
常见的注解:
1、@SpringBootApplication:Spring Boot项目的核心注解,主要目的是开启自动配置(通常用于主类上);
2、@Configuration:这是一个配置Spring的配置类;


33、说一下dubbo

dubbo:分布式微服务框架、用来提高性能和rpc远程调用方案,是阿里巴巴SOA服务化治理方案的核心框架。
最大的特点是按照分层的方式来架构,最大限度的解耦合;从服务角度来看可以抽象出服务消费方和服务提供方两个角色。
rpc:远程调用协议,就是在分布式系统中当a和b系统都有相同的一个功能时,把这个功能(接口、javabean以及接口的实现)抽取出来放到c这个系统中,
然后c这个系统就是服务提供方,a和b(a和b系统只保留接口和javabean,当然还可以把a、b、c这三个系统中的javabean和接口抽取出来放到一个新建的功能c-api中解决代码重复问题,在a、b、c系统中添加c-api的依赖就可以了)
个系统就是服务消费方(调用方),a和b调用c系统功能的这个过程就叫做远程调用。

dubbo入门配置:
dubbo-server.xml配置
将接口实现类加载到spring容器中,然后把接口暴露到dubbo中,然后用dubbo协议在20880端口中暴露服务,并注册到zookeeper注册中心。把监控中心也发布到注册中心里面去(监控中心也是一个服务),统计服务的调用时才发送数据到注册中心中。
当一个系统调用另一个系统发布的服务时httpclient发起get、post请求和使用dubbo协议的区别:
httpclient发起get、post请求:拿到的是json数据、需要自己进行反序列化。
使用dubbo协议会自动完成序列化和反序列化。

dubbo注册中心,比如当门户系统请求后台系统查询新闻时,先去注册中心查找,如果找到了,再调用后台服务查询新闻。
这样子在注册中心可以有效的管理起来。然后监控中心用来统计服务的调用(异步的方式)。
原理:服务消费者和提供者,在内存中累计调用次数和调用时间,定时每分钟发送一次统计数据到监控中心。
调用关系:
1. 服务容器负责启动,加载,运行服务提供者。
2. 服务提供者在启动时,向注册中心注册自己提供的服务。
3. 服务消费者在启动时,向注册中心订阅自己所需的服务。
4. 注册中心返回服务提供者地址列表给消费者,如果有变更,注册中心将基于长连接推送变更数据给消费者。
5. 服务消费者,从提供者地址列表中,基于软负载均衡算法,选一台提供者进行调用,如果调用失败,再选另一台调用。
6. 服务消费者和提供者,在内存中累计调用次数和调用时间,定时每分钟发送一次统计数据到监控中心。

http:短链接:使用完之后链接就会断开(打数据量小并发时用,比如文件)
dubbo协议:单一长链接:使用完之后不会断开、一直存在(小数据量大并发时用,因为大并发的情况下,每次都创建连接性能就会下降得很厉害)

猜你喜欢

转载自blog.csdn.net/lixiaohai_918/article/details/79951025