您的位置:首页 > 职场人生

总结一次失败的JAVA面试:消息、缓存、通知、Static……

2018-01-18 19:22 399 查看
最近面试了几家公司,发现没有每家的面试题、侧重点都不同。
有的基本完全不问技术、有的问底层多、有的问框架多。
今天去某公司面试,问的基本全部是基础的问题,好多都答得不好
0、谈谈对JVM的理解
这个有很多,我就不贴了
1、谈谈你对消息的理解
当时只说了异步、消息是能序列化的、有点对点和广播方式,面试官强调不要说某个中间件,只单说消息,说只有异步是对的,问还有其他嘛
回来查了一下,可能答案应该是:
消息是JMS(JAVA消息服务)中的一种类型对象
1)、消息包含:消息头、消息属性、消息自身
   消息头主要定义消息的Topic、消息序列、消息类型
2)、消息传送是建立在Observer设计模式基础上的
3)、消息传送的两种模型
   发布/订阅模型:客户端发送消息到一个名为主题(topic)的虚拟通道中,每个订阅该主题的消费者都会接收到每条消息的一个副本。
   点对点模式:客户端通过队列(queue)这个虚拟通道来同步和异步发送、接收消息,发送到队列的消息只能被一个接收者所接收,即使有多个消费者时也只能有一个消费者处理消息。
4)、在消息接收上分为推模型和拉模型,他们是使用轮询或事件驱动方式来进入消息接入。对消息服务而言,还要考虑消息消费模式:消息分派还是消息获取,消息的订阅与过滤机制、消息接入应用是同步处理还是异步处理
5)什么时候用到消息机制:
  A、异构系统集成,整合现有资源,提高资源的利用率
  B、异步请求处理,减轻或消除系统瓶颈,提高用户生产率和系统的整体可伸缩性
  C、组件解偶,增加系统的灵活性
参考:http://blog.csdn.net/zh521zh/article/details/50077567
2、synchronized的修饰对象有几种
synchronized是JAVA中的关键字,是一种同步锁。它修改的对象有:
1)、修饰一个代码块,被修饰的代码块称为同步语句块,其作用的范围是大括号{}括起来的代码,作用的对象是调用这个代码块的对象
2)、修饰一个方法,被修饰的方法称为同步方法,其作用的范围是整个方法,作用的对象是调用这个方法的对象
3)、修饰一个静态的方法,其作用的范围是整静态方法,作用的对象是这个类的所有对象
  静态方法是属于类的而不属于对象的。synchronized修改的静态方法锁定的是这个类的所有对象(实例)。
4)、修饰一个类,其作用的范围是synchronized后面括号括起来的部分,作用的对象是这个类的所有对象
如:
public void run(){
synchronized(account){ //给Account加锁
//******
}
}当没有明确的对象作为锁,只想让一段代码同步时,可以创建一个特殊的对象来充当锁:
零长度的byte数组对象创建起来将比任何对象都经济,查看编译后的字节码:生成零长度的byte[]对象只需3条操作码,而Object lock = new Object()则需要7行操作码。
class Test implements Runnable
{
private byte[] lock = new byte[0];  // 特殊的instance变量
public void method()
{
synchronized(lock) {
// todo 同步代码块
}
}
public void run() {
}
}
3、两个线程访问两个synchronized方法会怎么样?
1)、两个并发线程调用同一实例的synchronized方法,第二个Thread会被第一个Thread阻塞,第一个Thread执行完后再执行第二Thread。两个Thread是互斥的
2)、两个并发线程调用不同实例的synchronized方法,会给两个实例创建两个锁,两个线程互不影响
3)、两个并发线程,一个访问对象的synchronized(this)同步代码块时,另一个线程仍然可以访问该对象中的非synchronized(this)同步代码块
4)、两个并发线程,一个访问对象的synchronized非静态方法,一个访问对象的synchronized静态方法:因静态方法是属于类的,所以Thread2会被阻塞,2个Thread用的是同一把锁
总结:无论synchronized关键字加在方法上还是对象(实例)上,如果它作用的对象是非静态的,则它取得的锁是对象;如果synchronized作用的对象是一个静态方法或一个类,则它取得的锁是对类,该类所有的对象同一把锁。 
参考:http://blog.csdn.net/luoweifu/article/details/466130154、请谈谈static
“static方法就是没有this的方法。在static方法内部不能调用非静态方法,反过来是可以的。而且可以在没有创建任何对象的前提下,仅仅通过类本身来调用static方法。这实际上正是static方法的主要用途。”
  被static关键字修饰的方法或者变量不需要依赖于对象来进行访问,只要类被加载了,就可以通过类名去进行访问。
  static可以用来修饰类的成员方法、类的成员变量,另外可以编写static代码块来优化程序性能。
 1)static方法  
  静态方法中不能访问类的非静态成员变量和非静态成员方法,但是在非静态成员方法中是可以访问静态成员方法/变量的。
  即使没有显示地声明为static,类的构造器实际上也是静态方法。
