Java 面试必备

 1. Object有哪些方法?
clone,实现对象的浅复制。
getClass,final方法,得到运行时类型。
toString,该方法用得比较多,通常子类都有覆盖。
finalize,该方法用于释放资源。由于没法肯定该方法何时被调用,不多使用。
equals,该方法是很是重要的一个方法。通常equals和==是不同的,可是在Object中二者是同样的。子类通常都要重写这个方法。
hashCode,该方法用于哈希查找,重写了equals方法通常都要重写hashCode方法。这个方法在一些具备哈希功能的Collection中用到。通常必须知足obj1.equals(obj2)==true。能够推出obj1.hash- Code()==obj2.hashCode(),可是hashCode相等不必定就知足equals。不过为了提升效率,应该尽可能使上面两个条件接近等价。
wait,wait方法就是使当前线程等待该对象的锁,当前线程必须是该对象的拥有者,也就是具备该对象的锁。wait()方法一直等待,直到得到锁或者被中断。wait(long timeout)设定一个超时间隔,若是在规定时间内没有得到锁就返回。
notify,该方法唤醒在该对象上等待的某个线程。
notifyAll,该方法唤醒在该对象上等待的全部线程。前端

 2. 类的初始化顺序?
Static Field Initial (静态变量) 
Static Patch Initial (静态初始化块) 
Field Initial (变量)
Field Patch Initial (初始化块)
Structure Initial (构造器)java

 3. Map有哪些实现类?
HashMap无序的
LinkedHashMap 有序的
TreeMap 默认升序。mysql

 4. HashMap的工做原理
HashMap使用数组和链表的形式存储数据。
HashMap基于hashing原理,咱们经过put()和get()方法储存和获取对象。当咱们将键值对传递给put()方法时,它调用键对象的hashCode()方法来计算hashcode,让后找到bucket位置来储存值对象。当获取对象时,经过键对象的equals()方法找到正确的键值对,而后返回值对象。HashMap使用链表来解决碰撞问题,当发生碰撞了,对象将会储存在链表的下一个节点中。 HashMap在每一个链表节点中储存键值对对象。web

 5. HashMap、HashTable的区别?
HashMap是HashTable的轻量级实现(非线程安全的实现),他们都完成了Map接口。主要的区别有:线程安全性,同步(synchronization),以及速度。redis

 6. 放入HashMap中的类需重写哪些方法?
使用HashMap,若是key是自定义的类,就必须重写hashcode()和equals()。算法

 7. ConcurrentHashMap和HashTable的区别?
HashTable(同一把锁):使用synchronized来保证线程安全,但效率很是低下。当一个线程访问同步方法时,其余线程也访问同步方法,可能会进入阻塞或轮询状态,如使用put添加元素,另外一个线程不能使用put添加元素,也不能使用get,竞争会愈来愈激烈效率越低。
ConcurrentHashMap(分段锁):(锁分段技术)每一把锁只锁容器其中一部分数据,多线程访问容器里不一样数据段的数据,就不会存在锁竞争,提升并发访问率。
首先将数据分为一段一段的存储,而后给每一段数据配一把锁,当一个线程占用锁访问其中一个段数据时,其余段的数据也能被其余线程访问。ConcurrentHashMap是由Segment数组结构和HahEntry数组结构组成。Segment是一种可重入锁ReentrantLock,扮演锁的角色。HashEntry用于存储键值对数据。一个ConcurrentHashMap里包含一个Segment数组。Segment的结构和Hashmap相似,是一种数组和链表结构,一个Segment包含一个HashEntry数组,每一个HashEntry是一个链表结构的元素,每一个Segment守护着一个HashEntry数组里的元素,当对HashEntry数组的数据进行修改时,必须首先得到对应的Segment。spring

 8. ConcurrentHashMap的并发度是什么?
ConcurrentHashMap的并发度就是Segment的大小,默认为16。sql

 9. HashMap、HashTable、ConcurrentHashMap的区别?
HashMap 和 HashTable的父类不一样,HashMap是AbstMap,HashTable是Dictionary类。
HashMap的初始容量16,HashTable初始容量11。
HashMap扩容机制必须是2的倍数,HashTable不须要。
线程安全性,HashMap线程不安全,HashTable线程安全。
HashMap容许null ,HashTable不容许null。
遍历方式也不一样HashMap使用Iterator,HashTableEnumeration
计算hash值的方法不一样 ConcurrentHashMap也是线程安全的HashMap实现的一种;使用cas操做来修改以保证数据的原子性。数据库

 10. TCP、UDP的区别?
