面试题--CVTE

2.HashMap和HashSet的实现原理,hashset 和hashMap区别
HashSet底层就是HashMap实现的,
*HashMap* *HashSet*
HashMap实现了Map接口 HashSet实现了Set接口
HashMap储存键值对 HashSet仅仅存储对象
使用put()方法将元素放入map中 使用add()方法将元素放入set中
HashMap中使用键对象来计算hashcode值 HashSet使用成员对象来计算hashcode值,对于两个对象来说hashcode可能相同,所以equals()方法用来判断对象的相等性,如果两个对象不同的话,那么返回false
HashMap比较快,因为是使用唯一的键来获取对象 HashSet较HashMap来说比较慢
3.ConcurrentHashMap
HashTable是线程安全的,是给每个方法加synchronized;
4.同步方法。
(1)synchronized关键字修饰的语句块,synchronized只能标记非抽象的方法,不能标识成员变量。synchronized关键字也可以修饰静态方法,此时如果调用该静态方法,将会锁住整个类。
(2)使用特殊域变量(Volatile)实现线程同步
a.volatile关键字为域变量的访问提供了一种免锁机制
b.使用volatile修饰域相当于告诉虚拟机该域可能会被其他线程更新
c.因此每次使用该域就要重新计算,而不是使用寄存器中的值
d.volatile不会提供任何原子操作,它也不能用来修饰final类型的变量
(3)ReentrantLock类是可重入、互斥、实现了Lock接口的锁;
(4)使用ThreadLocal管理变量,则每一个使用该变量的线程都获得该变量的副本,副本之间相互独立,这样每一个线程都可以随意修改自己的变 量副本,而不会对其他线程产生影;
(5)
5.很常见的 Nullpointerexception ,你是怎么排查的,怎么解决的;
赋初值。
6.Out of MemoryError 产生的原因是什么,具体怎么去调优,以及理解那几个参数的含义 -Xms, -Xmx ,-Xmn, -XX:PermSize
内存泄露是指程序在运行过程中动态申请的内存空间不再使用后没有及时释放,从而很可能导致应用程序内存无线增长。
内存溢出即用户在对其数据缓冲区操作时,超过了其缓冲区的边界;尤其是对缓冲区写操作时,缓冲区的溢出很可能导致程序的异常。
原因:
1.内存中加载的数据量过于庞大,如一次从数据库取出过多数据;
2.集合类中有对对象的引用,使用完后未清空,使得JVM不能回收;
3.代码中存在死循环或循环产生过多重复的对象实体
4.启动参数内存值设定的过小;
调优:
1)检查代码中是否有死循环或递归调用。
2)检查是否有大循环重复产生新对象实体。
3)检查对数据库查询中,是否有一次获得全部数据的查询。一般来说,如果一次取十万条记录到内存,就可能引起内存溢出
4 )检查List、MAP等集合对象是否有使用完后,未清除的问题
5)应用服务器提示错误的解决: 把启动参数内存值设置足够大
-Xms, -Xmx 最小,最大堆大小;-Xmn新生代大小;-XX:PermSize设置永久代大小;
7.线程池的配置 Excutor 以及Connector的配置
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler)
corePoolSize,线程池里最小线程数
maximumPoolSize,线程池里最大线程数量,超过最大线程时候会使用RejectedExecutionHandler
keepAliveTime,unit,线程最大的存活时间
workerQueue,缓存异步任务的队列
threadFactory,用来构造线程池里的worker线程
8.负载均衡如何实现Seesion共享
(1)我们可以把用户访问页面产生的session放到cookie里面,就是以cookie为中转站。
(2)会话保持:Session保持是我们见到最多的名词之一,通过会话保持,负载均衡进行请求分发的时候保证每个客户端固定的访问到后端的同一台应用服务器。会话保持方案在所有的负载均衡都有对应的实现。而且这是在负载均衡这一层就可以解决Session问题。
(3)会话复制:将每个应用服务器中的Session信息复制到其它服务器节点上。(不可取)
(4)会话共享:对于Session来说,肯定是频繁使用的,虽然你可以把它存放在数据库中,但是真正生产环境中我更推荐存放在性能更快的分布式KV数据中,例如:Memcached和Redis。
10.HashMap如果有很多相同key,后面的链很长的话,你会怎么优化?或者你会用什么数据结构来存储?我说了一个SkipList
如果是hash冲突,可以通过(1)设置大一些的table值;(2)改进hashCode算法;
Skip List是一种随机化的数据结构(必须有序),基于并联的链表,其效率可比拟于二叉查找树(对于大多数操作需要O(log n)平均时间)。基本上,跳跃列表是对有序的链表增加上附加的前进链接,增加是以随机化的方式进行的,所以在列表中的查找可以快速的跳过部分列表(因此得 名)。所有操作都以对数随机化的时间进行。Skip List可以很好解决有序链表查找特定值的困难。
再向跳跃表中插入新的结点时候,我们需要生成该结点的层数,使用的就是随机数生成器,随机的生成一个层数。
11.谈一谈对volatile理解,这个问题很常见,答出要点:
可见性、防止指令重排即可
在并发编程中,我们通常会遇到以下三个问题:原子性问题,可见性问题,有序性问题。
只有简单的读取、赋值(而且必须是将数字赋值给某个变量,变量之间的相互赋值不是原子操作)才是原子操作。
1)保证了不同线程对这个变量进行操作时的可见性,即一个线程修改了某个变量的值,这新值对其他线程来说是立即可见的。
  2)禁止进行指令重排序。