2)static变量
  static变量也称作静态变量,静态变量和非静态变量的区别是:静态变量被所有的对象所共享,在内存中只有一个副本,它当且仅当在类初次加载时会被初始化。而非静态变量是对象所拥有的,在创建对象的时候被初始化,存在多个副本,各个对象拥有的副本互不影响。
  static成员变量的初始化顺序按照定义的顺序进行初始化。
3)static代码块
  static关键字还有一个比较关键的作用就是 用来形成静态代码块以优化程序性能(只会在类加载的时候执行一次)。static块可以置于类中的任何地方,类中可以有多个static块。在类初次被加载的时候,会按照static块的顺序来执行每个static块,并且只会执行一次。
4)static是不允许用来修饰局部变量

5、Spring bean scope及适用场景
1)singleton (单一实例)
  此取值时表明容器中创建时只存在一个实例,所有引用此bean都是单一实例
  singleton类型的bean定义从容器启动到第一次被请求而实例化开始,只要容器不销毁或退出,该类型的bean的单一实例就会一直存活。
   如:servlet在web容器中的生命周期。
2)prototype
  pring容器在进行输出prototype的bean对象时,会每次都重新生成一个新的对象给请求方
  对象的实例化及属性设置等工作是由窗口负责的,但准备完毕后,将对象实例返回给请求方,窗口就不再拥有当前对象的引用,请求方需要自己负责当前对象的后继生命周期的管理工作,包括该对象的销毁。适用于那些不能共享使用的类型。
  如:struts2中的action的scope就是prototype
3)request
再次说明request,session和global session类型只实用于web程序,通常是和XmlWebApplicationContext共同使用。<bean id ="requestPrecessor" class="...RequestPrecessor"   scope="request" />Spring容器,即XmlWebApplicationContext 会为每个HTTP请求创建一个全新的RequestPrecessor对象,当请求结束后,该对象的生命周期即告结束,如同java web中request的生命周期。当同时有100个HTTP请求进来的时候,容器会分别针对这10个请求创建10个全新的RequestPrecessor实例,且他们相互之间互不干扰,简单来讲,request可以看做prototype的一种特例,除了场景更加具体之外,语意上差不多。

对于web应用来说,放到session中最普遍的就是用户的登录信息,对于这种放到session中的信息,我们可以使用如下形式的制定scope为session:4)session
<bean id ="userPreferences" class="...UserPreferences"   scope="session" />Spring容器会为每个独立的session创建属于自己的全新的UserPreferences实例,比request scope的bean会存活更长的时间,其他的方面没区别,如果java web中session的生命周期

5) global session<bean id ="userPreferences" class="...UserPreferences"   scope="globalsession" />global session只有应用在基于porlet的web应用程序中才有意义,它映射到porlet的global范围的session,如果普通的servlet的web 应用中使用了这个scope,容器会把它作为普通的session的scope对待
 Scope配置的2种方式:XML、注解

6、Spring AOP应用场景
如性能监测,访问控制,事务管理、缓存、对象池管理以及日志记录
Authentication 权限
Caching 缓存
Context passing 内容传递
Error handling 错误处理
Lazy loading 懒加载
Debugging 调试
logging, tracing, profiling and monitoring 记录跟踪 优化 校准
Performance optimization 性能优化
Persistence 持久化
Resource pooling 资源池
Synchronization 同步
Transactions 事务