TCP是面向链接的,UDP是面向报文的(即发送的时候不须要创建链接)。
TCP是提供可靠服务的,请求有序,UDP尽最大努力交付,不保证服务可靠。
TCP能有拥塞控制,UDP没有拥塞控制。
TCP是点对点,UDP能够1对1,1对多,多对1通讯。
TCP首部开销20字节,UDP只有8。编程

 11. POST、GET的区别?
GET数据传输是,只容许ASCII,参数位于URL上,URL最大长度限制2k,重复提交无害,可为书签,能够被缓存,因此安全性差。
POST容许二进制数据使用多重编码,参数位于请求体重,没有最大长度限制,提交有害,不可为书签也不能被缓存,安全性较高。
POST两次TCP请求,GET一次TCP请求。

 12. 如何高效安全地删除一个List中的一个元素?
循环删除List中多个元素的,应该使用迭代器Iterator方式。

 13. 字节流和字符流的区别和联系?
字节流在操做的时候自己是不会用到缓冲区(内存)的,是与文件自己直接操做的,而字符流在操做的时候是使用到缓冲区的。字节流在操做文件时,即便不关闭资源(close方法),文件也能输出,可是若是字符流不使用close方法的话,则不会输出任何内容,说明字符流用的是缓冲区,而且可使用flush方法强制进行刷新缓冲区,这时才能在不close的状况下输出内容。

 14. 线程安全的含义? 
就是线程同步的意思,就是当一个程序对一个线程安全的方法或者语句进行访问的时候,其余的不能再对他进行操做了,必须等到此次访问结束之后才能对这个线程安全的方法进行访问。
synchronized修饰的方法或者代码块,全部加上synchronized和块语句,在多线程访问的时候,同一时刻只能有一个线程可以用。
volatile修饰的变量,线程在每次使用变量的时候,都会读取变量修改后的最的值。volatile很容易被误用,用来进行原子性操做。

 15. Thread和Runnable如何使用写段小代码
 Thread

public class Example {
	public static void main(String[] args){
		MyThread myThread=new MyThread();
		myThread.start(); 
		while (true){ 
			System.out.println("Main方法在运行");
		}
	}
 }

public class MyThread extends Thread{
	public void run(){                                                                                
		while(true){
			System.out.println("MyThread类的run()方法在运行");
		}
	}
 }

 Runnable

public class Example {
	public static void main(String[] args){
		MyThread myThread=new MyThread(); 
		Thread thread=new Thread(myThread);
		thread.start();
		while (true){
			System.out.println("Main方法在运行");
		}
	} 
} 

public class MyThread implements Runnable{
	public void run(){                                                                                
		while(true){
			System.out.println("MyThread类的run()方法在运行");
		}
	}
}

