Alibaba interviewJava面试

【转】各大公司 Java 后端开发面试题总结

2017-06-18  本文已影响71人  王帅199207

转自:https://zhuanlan.zhihu.com/p/25575446?utm_source=qq&utm_medium=social

ThreadLocal(线程变量副本)

Synchronized实现内存共享,ThreadLocal为每个线程维护一个本地变量。

采用空间换时间,它用于线程间的数据隔离,为每一个使用该变量的线程提供一个副本,每个线程都可以独立地改变自己的副本,而不会和其他线程的副本冲突。

ThreadLocal类中维护一个Map,用于存储每一个线程的变量副本,Map中元素的键为线程对象,而值为对应线程的变量副本。

ThreadLocal在Spring中发挥着巨大的作用,在管理Request作用域中的Bean、事务管理、任务调度、AOP等模块都出现了它的身影。

Spring中绝大部分Bean都可以声明成Singleton作用域,采用ThreadLocal进行封装,因此有状态的Bean就能够以singleton的方式在多线程中正常工作了。

Java内存模型:

Java虚拟机规范中将Java运行时数据分为六种。

“你能不能谈谈,java GC是在什么时候,对什么东西,做了什么事情?”

在什么时候:
对什么东西:

从GC Roots搜索不到,而且经过一次标记清理之后仍没有复活的对象。

做什么:
GC Roots都有哪些:

ReentrantLock

Synchronized 与Lock都是可重入锁,同一个线程再次进入同步代码的时候.可以使用自己已经获取到的锁。

Synchronized是悲观锁机制,独占锁。而Locks.ReentrantLock是,每次不加锁而是假设没有冲突而去完成某项操作,如果因为冲突失败就重试,直到成功为止。

ReentrantLock适用场景

StringBuffer StringBuilder

StringBuffer是线程安全的,每次操作字符串,String会生成一个新的对象,而StringBuffer不会;StringBuilder是非线程安全的

fail-fast

fail-fast:机制是java集合(Collection)中的一种错误机制。当多个线程对同一个集合的内容进行操作时,就可能会产生fail-fast事件。

例如:当某一个线程A通过iterator去遍历某集合的过程中,若该集合的内容被其他线程所改变了;那么线程A访问集合时,就会抛出ConcurrentModificationException异常,产生fail-fast事件

happens-before

happens-before:如果两个操作之间具有happens-before 关系,那么前一个操作的结果就会对后面一个操作可见。

Volatile和Synchronized四个不同点:

volatile具备两种特性

Volatile如何保证内存可见性:

同步和异步

同步:就是一个任务的完成需要依赖另外一个任务,只有等待被依赖的任务完成后,依赖任务才能完成。

异步:不需要等待被依赖的任务完成,只是通知被依赖的任务要完成什么工作,只要自己任务完成了就算完成了,被依赖的任务是否完成会通知回来。(异步的特点就是通知)。

打电话和发短信来比喻同步和异步操作。

阻塞和非阻塞

阻塞:CPU停下来等一个慢的操作完成以后,才会接着完成其他的工作。

非阻塞:非阻塞就是在这个慢的执行时,CPU去做其他工作,等这个慢的完成后,CPU才会接着完成后续的操作。

非阻塞会造成线程切换增加,增加CPU的使用时间能不能补偿系统的切换成本需要考虑。

CAS(Compare And Swap) 无锁算法:

CAS是乐观锁技术,当多个线程尝试使用CAS同时更新同一个变量时,只有其中一个线程能更新变量的值,而其它线程都失败,失败的线程并不会被挂起,而是被告知这次竞争中失败,并可以再次尝试。CAS有3个操作数,内存值V,旧的预期值A,要修改的新值B。当且仅当预期值A和内存值V相同时,将内存值V修改为B,否则什么都不做。

线程池的作用:

在程序启动的时候就创建若干线程来响应处理,它们被称为线程池,里面的线程叫工作线程

常用线程池:ExecutorService 是主要的实现类,其中常用的有

Executors.newSingleThreadPool()newFixedThreadPool(),newcachedTheadPool(),newScheduledThreadPool()。

类加载器工作机制:

双亲委派模型:


类加载器收到类加载请求,首先将请求委派给父类加载器完成

用户自定义加载器->应用程序加载器->扩展类加载器->启动类加载器。

一致性哈希


Memcahed缓存:


数据结构:key,value对