7、AOP  环绕通知
通知有:前置通知、后置通知、环绕通知@Around、异常通知
环绕通知其实就是动态代理的另一种实现,它是对匹配方法的一种包裹,可以实现其他的通知。
该类型的通知使用的是@Around注解,并且使用ProceedingJoinPoint代替之前的JoinPoint来获取方法的参数和签名等信息,同时通过它的实例对象来调用匹配的方法,因此这个类型的参数是必须有的。另外,该通知还必须有返回值,它的方法可以对应JDK中的动态代理中的invoke()方法,它的返回值就是Target的返回值
环绕通知和其他通知的区别:
1) 目标方法的调用由环绕通知决定,即你可以决定是否调用目标方法,而前置和后置通知   是不能决定的,他们只是在方法的调用前后执行通知而已,即目标方法肯定是要执行的。
2)  环绕通知可以控制返回对象,即你可以返回一个与目标对象完全不同的返回值,虽然这很危险,但是你却可以办到。而后置方法是无法办到的,因为他是在目标方法返回值后调用8、MySql Sql语句优化
这个我回答了一些:不要隐匿转换、不要Select *、建立索引,索引中不要Null列……之类的。
面试官说这是通用的,不分Mysql 和Oracle,而且select *和select 列名在查询分器中执行没什么性能差异,我要问的是MySql的Sql语句优化。 这个我不知道怎么答。如果有知道的同学,麻烦告诉我,谢谢

9、谈谈缓存机制
缓存,就是将程序或系统经常要调用的对象存在内存中,一遍其使用时可以快速调用,不必再去创建新的重复的实例。
这样做可以减少系统开销,提高系统效率。
在项目中使用缓存通常都是先检查缓存中是否存在,如果存在直接返回缓存内容,如果不存在就直接查询数据库然后再缓存查询结果返回

    缓存主要可分为二大类:
    一、通过文件缓存,顾名思义文件缓存是指把数据存储在磁盘上,不管你是以XML格式,序列化文件DAT格式还是其它文件格式; 
    二、内存缓存,也就是实现一个类中静态Map,对这个Map进行常规的增删查. 
     JVM就是开辟出一段内存空间。并控制JAVA创建后的对像在这段内存空间的生存周期 
     如果不定义为全局静态变量的话,JVM就会在一段时间里把不在使用的对像回收掉 
     而如果使用JAVA缓存的话,就是让这个对像不会被JVM回收掉,这样以后再需要操作这个对像时就不需要JVM创建,销毁这些耗时的动作了。

9、缓存穿透是什么?如果一个线程在缓存中没有查到Key,去DB中去取了,这时又有很多线程来取此Key,也一起去DB去取,怎么办?
缓存雪崩
缓存雪崩可能是因为数据未加载到缓存中,或者缓存同一时间大面积的失效,从而导致所有请求都去查数据库,导致数据库CPU和内存负载过高,甚至宕机。
解决思路:
1,采用加锁计数,或者使用合理的队列数量来避免缓存失效时对数据库造成太大的压力。这种办法虽然能缓解数据库的压力,但是同时又降低了系统的吞吐量。
2,分析用户行为,尽量让失效时间点均匀分布。避免缓存雪崩的出现。
3,如果是因为某台缓存服务器宕机,可以考虑做主备,比如:redis主备,但是双缓存涉及到更新事务的问题,update可能读到脏数据,需要好好解决。
缓存穿透
缓存穿透是指用户查询数据,在数据库没有,自然在缓存中也不会有。这样就导致用户查询的时候,在缓存中找不到,每次都要去数据库中查询。
解决思路:
1,如果查询数据库也为空,直接设置一个默认值存放到缓存,这样第二次到缓冲中获取就有值了,而不会继续访问数据库,这种办法最简单粗暴。
2,根据缓存数据Key的规则。例如我们公司是做机顶盒的,缓存数据以Mac为Key,Mac是有规则,如果不符合规则就过滤掉,这样可以过滤一部分查询。在做缓存规划的时候,Key有一定规则的话,可以采取这种办法。这种办法只能缓解一部分的压力,过滤和系统无关的查询,但是无法根治。
3,采用布隆过滤器,将所有可能存在的数据哈希到一个足够大的BitSet中,不存在的数据将会被拦截掉,从而避免了对底层存储系统的查询压力。
大并发的缓存穿透会导致缓存雪崩。
缓存并发
有时候如果网站并发访问高,一个缓存如果失效,可能出现多个进程同时查询DB,同时设置缓存的情况,如果并发确实很大,这也可能造成DB压力过大,还有缓存频繁更新的问题。
对缓存查询加锁,如果KEY不存在,就加锁,然后查DB入缓存,然后解锁;其他进程如果发现有锁就等待,然后等解锁后返回数据或者进入DB查询。只不过利用锁的方式,会造成部分请求等待。
缓存失效
引起这个问题的主要原因还是高并发的时候,平时我们设定一个缓存的过期时间时,可能有一些会设置1分钟啊,5分钟这些,并发很高时可能会出在某一个时间同时生成了很多的缓存,并且过期时间都一样,这个时候就可能引发一当过期时间到后,这些缓存同时失效,请求全部转发到DB,DB可能会压力过重。
那如何解决这些问题呢?
其中的一个简单方案就时讲缓存失效时间分散开,比如我们可以在原有的失效时间基础上增加一个随机值,比如1-5分钟随机,这样每一个缓存的过期时间的重复率就会降低,就很难引发集体失效的事件。