16. Synchronized和Lock类的区别?
Synchronized
存在层次:是Java的关键字,在jvm层面上。
锁的释放:以获取锁的线程执行完同步代码,释放锁,线程执行发生异常,jvm会让线程释放锁。
锁的获取:假设A线程得到锁,B线程等待。若是A线程阻塞,B线程会一直等待。
锁状态:没法判断。
锁类型:可重入、不可中断、非公平。
性能:少许同步。
Lock
存在层次:是Java的关键字,在jvm层面上;Lock是一个类。
锁的释放:在finally中必须释放锁,否则容易形成线程死锁。
锁的获取:分状况而定,Lock有多个锁获取的方式,具体下面会说道,大体就是能够尝试得到锁,线程能够不用一直等待。
锁状态:能够判断。
锁类型:可重入、可判断、可公平(二者皆可)。
性能:大量同步。
 
 17. CountDownLatch和CyclicBarrier的区别?
 CountDownLatch
 减计数方式。
 计算为0时释放全部等待的线程。
 计数为0时,没法重置。
 调用countDown()方法计数减一,调用await()方法只进行阻塞,对计数没任何影响。
 不可重复利用。
 CyclicBarrier
 加计数方式。
 计数达到指定值时释放全部等待线程。
 计数达到指定值时,计数置为0从新开始。
 调用await()方法计数加1,若加1后的值不等于构造方法的值,则线程阻塞。
 可重复利用。
 
 18. ThreadLocal和Executors的用途、原理、用法?
 ThreadLocal是线程的局部变量,是每个线程所单独持有的,其余线程不能对其进行访问。当使用ThreadLocal维护变量的时候为每个使用该变量的线程提供一个独立的变量副本,即每一个线程内部都会有一个该变量,这样同时多个线程访问该变量并不会彼此相互影响,所以他们使用的都是本身从内存中拷贝过来的变量的副本,这样就不存在线程安全问题,也不会影响程序的执行性能。
 Executors提供四种线程池:
 newCachedThreadPool建立一个可缓存线程池,若是线程池长度超过处理须要,可灵活回收空闲线程,若无可回收,则新建线程。
 newFixedThreadPool建立一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。
 newScheduledThreadPool建立一个定长线程池,支持定时及周期性任务执行。
 newSingleThreadExecutor建立一个单线程化的线程池,它只会用惟一的工做线程来执行任务,保证全部任务按照指定顺序(FIFO,LIFO,优先级)执行。
 
 19. 类的加载过程?
 首先经过一个类的全限定名来获取此类的二进制字节流;其次将这个字节流所表明的静态存储结构转化为方法区的运行时数据结构;最后在java堆中生成一个表明这个类的Class对象,做为方法区这些数据的访问入口。
 总的来讲就是查找并加载类的二进制数据。
 
 20. GC经常使用算法?
 串行收集器(SerialGC)最古老的垃圾回收算法,是之前运行在单核cpu的服务器下的。新生代、老年代都使用串行算法回收。
 并行垃圾回收器(ParallelGC)采用多线程的机制是执行GC操做,因此执行GC过程阻塞时间较短。新生代采用的是并行算法,而老年代依然采用的是串行算法。
 并发标记扫描垃圾回收器(ConcurrentMarkSweep)是应用程序线程和GC线程交替执行。使用的标记-清除算法,并发阶段会下降吞吐量。它常常被用在那些对于响应时间要求十分苛刻的应用之上。
 G1收集器垃圾回收器适用于堆内存很大的状况,他将堆内存分割成不一样的区域,而且并发的对其进行垃圾回收。G1也能够在回收内存以后对剩余的堆内存空间进行压缩。并发扫描标记垃圾回收器在STW状况下压缩内存。G1垃圾回收会优先选择第一块垃圾最多的区域。
 
 21. JVM调优步骤
第1步:分析GC日志及dump文件,判断是否须要优化,肯定瓶颈问题点;
第2步:肯定JVM调优量化目标;
第3步:肯定JVM调优参数(根据历史JVM参数来调整);
第4步:调优一台服务器,对比观察调优先后的差别;
第5步:不断的分析和调整,直到找到合适的JVM参数配置;
第6步:找到最合适的参数,将这些参数应用到全部服务器,并进行后续跟踪。

 22. OOM
 内存泄露:申请使用完的内存没有释放,致使虚拟机不能再次使用该内存,此时这段内存就泄露了,由于申请者不用了,而又不能被虚拟机分配给别人用。
 内存溢出:申请的内存超出了JVM能提供的内存大小,此时称之为溢出
 jstack、jmap能够定位到线程堆栈,根据堆栈信息咱们能够定位到具体代码,因此它在JVM性能调优中使用得很是多。
 
 23. SpringMVC执行流程及原理?
 用户发起请求到前端控制器(DispatcherServlet),该控制器会过滤出哪些请求能够访问Servlet、哪些不能访问。就是url-pattern的做用,而且会加载SpringMVC.xml配置文件。
 前端控制器会找处处理器映射器(HandlerMapping),经过HandlerMapping完成url到controller映射的组件,简单来讲,就是将在SpringMVC.xml中配置的或者注解的url与对应的处理类找到并进行存储,用Map这样的方式来存储。
 HandlerMapping有了映射关系,而且找到url对应的处理器,HandlerMapping就会将其处理器(Handler)返回,在返回前,会加上不少拦截器。
 DispatcherServlet拿到Handler后,找到HandlerAdapter(处理器适配器),经过它来访问处理器,并执行处理器。
 执行处理器会返回一个ModelAndView对象给HandlerAdapter。
 经过HandlerAdapter将ModelAndView对象返回给前端控制器(DispatcherServlet)。
 前端控制器请求视图解析器(ViewResolver)去进行视图解析,根据逻辑视图名解析成真正的视图(jsp),其实就是将ModelAndView对象中存放视图的名称进行查找,找到对应的页面造成视图对象,返回视图对象到前端控制器。
 视图渲染,就是将ModelAndView对象中的数据放到request域中,用来让页面加载数据的。
 
 24. 依赖注入是什么?
 依赖注入(DependencyInjection)和控制反转(InversionofControl)是同一个概念。具体含义是:当某个角色(多是一个Java实例,调用者)须要另外一个角色(另外一个Java实例,被调用者)的协助时,在传统的程序设计过程当中,一般由调用者来建立被调用者的实例。但在Spring里,建立被调用者的工做再也不由调用者来完成,所以称为控制反转;建立被调用者实例的工做一般由Spring容器来完成,而后注入调用者,所以也称为依赖注入。

 25. 用静态方法写测试用例时如何获取服务的实例
 继承AbstractJUnit4SpringContextTests。
 引入ApplicationContext。
 
 26. Bean注入后执行初始化代码的途径
 能够在XML配置bean时,指定init-method属性便可。
 须要在须要执行的方法上添加@PostConstruct注解便可。
 
 27. LeftJoin、RightJoin用法与做用?
LeftJoin(左链接)返回包括左表中的全部记录和右表中联结字段相等的记录。
RightJoin(右链接)返回包括右表中的全部记录和左表中联结字段相等的记录。
InnerJoin(等值链接)只返回两个表中联结字段相等的行。

 28. MySQL执行计划是什么?
 explain
 
 29. 什么状况会致使索引失效?
 条件中有or。
 对于多列索引,不是使用的第一部分,则不会使用索引。
 like查询是以%开头。
 若是列类型是字符串,那必定要在条件中将数据使用引号引用起来,不然不使用索引。
 
 30. ACID的概念
 原子性(atomicity),就是说这个事务要么不执行,要么所有执行,就是上面2条语句,不容许只执行一条而不执行次日语句的状况发生。
 一致性(consistency),就是说数据库从一个一致性状态转移到另外一个一致性状态,怎么理解呢,原子性是表示不容许只执行一条而不执行第二条的状况发生,那么一致性就是说要么第一条第二条都执行成功(所谓执行成功就是对数据库持久化数据产生了影响),要么就第一条第二条都执行失败(都不对数据库持久化数据产生影响),不容许一条成功,一条失败的状况。
 隔离性(isolation)理解隔离性,就是隔离另外一个线程(事务)的操做,好比线程A正在执行这个事务cars_Beijing–,cars_Shanghai++,线程B则正在查询cars_Beijing和cars_Shanghai的值,隔离性就要保证线程B只能查询到事务彻底没有执行或者彻底成功执行的值,不容许线程B查询到只执行了cars_Beijing–而没有执行cars_Shanghai++的值。
 持久性(durability),这个比较好理解,就是事务一旦提交,所修改的数据就被持久化,即便掉电也不会丢失。
 
 31. 事务的隔离级别
 未提交读(readuncommitted),就是不作隔离控制,能够读到“脏数据”,好比上面的cars_Beijing–,cars_Shanghai++,这个隔离级别容许其余线程读取到只作了cars_Beijing–而没有作cars_Shanghai++时候的值。显然这个隔离级别没有太大意义,现实中没有人会用,除非这个应用只有读取,没有任何写入。
 提交读(readcommitted),提交读就是不容许读取事务没有提交的数据,简单的说,就是上面的cars_Beijing–,cars_Shanghai++,不容许读取到只作了cars_Beijing–,而没有作cars_Shanghai++的记录。这个隔离级别是大多数数据库(除了mysql)的默认隔离级别。
 可重复读(repeatableread),什么是不可重复读,就是事务A去作cars_Beijing–,cars_Shanghai++以前,事务B启动了,先读取了一次事务A要修改的值,这个时候事务A修改了记录,可是事务B在事务A修改完后又读取了同一记录值,显然,这致使事务B相同的读取操做却读取了不一样值,这就是不可重复读。可重复读就是禁止这种状况发生,好比对须要修改的数据加排他锁,事务B须要读取这个记录,那么整个事务B没有完成以前,都容许事务A启动。可重复读的隔离级别是mysql默认的隔离级别。
 可串行化(serialzable),就是多个线程(事务)彻底不并发,串行执行,固然不会有任何隔离问题,显而易见效率也最低,通常不采用。
 
 32. 单例有哪些实现方式?最安全简洁是哪一种?
 饿汉模式(线程安全,调用效率高,可是不能延时加载)
 懒汉模式(线程安全,调用效率不高,可是能延时加载)
 双重检测锁模式(因为JVM底层模型缘由,偶尔会出问题,不建议使用)
 静态内部类式(线程安全,调用效率高,能够延时加载)
 枚举类(线程安全,调用效率高,不能延时加载,能够自然的防止反射和反序列化调用)
 
 33. Redis有哪些数据结构?
 字符串String、字典Hash、列表List、集合Set、有序集合SortedSet。
 
 34. 使用过Redis分布式锁么,它是什么回事?
 先拿setnx来争抢锁,抢到以后,再用expire给锁加一个过时时间防止锁忘记了释放。set指令有很是复杂的参数,这个应该是能够同时把setnx和expire合成一条指令来用的。
 
 35. 假如Redis里面有1亿个key,其中有10w个key是以某个固定的已知的前缀开头的,若是将它们所有找出来?
 使用keys指令能够扫出指定模式的key列表。redis的单线程的。keys指令会致使线程阻塞一段时间,线上服务会停顿,直到指令执行完毕,服务才能恢复。
 
 36. Redis如何作持久化的?
 bgsave作镜像全量持久化,aof作增量持久化。由于bgsave会耗费较长时间,不够实时,在停机的时候会致使大量丢失数据,因此须要aof来配合使用。在redis实例重启时,会使用bgsave持久化文件从新构建内存,再使用aof重放近期的操做指令来实现完整恢复重启以前的状态。
 
 37. bgsave的原理是什么?
 fork和cow。fork是指redis经过建立子进程来进行bgsave操做,cow指的是copyonwrite,子进程建立后,父子进程共享数据段,父进程继续提供读写服务,写脏的页面数据会逐渐和子进程分离开来。
 
 38. 是否使用过Redis集群,集群的原理是什么?
 RedisSentinal着眼于高可用,在master宕机时会自动将slave提高为master,继续提供服务。
 RedisCluster着眼于扩展性,在单个redis内存不足时,使用Cluster进行分片存储。
 
 39. Redis的同步机制?
 Redis可使用主从同步,从从同步。第一次同步时,主节点作一次bgsave,并同时将后续修改操做记录到内存buffer,待完成后将rdb文件全量同步到复制节点,复制节点接受完成后将rdb镜像加载到内存。加载完成后,再通知主节点将期间修改的操做记录同步到复制节点进行重放就完成了同步过程。
 
 40. Dubbo默认使用的是什么通讯框架?
 Netty
 
 41. Dubbo的序列化?
 dubbo序列化,阿里尚不成熟的java序列化实现。
 hessian2序列化:hessian是一种跨语言的高效二进制的序列化方式,但这里实际不是原生的hessian2序列化,而是阿里修改过的hessianlite,它是dubboRPC默认启用的序列化方式。
 json序列化:目前有两种实现,一种是采用的阿里的fastjson库,另外一种是采用dubbo中自已实现的简单json库,通常状况下,json这种文本序列化性能不如二进制序列化。
 java序列化:主要是采用JDK自带的java序列化实现,性能很不理想。
 
 42. Dubbo的调用关系?
 提供者启动时,向注册中心注册本身提供的服务。
 消费者启动时,向注册中心订阅本身所需的服务。
 注册中心返回提供者地址列表给消费者,若是有变动,注册中心将基于长链接推送变动数据给消费者。
 消费者,从远程接口列表中,调用远程接口,dubbo会基于负载均衡算法,选一台提供者进行调用,若是调用失败则选择另外一台。
 消费者和提供者,在内存中累计调用次数和调用时间,定时每分钟发送一次统计数据到监控中心。
 
 43. Dubbo中ZooKeeper作注册中心,若是注册中心集群都挂掉,发布者和订阅者之间还能通讯么?
 注册中心对等集群,任意一台宕掉后,会自动切换到另外一台。
 注册中心所有宕掉,服务提供者和消费者仍能够经过本地缓存通信。
 服务提供者无状态,任一台宕机后,不影响使用。
 服务提供者所有宕机,服务消费者会没法使用,并没有限次重连等待服务者恢复。
 
 44. Dubbo在安全机制方面是如何解决的?
 Dubbo经过Token令牌防止用户绕过注册中心直连,而后在注册中心上管理受权。Dubbo还提供服务黑白名单,来控制服务所容许的调用方。
 
 45. Dubbo超时和重连机制?
 Dubbo启动时默认有重试机制和超时机制。
 超时机制的规则是若是在必定的时间内,provider没有返回,则认为本次调用失败,重试机制在出现调用失败时,会再次调用。若是在配置的调用次数内都失败,则认为这次请求异常,抛出异常。
 
 46. 几个经常使用类的区别?
 ArrayList:元素单个,效率高,多用于查询。
 Vector:元素单个,线程安全,多用于查询。
 LinkedList:元素单个,多用于插入和删除。
 HashMap:元素成对,元素可为空。
 HashTable:元素成对,线程安全,元素不可为空。
 
 47. IO与NIO的区别?
 NIO即NewIO,这个库是在JDK1.4中才引入的。NIO和IO有相同的做用和目的,但实现方式不一样,NIO主要用到的是块,因此NIO的效率要比IO高不少。在JavaAPI中提供了两套NIO,一套是针对标准输入输出NIO,另外一套就是网络编程NIO。
 IO:面向流,阻塞IO。
 NIO:面向缓冲,非阻塞IO。
 
 48. TCP/IP协议三次握手?
 第一次握手:创建链接时,客户端发送syn包(syn=j)到服务器,并进入SYN_SEND状态,等待服务器确认;SYN:同步序列编号(SynchronizeSequenceNumbers)。
 第二次握手:服务器收到syn包,必须确认客户的SYN(ack=j+1),同时本身也发送一个SYN包(syn=k),即SYN+ACK包,此时服务器进入SYN_RECV状态。
 第三次握手:客户端收到服务器的SYN+ACK包,向服务器发送确认包ACK(ack=k+1),此包发送完毕,客户端和服务器进入ESTABLISHED状态,完成三次握手。
 完成三次握手,客户端与服务器开始传送数据。
 
 49. SpringBoot是什么?
 用来简化Spring应用的初始搭建以及开发过程,使用特定的方式来进行配置(properties或yml文件)
 建立独立的Spring引用程序main方法运行。
 嵌入的Tomcat无需部署war文件。
 简化Maven配置。
 自动配置Spring添加对应功能Starter自动化配置。
 
 50. SpringBoot经常使用的Starter有哪些?
 spring-boot-starter-web:tomcat和web开发须要servlet与jsp支持。
 spring-boot-starter-data-jpa:数据库支持。
 spring-boot-starter-data-redis:redis数据库支持。
 spring-boot-starter-data-solr:solr支持。
 mybatis-spring-boot-starter:第三方的MyBatis集成Starter。
 
 51. SpringBoot自动配置的原理?
 在Spring程序main方法中添加@SpringBootApplication或者@EnableAutoConfiguration会自动去Maven中读取每一个Starter中的spring.factories文件该文件里配置了全部须要被建立Spring容器中的bean。
 
 52. SpringBoot读取配置文件的方式?
 SpringBoot默认读取配置文件为application.properties或者是application.yml。
 
 53. SpringBoot集成MyBatis的过程?
 添加MyBatis的依赖:

<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>1.2.0</version>
</dependency>`

 54. MySQL数据库引擎MYISAM和INNODB区别?
 **InnoDB**
 具备事务(commit)、回滚(rollback)。
 支持外键。
 InnoDB中不保存表的具体行数,获取行数全表扫描。
 支持行锁。
 适用于须要事务支持的场景。
 **MyISAM**
 不具备事务(commit)、回滚(rollback)。
 不支持外键。
 直接获取行数。
 不支持行锁,插入和更新锁全表读多写少,而且不须要事务支持的场景。
 
 55. 哪些状况FullGC?
 SystemGC。
 老年代空间不足。
 永久代空间不足。
 MinorGC晋升大小大于老年代剩余大小。
 堆中分配大对象,老年代装不下的时候。
 CMS出发FullGC的两种状况,年轻代晋升老年代没有足够的连续空间,或者在CMS并发收集未完成以前老年代就已经满了。
 
 56. Tomcat调优方案?
 **工做方式选择**
 为了提高性能,首先就要对代码进行动静分离,让Tomcat只负责jsp文件的解析工做。如采用Apache和Tomcat的整合方式,他们之间的链接方案有三种选择,JK、http_proxy和ajp_proxy。相对于JK的链接方式,后两种在配置上比较简单的,灵活性方面也一点都不逊色。但就稳定性而言不像JK这样久经考验,因此建议采用JK的链接方式。
 **Connector链接器的配置**
 以前文件介绍过的Tomcat链接器的三种方式:bio、nio和apr,三种方式性能差异很大,apr的性能最优,bio的性能最差。而Tomcat7使用的Connector默认就启用的Apr协议,但须要系统安装Apr库,不然就会使用bio方式。
 **配置文件优化**
 默认配置下,Tomcat会为每一个链接器建立一个绑定的线程池(最大线程数200),服务启动时,默认建立了5个空闲线程随时等待用户请求。
 **JVM优化**
 Tomcat启动命令行中的优化参数,就是JVM的优化。Tomcat首先跑在JVM之上的,由于它的启动其实也只是一个java命令行,首先咱们须要对这个JAVA的启动命令行进行调优。无论是YGC仍是FullGC,GC过程当中都会对致使程序运行中中断,正确的选择不一样的GC策略,调整JVM、GC的参数,能够极大的减小因为GC工做,而致使的程序运行中断方面的问题,进而适当的提升Java程序的工做效率。可是调整GC是以个极为复杂的过程,因为各个程序具有不一样的特色,如:web和GUI程序就有很大区别(Web能够适当的停顿,但GUI停顿是客户没法接受的),并且因为跑在各个机器上的配置不一样(主要cup个数,内存不一样),因此使用的GC种类也会不一样。
 
 57. 有三个线程T1 T2 T3,如何保证他们按顺序执?
> public class TestJoin {
>    public static void main(String[] args) throws InterruptedException {
>        final Thread t1 = new Thread(new Runnable() {
>            public void run() {
>                System.out.println(Thread.currentThread().getName() + " run 1");
>            }
>        }, "T1");
>        final Thread t2 = new Thread(new Runnable() {
>            public void run() {
>                System.out.println(Thread.currentThread().getName() + " run 2");
>                try {
>                    t1.join(10);
>                } catch (InterruptedException e) {
>                    e.printStackTrace();
>                }
>            }
>        }, "T2");
>        final Thread t3 = new Thread(new Runnable() {
>            public void run() {
>                System.out.println(Thread.currentThread().getName() + " run 3");
>                try {
>                    t2.join(10);
>                } catch (InterruptedException e) {
>                    e.printStackTrace();
>                }
>            }
>        }, "T3");
>        //method1
>        //t1.start();
>        //t2.start();
>        //t3.start();
>        //method 2 使用 单个任务的线程池来实现。保证线程的依次执行
>        ExecutorService executor = Executors.newSingleThreadExecutor();
>        executor.submit(t1);
>        executor.submit(t2);
>        executor.submit(t3);
>        executor.shutdown();
>    }
>}

 58. 缓存优化  缓存雪崩:  多是由于数据未加载到缓存中,或者缓存同一时间大面积的失效,从而致使全部请求都去查数据库,致使数据库CPU和内存负载太高,甚至宕机。解决思路:加锁计数(即限制并发的数量,能够用semphore)或者起必定数量的队列来避免缓存失效时大量请求并发到数据库。但这种方式会下降吞吐量。分析用户行为,而后失效时间均匀分布。或者在失效时间的基础上再加1~5分钟的随机数。若是是某台缓存服务器宕机,则考虑作主备。  缓存穿透:  指用户查询数据,在数据库没有,天然在缓存中也不会有。这样就致使用户查询的时候,在缓存中找不到,每次都要去数据库中查询。解决思路:若是查询数据库也为空,直接设置一个默认值存放到缓存,这样第二次到缓冲中获取就有值了,而不会继续访问数据库。设置一个过时时间或者当有值的时候将缓存中的值替换掉便可。能够给key设置一些格式规则,而后查询以前先过滤掉不符合规则的Key。  缓存并发:  若是网站并发访问高,一个缓存若是失效,可能出现多个进程同时查询DB,同时设置缓存的状况,若是并发确实很大,这也可能形成DB压力过大,还有缓存频繁更新的问题。解决思路:对缓存查询加锁,若是KEY不存在,就加锁,而后查DB入缓存,而后解锁;其余进程若是发现有锁就等待,而后等解锁后返回数据或者进入DB查询。  缓存预热:  目的就是在系统上线前,将数据加载到缓存中。解决思路:数据量不大的话,在系统启动的时候直接加载。本身写个简单的缓存预热程序。    59. 缓存算法  FIFO算法:First in First out,先进先出。原则:一个数据最早进入缓存中,则应该最先淘汰掉。也就是说,当缓存满的时候,应当把最早进入缓存的数据给淘汰掉。  LFU算法:Least Frequently Used,最不常用算法。  LRU算法:Least Recently Used,近期最少使用算法。  LRU和LFU的区别。LFU算法是根据在一段时间里数据项被使用的次数选择出最少使用的数据项,即根据使用次数的差别来决定。而LRU是根据使用时间的差别来决定的。    60. 高并发、大流量处理及解决方法?  扩容、动静分离、缓存、服务降级和限流。  **限流的经常使用算法和实践思路**  令牌桶算法:  主要限制流量的流入速率,容许出现必定程度的突发流量。 每秒会有r个令牌按照固定速率放入桶中。桶的容量是固定不变的,若是桶满了再放入令牌,则溢出。若桶中的可用令牌不足,则改请求会被进行限流处理(被抛弃或缓存)。 漏桶算法: 主要限制流量的流出速率,而且流出速率是固定不变的  能够以任意速率向桶中流入水滴。桶的容量是固定不变的,若是桶满了则溢出。按照固定的速率从桶中流出水滴。 计数器算法: 生产环境中的商品抢购可使用,具体不一样的sku限流规则配置在配置中心内,支持动态更改。可抢购次数的扣减操做,既能够用redis,也能够用JVM。若是是集群而且选择用JVM,则要根据总并发数量除以集群数量,得出单台机器的并发数。(好比总并发数5000,集群机器10台,则每台机器的并发为5000/10=500)。 **高并发读需求** 对于一件抢购商品的流量来讲,由于key是同一个,因此流量必然会都引入到同一个redis缓存节点中,这时就容易出现单点故障。所以有下面两种解决方式:在每一个master节点都挂slave从节点,当主节点挂了能够自动顶上。多级Cache方案,多用LocalCache来过滤掉一部分流量。  本地缓存通常只缓存一些热点商品数据,缓存内容通常是商品详情和商品库存。  本地缓存跟分布式缓存的同步通常有两种方式:一种是定时主动拉取更新策略。这种会存在必定时间的不一致,要视业务状况而定,例如库存,暂时的不一致致使超卖,单到真正下单的时候还会再进行库存的判断,因此影响较小,能够接受。这种方式要注意关掉缓存的定时失效,防止当用户流量忽然过大,都到分布式缓存中拉取数据;第二种方式是每次商品更新,都发布一个消息,订阅此消息的节点监听到后再更新本地缓存的内容。 **热点自动发现方案** 能够将交易系统产生的相关数据,以及在上游系统中埋点上报的相关数据异步写入日志系统中,而后经过实时热点自动发现平台对收集到的日志数据作调用次数统计和热点分析。数据符合热点条件后,就当即通知交易系统作好热点保护。 **Redis使用watch命令实现高并发抢购需求** 通常高并发这里,不用悲观锁,会迅速增长系统资源;而使用队列,容易形成请求堆积,内存效果过快。因此通常使用乐观锁,能够用redis的watch命令实现。watch命令会监视给定的key,当exec时,若是监视的key从调用watch后发生过变化,则事务会失败。注意watch的能够是对整个链接有效的,事务也同样。若是链接断开,监视和事务都会被自动清除。固然exec,discard,unwatch命令都会清除链接中的全部监视。 **协程(纤程)Fiber** 协程概念:一种用户态的轻量级线程,其实就是单线程,指定执行整个函数中到一部分而后就先出去执行别的,等条件知足时,协程下次更新帧到了再继续往下执行。优势是无需线程上下文切换的开销,充分开发了单CPU的能力,资源占用低,适合高并发I/O。缺点也很明显,就是没办法利用多CPU的优点。 框架:Quasar,调度器使用ForkJoinPool来调度这些fiber。Fiber调度器FiberScheduler是一个高效的、work-stealing、多线程的调度器。 场景:服务A平时须要调用其余服务,但其余服务在并发高的时候延迟很严重。 一开始能够用httpClient链接池+线程池来处理,但若是调用服务的时候延迟过高或者超时,则会致使服务A的吞吐量会特别差。缘由主要是通常一个连接由一个线程来处理,是阻塞的,因此在线程池数有限的状况下,吞吐量确定上不去。而且当全部线程都I/O阻塞的时候,会很浪费CPU资源,而且CPU会一直作无用的上下文切换。这时候能够考虑协程来替换。 **ForkJoinPool线程池** Fork/Join框架是Java7提供了的一个用于并行执行任务的框架,是一个把大任务分割成若干个小任务,最终汇总每一个小任务结果后获得大任务结果的框架。 工做窃取(work-stealing)算法是Fork/Join框架最重要的特性。通常一个线程会对应一个任务队列,当处理较快的线程处理完本身的任务以后,就会窃取另一个处理比较慢的线程对应的任务,这时候会存在两个线程同时处理一个队列的状况,因此任务队列通常使用双端队列,被窃取任务线程永远从双端队列的头部拿任务执行,而窃取任务的线程永远从双端队列的尾部拿任务执行。优势是充分利用线程进行并行计算,并减小了线程间的竞争。    61. 说说秒杀如何实现的?  核心思路是流量控制和性能优化。  **流量控制**  请求流控:能够经过前端系统进行拦截,限制最终流入系统的请求数量。  客户端流控:较为合适的作法是屏蔽用户高频请求,好比在网页中设置5s一次访问限制,能够防止用户过分刷接口。  Web端流控:常见作法是能够经过在内存或缓存服务中加入请求访问信息,来实现访问量限制。  数据库存在瓶颈,为了应对大量的并发请求,使用redis缓存来拦截大量请求,使用redis原子操做incr和decr来确保库存。  **对此方案优化**  当库存为0时,须要在本地缓存中直接关闭标示位,便可以不去访问Redis。  当扣减库存以后,可使用异步操做来建立订单等一系列操做。