3)volatile也无法保证对变量的任何操作都是原子性的。
原理:
“观察加入volatile关键字和没有加入volatile关键字时所生成的汇编代码发现,加入volatile关键字时,会多出一个lock前缀指令”
  lock前缀指令实际上相当于一个内存屏障(也成内存栅栏),内存屏障会提供3个功能:
  1)它确保指令重排序时不会把其后面的指令排到内存屏障之前的位置,也不会把前面的指令排到内存屏障的后面;即在执行到内存屏障这句指令时,在它前面的操作已经全部完成;
  2)它会强制将对缓存的修改操作立即写入主存;
  3)如果是写操作,它会导致其他CPU中对应的缓存行无效。
12.讲一下Spring的AOP和IOC理解与实际使用
spring 的优点?
1.降低了组件之间的耦合性 ,实现了软件各层之间的解耦 
2.可以使用容易提供的众多服务,如事务管理,消息服务等 
3.容器提供单例模式支持 
4.容器提供了AOP技术,利用它很容易实现如权限拦截,运行期监控等功能 
5.容器提供了众多的辅助类,能加快应用的开发 
6.spring对于主流的应用框架提供了集成支持,如hibernate,JPA,Struts等 
7.spring属于低侵入式设计,代码的污染极低 
8.独立于各种应用服务器 
9.spring的DI机制降低了业务对象替换的复杂性 
10.Spring的高度开放性,并不强制应用完全依赖于Spring,开发者可以自由选择spring的部分或全部 
 
什么是DI机制? 
依赖注入(Dependecy Injection)和控制反转(Inversion of Control)是同一个概念,具体的讲:当某个角色需要另外一个角色协助的时候,在传统的程序设计过程中,通常由调用者来创建被调用者的实例。但在spring中创建被调用者的工作不再由调用者来完成,因此称为控制反转。创建被调用者的工作由spring来完成,然后注入调用者因此也称为依赖注入。 
spring以动态灵活的方式来管理对象 , 注入的两种方式,设置注入和构造注入。 
设置注入的优点:直观,自然 
构造注入的优点:可以在构造器中决定依赖关系的顺序。 
 
什么是AOP? 
面向切面编程(AOP)完善spring的依赖注入(DI),面向切面编程在spring中主要表现为两个方面 
1.面向切面编程提供声明式事务管理 
2.spring支持用户自定义的切面 
 
面向切面编程(aop)是对面向对象编程(oop)的补充, 
面向对象编程将程序分解成各个层次的对象,面向切面编程将程序运行过程分解成各个切面。 
AOP从程序运行角度考虑程序的结构,提取业务处理过程的切面,oop是静态的抽象,aop是动态的抽象,是对应用执行过程中的步骤进行抽象,,从而获得步骤之间的逻辑划分。 
 
aop框架具有的两个特征: 
1.各个步骤之间的良好隔离性 
2.源代码无关性 
15.什么是递归,递归的几个条件?写递归要注意些什么?
程序调用自身的编程技巧称为递归。
两个条件:可以通过递归调用来缩小问题规模,且新问题与原问题有着相同的形式。
存在一种简单情境,可以使递归在简单情境下退出。
19.对后台的优化有了解吗?比如负载均衡。我给面试官说了 Ngix+Tomcat负载均衡,异步处理(消息缓冲服务器),缓存(Redis,Memcache),NoSQL,数据库优化,存储索引优化。
epoll之会把哪个流发生了怎样的I/O事件通知我们。
20.对面向对象的认识,面向对象的特征
面向对象编程强调抽象、封装、继承、多态
抽象:我们在定义一个抽象类的时候,实际上就是把一类事物共有的属性和行为提取出来,形成一个物理模型(模版),这种研究问题的方法称为抽象。
封装:就是将类的属性包装起来,用户无需知道对象内部方法的实现细节,但可以根据对象提 供的外部接口。好处可以增强模块的独立性。
继承:子类拥有父类的所有属性,和方法. 继承的好处:抽取出了重复的代码,减少代码冗余; 继承的缺点:耦合性太强
多态:一 个对象变量可以指向多种实际类型的现象。
顺便说一下重载和重写(覆盖)的区别:
重载:相同的方法名,不同的实现机制(通过传入不同个数或类型的参数)。当程序运行过程中自己去判断到底该调用谁。
重写:从父类继承而来的方法不能满足需要的情况下,可以将此方法的逻辑在子类中重新实现。我们最常用的就是重写toString()方法了。
22.java中弱引用
强引用、软引用、弱引用和虚引用
弱引用就是不保证不被垃圾回收器回收的对象,它拥有比较短暂的生命周期,在垃圾回收器扫描它所管辖的内存区域过程中,一旦发现了只具有弱引用的对象,就会回收它的内存,不过一般情况下,垃圾回收器的线程优先级很低,也就不会很快发现那些只有弱引用的对象。
弱引用可以和一个引用队列(ReferenceQueue)联合使用,如果弱引用的对象被垃圾回收的话,Java虚拟机就会把这个弱引用加入相关的引用队列中。引用队列可以很容易地实现跟踪不需要的引用。当你在构造WeakReference时传入一个ReferenceQueue对象,当该引用指向的对象被标记为垃圾的时候,这个引用对象会自动地加入到引用队列里面。
弱引用简单来说就是将对象留在内存的能力不是那么强的引用。弱引用类型可以通过get获取。
WeakHashMap和HashMap几乎一样,唯一的区别就是它的键(不是值!!!)使用WeakReference引用。
 
软引用:但是如果是软引用可以到达,那么这个对象会停留在内存更时间上长一些。当内存不足时垃圾回收器才会回收这些软引用可到达的对象。
 
虚引用:虚引用指向的对象十分脆弱,我们不可以通过get方法来得到其指向的对象。它的唯一作用就是当其指向的对象被回收之后,自己被加入到引用队列,用作记录该引用指向的对象已被销毁。虚引用只有在其指向的对象从内存中移除掉之后才会加入到引用队列中。
虚引用使用场景主要由两个。它允许你知道具体何时其引用的对象从内存中移除。第二点,虚引用可以避免很多析构时的问题。
23.数据表中有一万条数据,查询时需要几次IO
原文地址:https://www.cnblogs.com/shan1393/p/9292383.html