使用方法:get,put等方法

Redis数据结构:

可以实现数据持久化

索引:B+,B-,全文索引

Mysql的索引是一个数据结构,旨在使数据库高效的查找数据。

常用的数据结构是B+Tree,每个叶子节点不但存放了索引键的相关信息还增加了指向相邻叶子节点的指针,这样就形成了带有顺序访问指针的B+Tree,做这个优化的目的是提高不同区间访问的性能。

什么时候使用索引:

  1. 经常出现在group by,order by和distinc关键字后面的字段

  2. 经常与其他表进行连接的表,在连接字段上应该建立索引

  3. 经常出现在Where子句中的字段

  4. 经常出现用作查询选择的字段

Spring IOC (控制反转,依赖注入)

Spring支持三种依赖注入方式,分别是属性(Setter方法)注入,构造注入和接口注入。

在Spring中,那些组成应用的主体及由Spring IOC容器所管理的对象被称之为Bean。

Spring的IOC容器通过反射的机制实例化Bean并建立Bean之间的依赖关系。

简单地讲,Bean就是由Spring IOC容器初始化、装配及被管理的对象。

获取Bean对象的过程,首先通过Resource加载配置文件并启动IOC容器,然后通过getBean方法获取bean对象,就可以调用他的方法。

Spring Bean的作用域

代理

代理的共有优点:业务类只需要关注业务逻辑本身,保证了业务类的重用性。

Java静态代理

代理对象和目标对象实现了相同的接口,目标对象作为代理对象的一个属性,具体接口实现中,代理对象可以在调用目标对象相应方法前后加上其他业务处理逻辑。

缺点:一个代理类只能代理一个业务类。如果业务类增加方法时,相应的代理类也要增加方法。

Java动态代理

Java动态代理是写一个类实现InvocationHandler接口,重写Invoke方法,在Invoke方法可以进行增强处理的逻辑的编写,这个公共代理类在运行的时候才能明确自己要代理的对象,同时可以实现该被代理类的方法的实现,然后在实现类方法的时候可以进行增强处理。

实际上:代理对象的方法 = 增强处理 + 被代理对象的方法

JDK和CGLIB生成动态代理类的区别

JDK动态代理只能针对实现了接口的类生成代理(实例化一个类)。此时代理对象和目标对象实现了相同的接口,目标对象作为代理对象的一个属性,具体接口实现中,可以在调用目标对象相应方法前后加上其他业务处理逻辑

CGLIB是针对类实现代理,主要是对指定的类生成一个子类(没有实例化一个类),覆盖其中的方法 。

Spring AOP应用场景

性能检测,访问控制,日志管理,事务等。

默认的策略是如果目标类实现接口,则使用JDK动态代理技术,如果目标对象没有实现接口,则默认会采用CGLIB代理

SpringMVC运行原理

Http请求

DNS域名解析 –> 发起TCP的三次握手 –> 建立TCP连接后发起http请求 –> 服务器响应http请求,浏览器得到html代码 –> 浏览器解析html代码,并请求html代码中的资源(如js、css、图片等) –> 浏览器对页面进行渲染呈现给用户

设计存储海量数据的存储系统

设计一个叫“中间层”的一个逻辑层,在这个层,将数据库的海量数据抓出来,做成缓存,运行在服务器的内存中,同理,当有新的数据到来,也先做成缓存,再想办法,持久化到数据库中,这是一个简单的思路。主要的步骤是负载均衡,将不同用户的请求分发到不同的处理节点上,然后先存入缓存,定时向主数据库更新数据。读写的过程采用类似乐观锁的机制,可以一直读(在写数据的时候也可以),但是每次读的时候会有个版本的标记,如果本次读的版本低于缓存的版本,会重新读数据,这样的情况并不多,可以忍受。

Session与Cookie

Cookie可以让服务端跟踪每个客户端的访问,但是每次客户端的访问都必须传回这些Cookie,如果Cookie很多,则无形的增加了客户端与服务端的数据传输量,

而Session则很好地解决了这个问题,同一个客户端每次和服务端交互时,将数据存储通过Session到服务端,不需要每次都传回所有的Cookie值,而是传回一个ID,每个客户端第一次访问服务器生成的唯一的ID,客户端只要传回这个ID就行了,这个ID通常为NAME为JSESSIONID的一个Cookie。这样服务端就可以通过这个ID,来将存储到服务端的KV值取出了。

Session和Cookie的超时问题,Cookie的安全问题

分布式Session框架

  1. 配置服务器,Zookeeper集群管理服务器可以统一管理所有服务器的配置文件

  2. 共享这些Session存储在一个分布式缓存中,可以随时写入和读取,而且性能要很好,如Memcache,Tair。

  3. 封装一个类继承自HttpSession,将session存入到这个类中然后再存入分布式缓存中

  4. 由于Cookie不能跨域访问,要实现Session同步,要同步SessionID写到不同域名下。

适配器模式

将一个接口适配到另一个接口,Java I/O中InputStreamReader将Reader类适配到InputStream,从而实现了字节流到字符流的准换。

装饰者模式

保持原来的接口,增强原来有的功能。

FileInputStream 实现了InputStream的所有接口,BufferedInputStreams继承自FileInputStream是具体的装饰器实现者,将InputStream读取的内容保存在内存中,而提高读取的性能。

Spring事务配置方法

Spring通过aop/tx Schema 命名空间和@Transaction注解技术来进行声明式事物配置。

Mybatis

每一个Mybatis的应用程序都以一个SqlSessionFactory对象的实例为核心。首先用字节流通过Resource将配置文件读入,然后通过SqlSessionFactoryBuilder().build方法创建SqlSessionFactory,然后再通过sqlSessionFactory.openSession()方法创建一个sqlSession为每一个数据库事务服务。

经历了Mybatis初始化 –>创建SqlSession –>运行SQL语句 返回结果三个过程

Servlet和Filter的区别

整的流程是:Filter对用户请求进行预处理,接着将请求交给Servlet进行处理并生成响应,最后Filter再对服务器响应进行后处理。

Filter有如下几个用处:

实际上Filter和Servlet极其相似,区别只是Filter不能直接对用户生成响应。实际上Filter里doFilter()方法里的代码就是从多个Servlet的service()方法里抽取的通用代码,通过使用Filter可以实现更好的复用。

Filter和Servlet的生命周期

HashMap与HashTable的区别

HashMap的实现机制

HashMap和TreeMap区别

HashMap,ConcurrentHashMap与LinkedHashMap的区别

ConcurrentHashMap应用场景

ConcurrentHashMap把HashMap分成若干个Segmenet

Vector和ArrayList的区别

线程池

ExecutorService service = Executors….

ExecutorService service = new ThreadPoolExecutor()

ExecutorService service = new ScheduledThreadPoolExecutor();

ThreadPoolExecutor 的内部工作原理

有了以上定义好的数据,下面来看看内部是如何实现的 。 Doug Lea 的整个思路总结起来就是 5 句话:

Executor包结构

CopyOnWriteArrayList

写时加锁,当添加一个元素的时候,将原来的容器进行copy,复制出一个新的容器,然后在新的容器里面写,写完之后再将原容器的引用指向新的容器,而读的时候是读旧容器的数据,所以可以进行并发的读,但这是一种弱一致性的策略。

使用场景:CopyOnWriteArrayList适合使用在读操作远远大于写操作的场景里,比如缓存。

Linux常用命令

cd,cp,mv,rm,ps(进程),tar,cat(查看内容),chmod,vim,find,ls

死锁的必要条件

解决死锁,第一个是死锁预防,就是不让上面的四个条件同时成立。二是,合理分配资源。

三是使用银行家算法,如果该进程请求的资源操作系统剩余量可以满足,那么就分配。

进程间的通信方式

数据库事务

数据库事务是指作为单个逻辑工作单元执行的一系列操作。

Hibernate的一级缓存是由Session提供的,因此它只存在于Session的生命周期中,当程序调用save(),update(),saveOrUpdate()等方法 及调用查询接口list,filter,iterate时,如Session缓存中还不存在相应的对象,Hibernate会把该对象加入到一级缓存中,当Session关闭的时候缓存也会消失。

Hibernate的一级缓存是Session所内置的,不能被卸载,也不能进行任何配置一级缓存采用的是key-value的Map方式来实现的,在缓存实体对象时,对象的主关键字ID是Map的key,实体对象就是对应的值。

Hibernate二级缓存:把获得的所有数据对象根据ID放入到第二级缓存中。Hibernate二级缓存策略,是针对于ID查询的缓存策略,删除、更新、增加数据的时候,同时更新缓存。

上一篇 下一篇

猜你喜欢

热点阅读