参考:http://ifeve.com/concurrency-cache-cross/
10、谈谈对RESTFUL的理解
REST描述的是在网络中client和server的一种交互形式;用URL定位资源,用HTTP描述操作
1)、URL定位资源,用HTTP动词(GET,POST,DELETE,DETC)描述操作
2)、Server提供的RESTful API中,URL中只使用名词来指定资源,原则上不使用动词。“资源”是REST架构或者说整个网络处理的核心。
比如: http://api.qc.com/v1/newsfeed: 获取某人的新鲜;  http://api.qc.com/v1/friends: 获取某人的好友列表; http://api.qc.com/v1/profile: 获取某人的详细信息;
3)、 用HTTP协议里的动词来实现资源的添加,修改,删除等操作。即通过HTTP动词来实现资源的状态扭转:
GET    用来获取资源,
POST  用来新建资源(也可以用于更新资源),
PUT    用来更新资源,
DELETE  用来删除资源。
4)、Server和Client之间传递某资源的一个表现形式,比如用JSON,XML传输文本,或者用JPG,WebP传输图片等。当然还可以压缩HTTP传输时的数据(on-wire data compression)。
5)、用 HTTP Status Code传递Server的状态信息。比如最常用的 200 表示成功,500 表示Server内部错误等

11、为什么要用RestFul
1)、客户端-服务器端分离
 提高用户界面的便携性(操作简单),通过简化服务器提高可伸缩性(高性能,低成本),允许组件分别优化(可以让服务端和客户端分别进行改进和优化)
2)无状态:从客户端的每个请求要包含服务器所需要的所有信息
  提高可见性(可以单独考虑每个请求),提高可靠性(更容易从局部故障中修复),提高可扩展性(降低了服务器资源使用)
3)、缓存:服务返回信息必须被标记是否可以缓存,如果缓存,客户端可能会重用之前的信息发送请求
  减少交互次数,减少交互的平均延迟
4)、分层系统:系统组件不需要知道与他交流组件之外的事情。封闭服务,引入中间层。
  限制了系统的复杂性、提高可扩展性
5)、统一接口
   提高交互的可见性,鼓励单独改善组件
6)、支持按需代码
   提高可扩展性
12、什么是微服务
微服务架构则是将单个的整体应用分割成更小的项目关联的独立的服务。一个服务通常实现一组独立的特性或功能,包含自己的业务逻辑和适配器。各个微服务之间的关联通过暴露API来实现

13、为什么要用微服务架构
1)、由于每个服务都是独立并且微小的,由单独的团队负责,仍然可以彩敏捷开发模式,自由的选择合适的技术,甚至可以重写老服务,当然都要遵守统一的API约定
2)、每一个微服务都是独立部署的,可以进行快速迭代部署,根据各自服务需求选择合适的虚拟机和使用最匹配的服务资源要求的硬件
3)、整体应用程序被分解成可管理的模块和服务,单个的服务可以更快的开发,更简单的理解和维护
4)、一些需要进行负载均衡的服务可以部署在多个云虚拟机上,加入NGINX这样的负载均衡器在多个实例之间分发请求,这样不需要整个应用进行负载均衡了
5)、每个后端服务暴露一套REST API,大部分服务调用其他服务提供的API。每个服务都有自己的数据库模式,而不是共享单个数据库模式。尽管这会造成某些数据的冗余,但是对于微服务架构这个独立的数据库模式是必要的,确保了独立服务之间的松散耦合
基于微服务的应用倾向于使用简单轻量级的协议,比如REST 而不是WS-
微服务的缺点:
1)、微服务应用作为分布式系统带来了复杂性
2)、多个独立数据库,事务的实现更具挑战性
3)、测试微服务变得复杂,当一个服务依赖另外一个服务时,测试时需要另外一个服务的支持
4)、部署基于微服务的应用也很复杂,整体应用程序部署只需要部署在一组相同的服务器上,在这些服务前面加入传统的负载均衡器即可。独立服务的需要更高的自动化形式
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: