面试-准备

深刻理解java虚拟机
http://www.cnblogs.com/prayers/p/5515245.html

spring面试题
http://www.importnew.com/15851.html

sed 's/原字符串/替换字符串/'  末尾加g替换每个匹配的关键字,不然只替换每行的第一个
cat /etc/passwd |awk  -F ':'  '{print $1"\t"$7}'

当前WEB服务器中联接次数最多的ip地址
#netstat -ntu |awk '{print $5}' |sort | uniq -c| sort -nr
查看日志中访问次数最多的前10个IP
#cat access_log |cut -d ' ' -f 1 | sort |uniq -c | sort -nr | awk '{print $0 }' | head -n 10 | less
查看日志中出现100次以上的IP
#cat access_log |cut -d ' ' -f 1 | sort |uniq -c | awk '{if ($1 > 100) print $0}'|sort -nr | less
查看最近访问量最高的文件
#cat access_log | tail -10000 | awk '{print $7}' | sort | uniq -c | sort -nr | less
查看日志中访问超过100次的页面
#cat access_log | cut -d ' ' -f 7 | sort |uniq -c | awk '{if ($1 > 100) print $0}' | less
统计某url,一天的访问次数
#cat access_log | grep '12/Aug/2009' | grep '/images/index/e1.gif' | wc | awk '{print $1}'
前五天的访问次数最多的网页
#cat access_log | awk '{print $7}' | uniq -c | sort -n -r | head -20
从日志里查看该ip在干吗
#cat access_log | grep 218.66.36.119 | awk '{print $1"\t"$7}' | sort | uniq -c | sort -nr | less
列出传输时间超过 30 秒的文件
#cat access_log | awk '($NF > 30){print $7}' | sort -n | uniq -c | sort -nr | head -20
列出最最耗时的页面(超过60秒的)
#cat access_log | awk '($NF > 60 && $7~/\.php/){print $7}' | sort -n | uniq -c | sort -nr | head -100

(01) ArrayList 其实是经过一个数组去保存数据的。当咱们构造ArrayList时;若使用默认构造函数,则ArrayList的默认容量大小是10。
(02) 当ArrayList容量不足以容纳所有元素时,ArrayList会从新设置容量:新的容量=“(原始容量x3)/2 + 1”。
(03) ArrayList的克隆函数,便是将所有元素克隆到一个数组中。
(04) ArrayList实现java.io.Serializable的方式。当写入到输出流时,先写入“容量”,再依次写入“每个元素”;当读出输入流时,先读取“容量”,再依次读取“每个元素”
ArrayList 是一个数组队列,至关于动态数组。它由数组实现,随机访问效率高,随机插入、随机删除效率低。
LinkedList 是一个双向链表。它也能够被看成堆栈、队列或双端队列进行操做。LinkedList随机访问效率低,但随机插入、随机删除效率低。

hashMap
1.HashMap其实是一个“链表散列”的数据结构,即数组和链表的结合体
初始容量,加载因子
对key作null检查,若是key是null,会被存储到table[0],由于null的hash值老是0
HashMap和Hashtable都是存储“键值对(key-value)”的散列表,并且都是采用拉链法实现的。
存储的思想都是:经过table数组存储,数组的每个元素都是一个Entry;而一个Entry就是一个单向链表,Entry链表中的每个节点就保存了key-value键值对数据。
添加key-value键值对:首先,根据key值计算出哈希值,再计算出数组索引(即,该key-value在table中的索引)。而后,根据数组索引找到Entry(即,单向链表),再遍历单向链表,将key和链表中的每个节点的key进行对比。若key已经存在Entry链表中,则用该value值取代旧的value值;若key不存在Entry链表中,则新建一个key-value节点,并将该节点插入Entry链表的表头位置。
删除key-value键值对:删除键值对,相比于“添加键值对”来讲,简单不少。首先,仍是根据key计算出哈希值,再计算出数组索引(即,该key-value在table中的索引)。而后,根据索引找出Entry(即,单向链表)。若节点key-value存在与链表Entry中,则删除链表中的节点便可。、

ConcurrentHashMap是线程安全的哈希表,它是经过“锁分段”来实现的。ConcurrentHashMap中包括了“Segment(锁分段)数组”,每一个Segment就是一个哈希表,并且也是可重入的互斥锁。第一,Segment是哈希表表如今,Segment包含了“HashEntry数组”,而“HashEntry数组”中的每个HashEntry元素是一个单向链表。即Segment是经过链式哈希表。第二,Segment是可重入的互斥锁表如今,Segment继承于ReentrantLock,而ReentrantLock就是可重入的互斥锁。
对于ConcurrentHashMap的添加,删除操做,在操做开始前,线程都会获取Segment的互斥锁;操做完毕以后,才会释放。而对于读取操做,它是经过volatile去实现的,HashEntry数组是volatile类型的,而volatile能保证“即对一个volatile变量的读,老是能看到(任意线程)对这个volatile变量最后的写入”,即咱们总能读到其它线程写入HashEntry以后的值。
大于或等于concurrencyLevel的最小的2的N次方值

ArrayBlockingQueue若某线程(线程A)要取出数据时,队列正好为空,则该线程会执行notEmpty.await()进行等待;当其它某个线程(线程B)向队列中插入了数据以后,会调用notEmpty.signal()唤醒“notEmpty上的等待线程”。此时,线程A会被唤醒从而得以继续运行。 此外,线程A在执行取操做前,会获取takeLock,在取操做执行完毕再释放takeLock。
若某线程(线程H)要插入数据时,队列已满,则该线程会它执行notFull.await()进行等待;当其它某个线程(线程I)取出数据以后,会调用notFull.signal()唤醒“notFull上的等待线程”。此时,线程H就会被唤醒从而得以继续运行。 此外,线程H在执行插入操做前,会获取putLock,在插入操做执行完毕才释放putLock。

一级缓存: 基于PerpetualCache 的 HashMap本地缓存,其存储做用域为 Session,当 Session flush 或 close 以后,该Session中的全部 Cache 就将清空。
二级缓存与一级缓存其机制相同,默认也是采用 PerpetualCache,HashMap存储,不一样在于其存储做用域为 Mapper(Namespace),而且可自定义存储源,如 Ehcache。
对于缓存数据更新机制,当某一个做用域(一级缓存Session/二级缓存Namespaces)的进行了 C/U/D 操做后,默认该做用域下全部 select 中的缓存将被clear。

1)CountDownLatch和CyclicBarrier都可以实现线程之间的等待,只不过它们侧重点不一样:
CountDownLatch通常用于某个线程A等待若干个其余线程执行完任务以后,它才执行;
而CyclicBarrier通常用于一组线程互相等待至某个状态,而后这一组线程再同时执行;
另外,CountDownLatch是不可以重用的,而CyclicBarrier是能够重用的。
2)Semaphore其实和锁有点相似,它通常用于控制对某组资源的访问权限。


ThreadPoolExecutor 线程池任务执行流程:
    当线程池小于corePoolSize时,新提交任务将建立一个新线程执行任务,即便此时线程池中存在空闲线程。
    当线程池达到corePoolSize时,新提交任务将被放入workQueue中,等待线程池中任务调度执行
    当workQueue已满,且maximumPoolSize>corePoolSize时,新提交任务会建立新线程执行任务
    当提交任务数超过maximumPoolSize时,新提交任务由RejectedExecutionHandler处理
    当线程池中超过corePoolSize线程,空闲时间达到keepAliveTime时,关闭空闲线程
    当设置allowCoreThreadTimeOut(true)时,线程池中corePoolSize线程空闲时间达到keepAliveTime也将关闭

排队
1.直接提交。工做队列的默认选项是 SynchronousQueue,它将任务直接提交给线程而不保持它们。
2.无界队列。使用无界队列(例如,不具备预约义容量的 LinkedBlockingQueue)将致使在全部 corePoolSize 线程都忙时新任务在队列中等待。这样,建立的线程就不会超过 corePoolSize。
3.有界队列。当使用有限的 maximumPoolSizes 时,有界队列(如 ArrayBlockingQueue)有助于防止资源耗尽,可是可能较难调整和控制

被拒绝的任务
当 Executor 已经关闭,而且 Executor 将有限边界用于最大线程和工做队列容量,且已经饱和时,在方法 execute(java.lang.Runnable) 中提交的新任务将被拒绝

1.在默认的 ThreadPoolExecutor.AbortPolicy 中,处理程序遭到拒绝将抛出运行时RejectedExecutionException。
2.在 ThreadPoolExecutor.CallerRunsPolicy 中,线程调用运行该任务的execute 自己。此策略提供简单的反馈控制机制,可以减缓新任务的提交速度。
3.在 ThreadPoolExecutor.DiscardPolicy 中,不能执行的任务将被删除。
4.在 ThreadPoolExecutor.DiscardOldestPolicy 中,若是执行程序还没有关闭,则位于工做队列头部的任务将被删除,而后重试执行程序(若是再次失败,则重复此过程)。

newCachedThreadPool:
    底层:返回ThreadPoolExecutor实例,corePoolSize为0;maximumPoolSize为Integer.MAX_VALUE;keepAliveTime为60L;unit为TimeUnit.SECONDS;workQueue为SynchronousQueue(同步队列)
    通俗:当有新任务到来,则插入到SynchronousQueue中,因为SynchronousQueue是同步队列,所以会在池中寻找可用线程来执行,如有能够线程则执行,若没有可用线程则建立一个线程来执行该任务;若池中线程空闲时间超过指定大小,则该线程会被销毁。
    适用:执行不少短时间异步的小程序或者负载较轻的服务器
newFixedThreadPool:
    底层:返回ThreadPoolExecutor实例,接收参数为所设定线程数量nThread,corePoolSize为nThread,maximumPoolSize为nThread;keepAliveTime为0L(不限时);unit为:TimeUnit.MILLISECONDS;WorkQueue为:new LinkedBlockingQueue<Runnable>() 无解阻塞队列
    通俗:建立可容纳固定数量线程的池子,每隔线程的存活时间是无限的,当池子满了就不在添加线程了;若是池中的全部线程均在繁忙状态,对于新任务会进入阻塞队列中(无界的阻塞队列)
    适用:执行长期的任务,性能好不少
newSingleThreadExecutor:
    底层:FinalizableDelegatedExecutorService包装的ThreadPoolExecutor实例,corePoolSize为1;maximumPoolSize为1;keepAliveTime为0L;unit为:TimeUnit.MILLISECONDS;workQueue为:new LinkedBlockingQueue<Runnable>() 无解阻塞队列
    通俗:建立只有一个线程的线程池,且线程的存活时间是无限的;当该线程正繁忙时,对于新任务会进入阻塞队列中(无界的阻塞队列)
    适用:一个任务一个任务执行的场景
NewScheduledThreadPool:
    底层:建立ScheduledThreadPoolExecutor实例,corePoolSize为传递来的参数,maximumPoolSize为Integer.MAX_VALUE;keepAliveTime为0;unit为:TimeUnit.NANOSECONDS;workQueue为:new DelayedWorkQueue() 一个按超时时间升序排序的队列
    通俗:建立一个固定大小的线程池,线程池内线程存活时间无限制,线程池能够支持定时及周期性任务执行,若是全部线程均处于繁忙状态,对于新任务会进入DelayedWorkQueue队列中,这是一种按照超时时间排序的队列结构
    适用:周期性执行任务的场景



BIO是一个链接一个线程。
NIO是一个请求一个线程。
AIO是一个有效请求一个线程。

先来个例子理解一下概念,以银行取款为例:
    同步 : 本身亲自出马持银行卡到银行取钱(使用同步IO时,Java本身处理IO读写);
    异步 : 委托一小弟拿银行卡到银行取钱,而后给你(使用异步IO时,Java将IO读写委托给OS处理,须要将数据缓冲区地址和大小传给OS(银行卡和密码),OS须要支持异步IO操做API);
    阻塞 : ATM排队取款,你只能等待(使用阻塞IO时,Java调用会一直阻塞到读写完成才返回);
    非阻塞 : 柜台取款,取个号,而后坐在椅子上作其它事,等号广播会通知你办理,没到号你就不能去,你能够不断问大堂经理排到了没有,大堂经理若是说还没到你就不能去(使用非阻塞IO时,若是不能读写Java调用会立刻返回,当IO事件分发器会通知可读写时再继续进行读写,不断循环直到读写完成)

Java对BIO、NIO、AIO的支持:
    Java BIO : 同步并阻塞,服务器实现模式为一个链接一个线程,即客户端有链接请求时服务器端就须要启动一个线程进行处理,若是这个链接不作任何事情会形成没必要要的线程开销,固然能够经过线程池机制改善。
    Java NIO : 同步非阻塞,服务器实现模式为一个请求一个线程,即客户端发送的链接请求都会注册到多路复用器上,多路复用器轮询到链接有I/O请求时才启动一个线程进行处理。
    Java AIO(NIO.2) : 异步非阻塞,服务器实现模式为一个有效请求一个线程,客户端的I/O请求都是由OS先完成了再通知服务器应用去启动线程进行处理,

 同步阻塞IO:在此种方式下,用户进程在发起一个IO操做之后,必须等待IO操做的完成,只有当真正完成了IO操做之后,用户进程才能运行。JAVA传统的IO模型属于此种方式!
同步非阻塞IO:在此种方式下,用户进程发起一个IO操做之后边可返回作其它事情,可是用户进程须要时不时的询问IO操做是否就绪,这就要求用户进程不停的去询问,从而引入没必要要的CPU资源浪费。其中目前JAVA的NIO就属于同步非阻塞IO。
异步阻塞IO:此种方式下是指应用发起一个IO操做之后,不等待内核IO操做的完成,等内核完成IO操做之后会通知应用程序,这其实就是同步和异步最关键的区别,同步必须等待或者主动的去询问IO是否完成,那么为何说是阻塞的呢?由于此时是经过select系统调用来完成的,而select函数自己的实现方式是阻塞的,而采用select函数有个好处就是它能够同时监听多个文件句柄,从而提升系统的并发性!

 异步非阻塞IO:在此种模式下,用户进程只须要发起一个IO操做而后当即返回,等IO操做真正的完成之后,应用程序会获得IO操做完成的通知,此时用户进程只须要对数据进行处理就行了,不须要进行实际的IO读写操做,由于真正的IO读取或者写入操做已经由内核完成了。目前Java中尚未支持此种IO模型。


若是你想吃一份宫保鸡丁盖饭:
同步阻塞:你到饭馆点餐,而后在那等着,还要一边喊:好了没啊!
同步非阻塞:在饭馆点完餐,就去遛狗了。不过溜一下子,就回饭馆喊一声:好了没啊!
异步阻塞:遛狗的时候,接到饭馆电话,说饭作好了,让您亲自去拿。
异步非阻塞:饭馆打电话说,咱们知道您的位置,一会给你送过来,安心遛狗就能够了。


3.springmvc
第一步:发起请求到前端控制器(DispatcherServlet)
第二步:前端控制器请求HandlerMapping查找 Handler
         能够根据xml配置、注解进行查找
第三步:处理器映射器HandlerMapping向前端控制器返回Handler
第四步:前端控制器调用处理器适配器去执行Handler
第五步:处理器适配器去执行Handler
第六步:Handler执行完成给适配器返回ModelAndView
第七步:处理器适配器向前端控制器返回ModelAndView
         ModelAndView是springmvc框架的一个底层对象,包括Model和view
第八步:前端控制器请求视图解析器去进行视图解析
        根据逻辑视图名解析成真正的视图(jsp)
第九步:视图解析器向前端控制器返回View
第十步:前端控制器进行视图渲染
         视图渲染将模型数据(在ModelAndView对象中)填充到request域
第十一步:前端控制器向用户响应结果

maven总结
maven解决jar冲突
1.dependency:tree 以层级树方式展示传递性依赖
2.<exclusion> 将不想要的传递依赖剪除掉
3.查看运行期类来源的JAR包


事务属性
传播行为 隔离规则 回滚规则 事务超时 是否只读

spring 事务传播
REQUIRED 表示当前方法必须运行在事务中。若是当前事务存在,方法将会在该事务中运行。不然,会启动一个新的事务
SUPPORTS 表示当前方法不须要事务上下文,可是若是存在当前事务的话,那么该方法会在这个事务中运行
MANDATORY     表示该方法必须在事务中运行,若是当前事务不存在,则会抛出一个异常
REQUIRED_NEW     表示当前方法必须运行在它本身的事务中。一个新的事务将被启动。若是存在当前事务,在该方法执行期间,当前事务会被挂起。若是使用JTATransactionManager的话,则须要访问TransactionManager
NOT_SUPPORTED     表示该方法不该该运行在事务中。若是存在当前事务,在该方法运行期间,当前事务将被挂起。若是使用JTATransactionManager的话,则须要访问TransactionManager
NEVER     表示当前方法不该该运行在事务上下文中。若是当前正有一个事务在运行,则会抛出异常
NESTED     表示若是当前已经存在一个事务,那么该方法将会在嵌套事务中运行

脏读(Dirty reads)——脏读发生在一个事务读取了另外一个事务改写但还没有提交的数据时。若是改写在稍后被回滚了,那么第一个事务获取的数据就是无效的。
不可重复读(Nonrepeatable read)——不可重复读发生在一个事务执行相同的查询两次或两次以上,可是每次都获得不一样的数据时。这一般是由于另外一个并发事务在两次查询期间进行了更新。
幻读(Phantom read)——幻读与不可重复读相似。它发生在一个事务(T1)读取了几行数据,接着另外一个并发事务(T2)插入了一些数据时。在随后的查询中,第一个事务(T1)就会发现多了一些本来不存在的记录。

不可重复读的重点是修改,幻读的重点在于新增或者删除
从控制的角度来看, 二者的区别就比较大。
对于前者, 只须要锁住知足条件的记录。
对于后者, 要锁住知足条件及其相近的记录

隔离级别
定义了一个事务可能受其余并发事务影响的程度
SOLATION_READ_UNCOMMITTED     最低的隔离级别,容许读取还没有提交的数据变动,可能会致使脏读、幻读或不可重复读
ISOLATION_READ_COMMITTED     容许读取并发事务已经提交的数据,能够阻止脏读,可是幻读或不可重复读仍有可能发生
ISOLATION_REPEATABLE_READ     对同一字段的屡次读取结果都是一致的,除非数据是被自己事务本身所修改,能够阻止脏读和不可重复读,但幻读仍有可能发生
ISOLATION_SERIALIZABLE     最高的隔离级别,彻底服从ACID的隔离级别,确保阻止脏读、不可重复读以及幻读,也是最慢的事务隔离级别,由于它一般是经过彻底锁定事务相关的数据库表来实现的



JVM常见配置
堆设置
-Xms:初始堆大小
-Xmx:最大堆大小
-XX:NewSize=n:设置年轻代大小
-XX:NewRatio=n:设置年轻代和年老代的比值。如:为3,表示年轻代与年老代比值为1:3,年轻代占整个年轻代年老代和的1/4
-XX:SurvivorRatio=n:年轻代中Eden区与两个Survivor区的比值。注意Survivor区有两个。如:3,表示Eden:Survivor=3:2,一个Survivor区占整个年轻代的1/5
-XX:MaxPermSize=n:设置持久代大小
收集器设置
-XX:+UseSerialGC:设置串行收集器
-XX:+UseParallelGC:设置并行收集器
-XX:+UseParalledlOldGC:设置并行年老代收集器
-XX:+UseConcMarkSweepGC:设置并发收集器
垃圾回收统计信息
-XX:+PrintGC
-XX:+PrintGCDetails
-XX:+PrintGCTimeStamps
-Xloggc:filename

并行收集器设置
-XX:ParallelGCThreads=n:设置并行收集器收集时使用的CPU数。并行收集线程数。
-XX:MaxGCPauseMillis=n:设置并行收集最大暂停时间
-XX:GCTimeRatio=n:设置垃圾回收时间占程序运行时间的百分比。公式为1/(1+n)

并发收集器设置
-XX:+CMSIncrementalMode:设置为增量模式。适用于单CPU状况。
-XX:ParallelGCThreads=n:设置并发收集器年轻代收集方式为并行收集时,使用的CPU数。并行收集线程数。

spring 配置双数据源并读写分离
关键思想在于重写 AbstractRoutingSource.determineCurrentLookupKey();
配置writeDataSource,readDataSource
aop配置根据方法名前缀选择使用的数据源<entry key="read" value=",get,select,count,list,query," />
<entry key="write" value=",add,insert,create,update,delete,remove," />

实现@DataSource注解,在方法上配置


Redis是一个开源的,基于内存的结构化数据存储媒介,能够做为数据库、缓存服务或消息服务使用。
Redis支持多种数据结构,包括字符串 string、哈希表 hash、链表list、集合set、有序集合sorted set、位图、Hyperloglogs等。
Redis具有LRU淘汰、事务实现、以及不一样级别的硬盘持久化等能力,而且支持副本集和经过Redis Sentinel实现的高可用方案,同时还支持经过Redis Cluster实现的数据自动分片能力。
Redis的主要功能都基于单线程模型实现,也就是说Redis使用一个线程来服务全部的客户端请求,同时Redis采用了非阻塞式IO,并精细地优化各类命令的算法时间复杂度
前文提到过,Redis采用单线程模型,自然是线程安全的,这使得INCR/DECR命令能够很是便利的实现高并发场景下的精确控制。


1 Dubbo中zookeeper作注册中心,若是注册中心集群都挂掉,发布者和订阅者之间还能通讯么?
能够的,启动dubbo时,消费者会从zk拉取注册的生产者的地址接口等数据,缓存在本地。每次调用时,按照本地存储的地址进行调用

注册中心对等集群,任意一台宕掉后,会自动切换到另外一台
注册中心所有宕掉,服务提供者和消费者仍能够经过本地缓存通信
服务提供者无状态,任一台 宕机后,不影响使用
服务提供者所有宕机,服务消费者会没法使用,并没有限次重连等待服务者恢复
2 dubbo链接注册中心和直连的区别
在开发及测试环境下,常常须要绕过注册中心,只测试指定服务提供者,这时候可能须要点对点直连,
点对点直联方式,将以服务接口为单位,忽略注册中心的提供者列表,

服务注册中心,动态的注册和发现服务,使服务的位置透明,并经过在消费方获取服务提供方地址列表,实现软负载均衡和Failover, 注册中心返回服务提供者地址列表给消费者,若是有变动,注册中心将基于长链接推送变动数据给消费者。
服务消费者,从提供者地址列表中,基于软负载均衡算法,选一台提供者进行调用,若是调用失败,再选另外一台调用。注册中心负责服务地址的注册与查找,至关于目录服务,服务提供者和消费者只在启动时与注册中心交互,注册中心不转发请求,服务消费者向注册中心获取服务提供者地址列表,并根据负载算法直接调用提供者,注册中心,服务提供者,服务消费者三者之间均为长链接,监控中心除外,注册中心经过长链接感知服务提供者的存在,服务提供者宕机,注册中心将当即推送事件通知消费者
注册中心和监控中心所有宕机,不影响已运行的提供者和消费者,消费者在本地缓存了提供者列表
注册中心和监控中心都是可选的,服务消费者能够直连服务提供者

三、Dubbo在安全机制方面是如何解决的
Dubbo经过Token令牌防止用户绕过注册中心直连,而后在注册中心上管理受权。Dubbo还提供服务黑白名单,来控制服务所容许的调用方

4 Dubbo提供了4种均衡策略,如:Random LoadBalance(随机均衡算法)、;RoundRobin LoadBalance(权重轮循均衡算法)、LeastAction LoadBalance(最少活跃调用数均衡算法)、ConsistentHash LoadBalance(一致性Hash均衡算法)

5 集群容错模式:
Failover Cluster
失败自动切换,当出现失败,重试其它服务器。(缺省)
一般用于读操做,但重试会带来更长延迟。
可经过retries="2"来设置重试次数(不含第一次)。正是文章刚开始说的那种状况.

 Failfast Cluster
快速失败,只发起一次调用,失败当即报错。
一般用于非幂等性的写操做,好比新增记录。

  Failsafe Cluster
失败安全,出现异常时,直接忽略。
一般用于写入审计日志等操做。

  Failback Cluster
失败自动恢复,后台记录失败请求,定时重发。
一般用于消息通知操做。
  Forking Cluster
并行调用多个服务器,只要一个成功即返回。
一般用于实时性要求较高的读操做,但须要浪费更多服务资源。
可经过forks="2"来设置最大并行数。
  Broadcast Cluster
广播调用全部提供者,逐个调用,任意一台报错则报错。(2.1.0开始支持)
一般用于通知全部提供者更新缓存或日志等本地资源信息。php