面试题整理 !=!=未看 *****面试题整理最全 有用

1、Java基础


 
1. String类为何是final的。
        最佳答案:主要是为了“ 效率”和“安全性”的缘故。如String容许被继承,因为它的高度被实用性,可能会下降程序的性能,全部String被定义成final。
 
2. HashMap的源码,实现原理,底层结构。
       参考:  http://blog.csdn.net/vking_wang/article/details/14166593   or    
 
3. 说说你知道的几个Java集合类:list、set、queue、map实现类咯。。。
HashMap
Hashtable
    是一个古老的Map实现类
        2.1) Properties 
        Properties对象在处理属性文件时特别方便(windows平台上的.ini文件),Properties类能够把Map对象和属性文件关联起来,从而能够把Map对象中的key-value对写入到属性文
 
 HashSet
        HashSet是Set接口的典型实现,HashSet使用HASH算法来存储集合中的元素,所以具备良好的存取和查找性能。当向HashSet集合中存入一个元素时,HashSet会调用该对象的
     hashCode()方法来获得该对象的hashCode值,而后根据该HashCode值决定该对象在HashSet中的存储位置。 值得主要的是,HashSet集合判断两个元素相等的标准是两个对象经过equals()方法比较相等,而且两个对象的hashCode()方法的返回值相等 1.1.1) LinkedHashSet LinkedHashSet集合也是根据元素的hashCode值来决定元素的存储位置,但和HashSet不一样的是,它同时使用链表维护元素的次序,这样使得元素看起来是以插入的顺序保存的。
       当遍历LinkedHashSet集合里的元素时,LinkedHashSet将会按元素的添加顺序来访问集合里的元素。 LinkedHashSet须要维护元素的插入顺序,所以性能略低于HashSet的性能,但在迭代访问Set里的所有元素时(遍历)将有很好的性能(链表很适合进行遍历)
Deque
        Deque接口表明一个"双端队列",双端队列能够同时从两端来添加、删除元素,所以Deque的实现类既能够当成队列使用、也能够当成栈使用
            3.2.1) ArrayDeque
            是一个基于数组的双端队列,和ArrayList相似,它们的底层都采用一个动态的、可重分配的Object[]数组来存储集合元素,当集合元素超出该数组的容量时,系统会在底层重
     PriorityQueue并非一个比较标准的队列实现,PriorityQueue保存队列元素的顺序并非按照加入队列的顺序,而是按照队列元素的大小进行从新排序,这点从它的类名也能够
 
4. 描述一下ArrayList和LinkedList各自实现和区别
     参考: http://www.importnew.com/6629.html 
 
5. Java中的队列都有哪些,有什么区别。
种类:普通队列、阻塞队列、非阻塞队列
区别:
(1) 阻塞队列与普通队列区别在于,当队列是空时,从队列中获取元素的操做将被阻塞,或者当队列满时,往队列里添加元素的操做会被阻塞。试图从空的阻塞队列中获取元素的线程将会被阻塞,直到其余的线程往空的队列插入新的元素。一样,试图往已满的阻塞队列中添加新的元素的线程一样会被阻塞,知道其余的线程使得队列从新变的空闲起来,如从队列中溢出一个或多个元素,或者彻底状况队列。
 举例说明:阻塞队列(LinkedBlockingQueue)和非阻塞队列(ConcurrentLinkedQueue)的区别
    相同点:两者都是线程安全的
    不一样点:
         (1)阻塞队列:按FIFO排序元素。队列的头部是在队列中时间最长的元素。队列的尾部是在队列中最短的元素。新元素插入队列的尾部,而且队列检索操做会得到位于队列头部的元素。连接队列的吞吐量一般要高于基于数组的队列,可是在大多数并发应用程序中,其可预知性能要低。
          注意:A:必需要使用take()方法获取的时候达成阻塞结果
                    B:使用poll()方法产生非阻塞效果
         (2)非阻塞队列:基于连接节点的、无界的、线程安全。按FIFO排序元素。队列的头部是在队列中时间最长的元素。队列的尾部是在队列中最短的元素。新元素插入队列的尾部,而且队列检索操做会得到位于队列头部的元素。 当许多线程共享访问一个公共Collection时,ConcurrentLinkedQueue是一个恰当的选择。此队列不容许为null元素。
         (3)在并发编程中,通常推荐使用 阻塞队列,这样实现能够尽可能避免程序出现意外错误。阻塞队列 使用最经典的场景就是socket客户端数据的读取和解析,读取数据的线程不断将数据放入队列,而后解析线程不断从队列取数据解析。只要符合生产者-消费者模型的均可以使用阻塞队列
        (4 )使用非阻塞队列,虽然能即时返回结果(消费结果),可是必须自行编码解决返回为空的状况(以及消费重试等问题)
 
6. 反射中,Class.forName和classloader的区别
     均可以用来对类进行加载。Class.forName不但将类.c lass文件加载到jvm中以外,还会对类进行解释 执行类中的static块。而classloader只是将.class文件加载到jvm中,不会执行static中的内容,只有在newInstance时才会去执行static块。
     对比二者具体的执行过程:
     (1)LoadClass()方法加载类及其初始化过程:
          类加载---》newInstance() (连接+初始化)
          newInstance():
         (开始链接) 静态代码块-->普通变量分配准备(a=0;b=0;c=null)-->(开始初始化)普通变量赋值(a=1;b=2;c='haha')-->构造方法-->初始化成功
     (2)Class.forName(String className)一个参数方法加载类及其初始化过程:
          类加载--->静态代码块-->newInstance() (连接+初始化)
  newInstance():
         (开始链接)普通变量分配准备(a=0;b=0;c=null)-->(开始初始化)普通变量赋值(a=1;b=2;c='haha')-->构造方法-->初始化成功
 
      JVM加载类及其初始化过程
     (1)类加载:Boostrap Loader(启动类加载器)-->Extened Loader(扩展类加载器)-->System Loader(系统加载器)
     (2)静态代码块初始化
     (3)连接:A:验证:是否符合java规范 是否有正确的内部结构 及数据是否符合JVM规范 B:准备:静态变量默认初始值 C:解析:符号引用转为直接引用,解析地址
     (4)初始化:A:赋值,真正的初始化,用户给变量赋予的值 B:构造方法
 
7. Java七、Java8的新特性(baidu问的,好BT)
     Java7的新特性:
       (1)语法上:
               A:二进制变量的标示,支持将整数类型用二进制来标示,用0b开头。
                B:Switch语句支持String类型
                C:Try-witch-resource语句
               D:Catch多个异常(catch异常类型为final)
               E:数字类型的下划线标示,更友好的表达式
               F: 泛型实例的建立能够经过类型推断来简化 能够去掉后面 new 部分的泛型类型,只用<>就能够了。
        G:在可变参数方法中传递非具体化参数,改进编译警告和错误
        H: 信息更丰富的回溯追踪 就是上面 try try 语句和里面的语句同时抛出异常时,异常栈的信息
    Java8的新特性
          (1)接口的默认方法:容许给接口添加一个非抽象的方法实现,只须要使用default关键字便可,这个特征又叫扩展方法。
              
          (2)Lambda表达式
            
     
            
          (3)函数式接口:仅仅只包含一个抽象对象的接口,每个该类型的lambda表达式都会被匹配到这个抽象方法。只需给接口添加@FunctionalInterface注释,编译器若是发现你标注了这个注解的接口有多于一个抽象方法的时候会报错的。
            
            
          (4)方法与构造函数引用:容许你使用::关键字来传递方法或者构造函数引用,如下代码展现了如何引用一个静态方法。
            
             构造函数引用:
            
              
          (5)lambda做用域:
               在lambda表达式中访问外层做用域和老版本的匿名对象中的方式类似,你能够直接访问标记了final的外层局部变量,或者实例的字段以及静态变量。
          (6)访问局部变量
                
          (7)访问对象字段与静态变量
               和本地变量不一样的是,lambda内部对于实例的字段以及静态变量是既可读又可写的。
            
          (8)访问接口的默认方法
          (9)Date API
               Clock时钟:提供了访问当前日期和时间方法。java.time.Clock
          (10)Annotation注解:支持多种注解
      
 
8. Java数组和链表两种结构的操做效率,在哪些状况下(从开头开始,从结尾开始,从中间开始),哪些操做(插入,查找,删除)的效率高
 
9. Java内存泄露的问题调查定位:jmap,jstack的使用等等

下面就来认识一下MemoryAnalyzer.exe。java内存泄漏检查工具利器。php

首先咱们必须对jvm的堆内存进行dump,只有拿到这个文件咱们才能分析出jvm堆内存中到底存了些什么内容,到底在作什么?html

MemoryAnalyzer的用户我在这里就不一一说明了,个人博客里也有说明,下面就展现我测试的成功图:java

其中深蓝色的部分就为内存泄漏的部分,java的堆内存一共只有481.5M而内存泄漏的部分独自占有了336.2M因此本次的内存泄漏很明显,那么我就来看看那个方法致使的内存泄漏:mysql

从上图咱们能够发现红线圈着的方法占用了堆内存的67.75%,若是能把这个测试结果交给开发,开发是否是应该很好定位呢。因此做为一名高级测试工程师,咱们须要学习的东西太多。linux

虽然不肯定必定是内存泄漏,可是能够准确的告诉开发问题出现的缘由,有必定的说服力。nginx

本人刚刚完成了云存储架构师的培训学习(包括了linux的内核了解、 shell的高级编程、linux安全的学习重点iptables和tcp/ip等各类协议的抓包分析、linux的集群、性能调优等接下来还有dba的课程等待着我挑战)。程序员

 
10. string、stringbuilder、stringbuffer区别

可变与不可变web

  String类中使用字符数组保存字符串,以下就是,由于有“final”修饰符,因此能够知道string对象是不可变的。面试

    private final char value[];redis

  StringBuilder与StringBuffer都继承自AbstractStringBuilder类,在AbstractStringBuilder中也是使用字符数组保存字符串,以下就是,可知这两种对象都是可变的。

    char[] value;

2.是否多线程安全

  String中的对象是不可变的,也就能够理解为常量,显然线程安全

  AbstractStringBuilder是StringBuilder与StringBuffer的公共父类,定义了一些字符串的基本操做,如expandCapacity、append、insert、indexOf等公共方法。

  StringBuffer对方法加了同步锁或者对调用的方法加了同步锁,因此是线程安全的。

 

.StringBuilder与StringBuffer共同点

  StringBuilder与StringBuffer有公共父类AbstractStringBuilder(抽象类)。

  抽象类与接口的其中一个区别是:抽象类中能够定义一些子类的公共方法,子类只须要增长新的功能,不须要重复写已经存在的方法;而接口中只是对方法的申明和常量的定义。

  StringBuilder、StringBuffer的方法都会调用AbstractStringBuilder中的公共方法,如super.append(...)。只是StringBuffer会在方法上加synchronized关键字,进行同步。

  最后,若是程序不是多线程的,那么使用StringBuilder效率高于StringBuffer。

11. hashtable和hashmap的区别
 
Hashtable 和 HashMap 的比较

 

 
Hashtable
HashMap
并发操做
使用同步机制
实际应用程序中,仅仅是Hashtable自己的同步并不能保证程序在并发操做下的正确性,须要高层次的并发保护。
下面的代码试图在key所对应的value值等于x的状况下修改value为x+1
{
 value = hashTable.get(key);
   if(value.intValue()== x){
hashTable.put(key,      new Integer(value.intValue()+1));
   }
}
如2个线程同时执行以上代码,可能放入不是x+1,而是x+2.
没有同步机制,须要使用者本身进行并发访问控制
数据遍历的方式
Iterator 和 Enumeration
Iterator
是否包含Contains方法 包含 不包含 可是改为containskey 和containsvalue
是否接受值为null的Key 或Value?
不接受
接受
根据hash值计算数组下标的算法
当数组长度较小,而且Key的hash值低位数值分散不均匀时,不一样的hash值计算获得相同下标值的概率较高
 
hash = key.hashCode();
index=(hash&0x7FFFFFFF) % tab.length;
优于hashtable,经过对Key的hash作移位运算和位的与运算,使其能更普遍地分散到数组的不一样位置
 
hash = hash (k);
index = indexFor(hash, table.length);
 
static int hash(Object x) {
 int h = x.hashCode();
h += ~(h << 9);
 h ^= (h >>> 14);
  h += (h << 4);
 h ^= (h >>> 10);
 return h;
}
static int indexFor(int h, int length) {
return h & (length-1);
}
 
Entry数组的长度
Ø         缺省初始长度为11
Ø         初始化时能够指定initial capacity
Ø         缺省初始长度为16
Ø         长度始终保持2的n次方
Ø         初始化时能够指定initial capacity,若不是2的次方,HashMap将选取第一个大于initial capacity 的2n次方值做为其初始长度
LoadFactor负荷因子
0.75
负荷超过(loadFactor * 数组长度)时,内部数据的调整方式
扩展数组:2*原数组长度+1
扩展数组: 原数组长度 * 2
二者都会从新根据Key的hash值计算其在数组中的新位置,从新放置。算法类似,时间、空间效率相同
 
13 .异常的结构,运行时异常和非运行时异常,各举个例子
     参考:  http://www.tuicool.com/articles/YVZBNfN   

4.运行时异常和非运行时异常

(1)运行时异常都是RuntimeException类及其子类异常,如NullPointerException、IndexOutOfBoundsException等,这些异常是不检查异常,程序中能够选择捕获处理,也能够不处理。这些异常通常是由程序逻辑错误引发的,程序应该从逻辑角度尽量避免这类异常的发生。

当出现RuntimeException的时候,咱们能够不处理。当出现这样的异常时,老是由虚拟机接管。好比:咱们历来没有人去处理过NullPointerException异常,它就是运行时异常,而且这种异常仍是最多见的异常之一。

出现运行时异常后,系统会把异常一直往上层抛,一直遇处处理代码。若是没有处理块,到最上层,若是是多线程就由Thread.run()抛出,若是是单线程就被main()抛出。抛出以后,若是是线程,这个线程也就退出了。若是是主程序抛出的异常,那么这整个程序也就退出了。运行时异常是Exception的子类,也有通常异常的特色,是能够被Catch块处理的。只不过每每咱们不对他处理罢了。也就是说,你若是不对运行时异常进行处理,那么出现运行时异常以后,要么是线程停止,要么是主程序终止。 

若是不想终止,则必须扑捉全部的运行时异常,决不让这个处理线程退出。队列里面出现异常数据了,正常的处理应该是把异常数据舍弃,而后记录日志。不该该因为异常数据而影响下面对正常数据的处理。

(2)非运行时异常是RuntimeException之外的异常,类型上都属于Exception类及其子类。如 IOException、SQLException 等以及用户自定义的Exception异常。对于这种异常,JAVA编译器强制要求咱们必需对出现的这些异常进行catch并处理,不然程序就不能编译经过。因此,面对这种异常无论咱们是否愿意,只能本身去写一大堆catch块去处理可能的异常。

14. String a= “abc” String b = "abc" String c = new String("abc") String d = "ab" + "c" .他们之间用 == 比较的结果

 
15. String 类的经常使用方法
     参考:  http://www.pc6.com/java/j_50343.html 

、String类经常使用方法
一、求字符串长度
public int length()//返回该字符串的长度

1 String str = new String("asdfzxc");
2 int strlength = str.length();//strlength = 7


二、求字符串某一位置字符
public char charAt(int index)//返回字符串中指定位置的字符;注意字符串中第一个字符索引是0,最后一个是length()-1

1 String str = new String("asdfzxc");
2 char ch = str.charAt(4);//ch = z


三、提取子串
用String类的substring方法能够提取字符串中的子串,该方法有两种经常使用参数:
1)public String substring(int beginIndex)//该方法从beginIndex位置起,从当前字符串中取出剩余的字符做为一个新的字符串返回。
2)public String substring(int beginIndex, int endIndex)//该方法从beginIndex位置起,从当前字符串中取出到endIndex-1位置的字符做为一个新的字符串返回。

1 String str1 = new String("asdfzxc");
2 String str2 = str1.substring(2);//str2 = "dfzxc"
3 String str3 = str1.substring(2,5);//str3 = "dfz"


四、字符串比较
1)public int compareTo(String anotherString)//该方法是对字符串内容按字典顺序进行大小比较,经过返回的整数值指明当前字符串与参数字符串的大小关系。若当前对象比参数大则返回正整数,反之返回负整数,相等返回0。
2)public int compareToIgnore(String anotherString)//与compareTo方法类似,但忽略大小写。
3)public boolean equals(Object anotherObject)//比较当前字符串和参数字符串,在两个字符串相等的时候返回true,不然返回false
4)public boolean equalsIgnoreCase(String anotherString)//

 

字符串中字符的大小写转换
1)public String toLowerCase()//返回将当前字符串中全部字符转换成小写后的新串
2)public String toUpperCase()//返回将当前字符串中全部字符转换成大写后的新串

1 String str = new String("asDF");
2 String str1 = str.toLowerCase();//str1 = "asdf"
3 String str2 = str.toUpperCase();//str2 = "ASDF"


八、字符串中字符的替换
1)public String replace(char oldChar, char newChar)//用字符newChar替换当前字符串中全部的oldChar字符,并返回一个新的字符串。


九、其余类方法
1)String trim()//截去字符串两端的空格,但对于中间的空格不处理。

1 String str = " a sd ";
2 String str1 = str.trim();
3 int a = str.length();//a = 6
4 int b = str1.length();//b = 4


2)boolean statWith(String prefix)boolean endWith(String suffix)//用来比较当前字符串的起始字符或子字符串prefix和终止字符或子字符串suffix是否和当前字符串相同,重载方法中同时还能够指定比较的开始位置offset。

1 String str = "asdfgh";
2 boolean a = str.statWith("as");//a = true
3 boolean b = str.endWith("gh");//b = true


3)regionMatches(boolean b, int firstStart, String other, int otherStart, int length)//从当前字符串的firstStart位置开始比较,取长度为length的一个子字符串,other字符串从otherStart位置开始,指定另一个长度为length的字符串,两字符串比较,当b为true时字符串不区分大小写。
4)contains(String str)//判断参数s是否被包含在字符串中,并返回一个布尔类型的值。

1 String str = "student";
2 str.contains("stu");//true
3 str.contains("ok");//false


5)String[] split(String str)//将str做为分隔符进行字符串分解,分解后的字字符串在字符串数组中返回

1 String str = "asd!qwe|zxc#";
2 String[] str1 = str.split("!|#");//str1[0] = "asd";str1[1] = "qwe";str1[2] = "zxc";

5、字符串与基本类型的转换
一、字符串转换为基本类型
java.lang包中有Byte、Short、Integer、Float、Double类的调用方法:
1)public static byte parseByte(String s)
2)public static short parseShort(String s)
3)public static short parseInt(String s)
4)public static long parseLong(String s)
5)public static float parseFloat(String s)
6)public static double parseDouble(String s)
例如:

16. Java 的引用类型有哪几种
     强引用、软引用、弱引用、虚引用
 
17. 抽象类和接口的区别
     参考:  http://www.importnew.com/12399.html 

抽象类和接口的对比

参数 抽象类 接口
默认的方法实现 它能够有默认的方法实现 接口彻底是抽象的。它根本不存在方法的实现
实现 子类使用extends关键字来继承抽象类。若是子类不是抽象类的话,它须要提供抽象类中全部声明的方法的实现。 子类使用关键字implements来实现接口。它须要提供接口中全部声明的方法的实现
构造器 抽象类能够有构造器 接口不能有构造器
与正常Java类的区别 除了你不能实例化抽象类以外,它和普通Java类没有任何区别 接口是彻底不一样的类型
访问修饰符 抽象方法能够有public、protected和default这些修饰符 接口方法默认修饰符是public。你不能够使用其它修饰符。
main方法 抽象方法能够有main方法而且咱们能够运行它 接口没有main方法,所以咱们不能运行它。
多继承 抽象方法能够继承一个类和实现多个接口 接口只能够继承一个或多个其它接口
速度 它比接口速度要快 接口是稍微有点慢的,由于它须要时间去寻找在类中实现的方法。
添加新方法 若是你往抽象类中添加新的方法,你能够给它提供默认的实现。所以你不须要改变你如今的代码。 若是你往接口中添加方法,那么你必须改变实现该接口的类。

何时使用抽象类和接口

  • 若是你拥有一些方法而且想让它们中的一些有默认实现,那么使用抽象类吧。
  • 若是你想实现多重继承,那么你必须使用接口。因为Java不支持多继承,子类不可以继承多个类,但能够实现多个接口。所以你就能够使用接口来解决它。
 
18. java的基础类型和字节大小。
 
19. Hashtable,HashMap,ConcurrentHashMap 底层实现原理与线程安全问题(建议熟悉 jdk 源码,才能从容应答)
 
20. 若是不让你用Java Jdk提供的工具,你本身实现一个Map,你怎么作。说了很久,说了HashMap源代码,若是我作,就会借鉴HashMap的原理,说了一通HashMap实现
 
21. Hash冲突怎么办?哪些解决散列冲突的方法?
 
22. HashMap冲突很厉害,最差性能,你会怎么解决?从O(n)提高到log(n)咯,用二叉排序树的思路说了一通
          理解了hashmap的实现,聪明的人确定已经知道怎么更加高性能的使用hashmap。不过在此以前仍是先说明下初始容量和负载因子的含义。 
          Hashmap的设想是在O(1)的时间复杂度存取数据,根据咱们的分析,在最坏状况下,时间复杂度极可能是o(n),但这确定极少出现。可是某个链表中存在多个元素仍是有至关大的可能的。当hashmap中的元素数量越接近数组长度,这个概率就越大。为了保证hashmap的性能,咱们对元素数量/数组长度的值作了上限,此值就是负载因子。当比值大于负载因子时,就须要对内置数组进行扩容,从而提升读写性能。但这也正是问题的所在,对数组扩容,代价较大,时间复杂度时O(n)。   
          故咱们在hashmap须要存放的元素数量能够预估的状况下,预先设定一个初始容量,来避免自动扩容的操做来提升性能。  
 
最直观的判断就是程序中采用了二分,且二分后只运算数据的一半。但若是两部分都运算的话,时间复杂度就是O(nlogn)了。其实不必定是二分,只不过二分比较经常使用罢了
 
23. rehash
再哈希就是扩容的过程
在扩容的过程当中须要进行ReHash操做,而这是很是耗时的,在实际中应该尽可能避免
 
24. hashCode() 与 equals() 生成算法、方法怎么重写

2、Java IO


 
1. 讲讲IO里面的常见类,字节流、字符流、接口、实现类、方法阻塞。
 

字节流与字符流的区别

字节流在操做的时候自己是不会用到缓冲区(内存)的,是与文件自己直接操做的,而字符流在操做的时候是使用到缓冲区的

字节流在操做文件时,即便不关闭资源(close方法),文件也能输出,可是若是字符流不使用close方法的话,则不会输出任何内容,说明字符流用的是缓冲区,而且可使用flush方法强制进行刷新缓冲区,这时才能在不close的状况下输出内容

 

那开发中究竟用字节流好仍是用字符流好呢?

在全部的硬盘上保存文件或进行传输的时候都是以字节的方法进行的,包括图片也是按字节完成,而字符是只有在内存中才会造成的,因此使用字节的操做是最多的。

 

若是要java程序实现一个拷贝功能,应该选用字节流进行操做(可能拷贝的是图片),而且采用边读边写的方式(节省内存)。

2. 讲讲NIO。
     参考: http://blog.jobbole.com/88984/
 
3. String 编码UTF-8 和GBK的区别?
iso8859-1属于 单字节编码,最多能表示的 字符范围是0-255,应用于英文系列很明显,iso8859-1编码表示的字符范围很窄, 没法表示中文字符
 GB2312/GBK这就是 汉子的国标码,专门用来表示汉字,是 双字节编码,而英文字母和iso8859-1一致
unicode 这是 最统一的编码,能够用来表示全部语言的字符,并且是 定长双字节(也有四字节的)编码,包括英文字母在内。因此能够说它是 不兼容iso8859-1编码的,也不兼容任何编码
UTF 考虑到unicode编码不兼容iso8859-1编码,并且容易占用更多的空间:由于对于英文字母,unicode也须要两个字节来表示。因此unicode不便于传输和存储。所以而产生了utf编码 ,而 汉字使用三个字节
 
4. 何时使用字节流、何时使用字符流?

字节流与字符流的区别

字节流和字符流使用是很是类似的,那么除了操做代码的不一样以外,还有哪些不一样呢?

字节流在操做的时候自己是不会用到缓冲区(内存)的,是与文件自己直接操做的,而字符流在操做的时候是使用到缓冲区的

字节流在操做文件时,即便不关闭资源(close方法),文件也能输出,可是若是字符流不使用close方法的话,则不会输出任何内容,说明字符流用的是缓冲区,而且能够使用flush方法强制进行刷新缓冲区,这时才能在不close的状况下输出内容

 

那开发中究竟用字节流好仍是用字符流好呢?

在全部的硬盘上保存文件或进行传输的时候都是以字节的方法进行的,包括图片也是按字节完成,而字符是只有在内存中才会造成的,因此使用字节的操做是最多的。

 
5. 递归读取文件夹下的文件,代码怎么实现
 private List<String> ergodic(File file,List<String> resultFileName){
        File[] files = file.listFiles();
        if(files==null)return resultFileName;// 判断目录下是否是空的
        for (File f : files) {
            if(f.isDirectory()){// 判断是否文件夹
                resultFileName.add(f.getPath());
                ergodic(f,resultFileName);// 调用自身,查找子目录
            }else
                resultFileName.add(f.getPath());
        }
        return resultFileName;
    }
复制代码

调用时,使用:return ergodic(new File(forderPath), resultList);
返回结果就是目录下包括子目录下所有的文件路径,包括子目录的子目录.....

3、Java Web


1. session和cookie的区别和联系,session的生命周期,多个服务部署时session管理。



1. 因为HTTP协议是无状态的协议,因此服务端须要记录用户的状态时,就须要用某种机制来识具体的用户,这个机制就是Session.典型的场景好比购物车, 当你点击下单按钮时,因为HTTP协议无状态,因此并不知道是哪一个用户操做的,因此服务端要为特定的用户建立了特定的Session,用用于标识这个用户,而且跟踪用户,这样才知道购物车里面有几本书。这个Session是保存在服务端的,有一个惟一标识JssessionId。在服务端保存Session的方法不少,内存、数据库、文件都有。集群的时候也要考虑Session的转移,在大型的网站,通常会有专门的Session服务器集群,用来保存用户会话,这个时候 Session 信息都是放在内存的,使用一些缓存服务好比Memcached之类的来放 Session。
2. 思考一下服务端如何识别特定的客户?这个时候Cookie就登场了。每次HTTP请求的时候,客户端都会发送相应的Cookie信息到服务端。实际上大多数的应用都是用 Cookie 来实现Session跟踪的,第一次建立Session的时候,服务端会在HTTP协议中告诉客户端,须要在 Cookie 里面记录一个Session ID,之后每次请求把这个会话ID发送到服务器,我就知道你是谁了。有人问, 若是客户端的浏览器禁用了 Cookie 怎么办?通常这种状况下,会使用一种叫作URL重写的技术来进行会话跟踪,即每次HTTP交互,URL后面都会被附加上一个诸如 sid=xxxxx 这样的参数,服务端据此来识别用户。
3. Cookie其实还能够用在一些方便用户的场景下,设想你某次登录过一个网站,下次登陆的时候不想再次输入帐号了,怎么办?这个信息能够写到Cookie里面,访问网站的时候,网站页面的脚本能够读取这个信息,就自动帮你把用户名给填了,可以方便一下用户。 这也是Cookie名称的由来,给用户的一点甜头。
因此,总结一下:
Session是在服务端保存的一个数据结构,用来跟踪用户的状态,这个数据能够保存在集群、数据库、文件中;
Cookie是客户端保存用户信息的一种机制,用来记录用户的一些信息,也是实现Session的一种方式。

 

 

 

2. servlet的一些相关问题

3. webservice相关问题

3.是多个跨语言跨平台的应用间通讯整合的方案(实际)

webservice至关于什么? http + xml + schema

 

**SOAP(Simple Object Access Protocal)简单对象访问协议 1.是一种简单的,基于HTTP和XML的协议,用于在WEB交换结构化(XML)的数据 2.SOAP消息:请求消息和响应消息 3.HTTP+XML片段

**如何请求一个webservice

1.根据wsdl文档生成客户端代码

2.根据生成的代码调用webservice 找到wsdl文档中service标签的name属性对应的类,找到这个port标签的name属性 调用这个方法

4. jdbc链接,forname方式的步骤,怎么声明使用一个事务。举例并具体代码

5. 无框架下配置web.xml的主要配置内容

6. jsp和servlet的区别

4、JVM


 
1. Java的内存模型以及GC算法
 
2. jvm性能调优都作了什么
     
      JVM性能调优有不少设置,这个参考JVM参数便可.
     主要调优的目的:
    1. 控制GC的行为.GC是一个后台处理,可是它也是会消耗系统性能的,所以常常会根据系统运行的程序的特性来更改GC行为
    2. 控制JVM堆栈大小.通常来讲,JVM在内存分配上不须要你修改,(举例)可是当你的程序新生代对象在某个时间段产生的比较多的时候,就须要控制新生代的堆大小.同时,还要须要控制总的JVM大小避免内存溢出
    3. 控制JVM线程的内存分配.若是是多线程程序,产生线程和线程运行所消耗的内存也是能够控制的,须要经过必定时间的观测后,配置最优结果
 
3. 介绍JVM中7个区域,而后把每一个区域可能形成内存的溢出的状况说明

JVM

一、内存模型以及分区,须要详细到每一个区放什么。

JVM 分为堆区和栈区,还有方法区,初始化的对象放在堆里面,引用放在栈里面,class类信息常量池等放在方法区

二、堆里面的分区:Eden,survival (from+ to),老年代,各自的特色。

堆里面分为新生代和老生代,新生代包含Eden+Survivor区,survivor区里面分为from和to区,内存回收时,用的是复制算法,从from复制到to,当通过一次或者屡次GC以后,存活下来的对象会被移动到老年区,当JVM内存不够用的时候,会触发Full GC,清理JVM老年区

当新生区满了以后会触发YGC,先把存活的对象放到其中一个Survice区,而后进行垃圾清理。由于若是仅仅清理须要删除的对象,这样会致使内存碎片,所以通常会把Eden 进行彻底的清理,而后整理内存。那么下次GC 的时候,就会使用下一个Survive,这样循环使用。若是有特别大的对象,新生代放不下,就会使用老年代的担保,直接放到老年代里面。由于JVM 认为,通常大对象的存活时间通常比较久远。

三、对象建立方法,对象的内存分配,对象的访问定位。

new 一个对象

四、GC的两种断定方法:

引用计数法:指的是若是某个地方引用了这个对象就+1,若是失效了就-1,当为0就会回收可是JVM没有用这种方式,由于没法断定相互循环引用(A引用B,B引用A)的状况

引用链法:  经过一种GC ROOT的对象(方法区中静态变量引用的对象等)来判断,若是有一条链可以到达GC ROOT就说明,不能到达GC ROOT就说明能够回收

五、GC的三种收集方法:标记清除、标记整理、复制算法的原理与特色,分别用在什么地方,若是让你优化收集方法,有什么思路?

先标记,标记完毕以后再清除,效率不高,会产生碎片

复制算法:分为8:1的Eden区和survivor区,就是上面谈到的YGC

标记整理:标记完毕以后,让全部存活的对象向一端移动 清除边缘之外的 

六、GC收集器有哪些?CMS收集器与G1收集器的特色。

CMS收集器是基于标记—清除”算法实现的,它的运做过程相对于前面几种收集器来讲更复杂一些

G1从总体来看是基于“标记—整理算法实现的收集器从局部(两个Region之间)上来看是基于“复制”算法实现的

GC收集器参见http://www.jianshu.com/p/50d5c88b272d

七、Minor GC与Full GC分别在何时发生?

新生代内存不够用时候发生MGC也叫YGC,JVM内存不够的时候发生FGC

八、几种经常使用的内存调试工具:jmap、jstack、jconsole。

jstack能够看当前栈的状况,jmap查看内存

九、类加载的五个过程:

加载、验证、准备、解析、初始化。而后是使用和卸载了

经过全限定名来加载生成class对象,而后进行验证这个class文件,包括元数据验证,字节码校验等。准备是对这个静态变量对象分配内存并初始化 为0。解析是将符号引用转化为直接引用(指针引用),初始化就是开始执行构造器的代码

十、双亲委派模型:Bootstrap ClassLoader、Extension ClassLoader、ApplicationClassLoader。

Bootstrap ClassLoader:启动类加载器,负责将$ Java_Home/lib下面的类库加载到内存中(好比rt.jar

Extension ClassLoader:标准扩展(Extension)类加载器,它负责将$Java_Home /lib/ext或者由系统变量 java.ext.dir指定位置中的类库加载到内存中。

ApplicationClassLoader:它负责将系统类路径(CLASSPATH)中指定的类库加载到内存中。开发者能够直接使用系统类加载器

十一、双亲委派模型是某个特定的类加载器在接到加载类的请求时,首先将加载任务委托给父类加载器,依次递归,若是父类加载器能够完成类加载任务,就成功返回;只有父类加载器没法完成此加载任务时,才本身去加载。-----例如类java.lang.Object,它存在在rt.jar中,不管哪个类加载器要加载这个类,最终都是委派给处于模型最顶端的Bootstrap ClassLoader进行加载,所以Object类在程序的各类类加载器环境中都是同一个类。相反,若是没有双亲委派模型而是由各个类加载器自行加载的话,若是用户编写了一个java.lang.Object的同名类并放在ClassPath中,那系统中将会出现多个不一样的Object类,程序将混乱

十二、分派:静态分派(重载)与动态分派(重写)。

1三、你知道哪些JVM性能调优

设定堆内存大小-Xms

-Xmx:堆内存最大限制。

设定新生代大小。新生代不宜过小,不然会有大量对象涌入老年代

-XX:NewSize:新生代大小

-XX:NewRatio  新生代和老生代占比

-XX:SurvivorRatio:伊甸园空间和幸存者空间的占比

设定垃圾回收器

​        年轻代用  -XX:+UseParNewGC  年老代用-XX:+UseConcMarkSweepGC



做者:itar
连接:https://www.jianshu.com/p/763ade0c7267
來源:简书
著做权归做者全部。商业转载请联系做者得到受权,非商业转载请注明出处。
 
4. 介绍GC 和GC Root不正常引用。
 
5. 本身从classload 加载方式,加载机制说开去,从程序运行时数据区,讲到内存分配,讲到String常量池,讲到JVM垃圾回收机制,算法,hotspot。反正就是各类扩展
     程序运行数据区: http://www.cnblogs.com/lrh-xl/p/5277585.html
     内存分配:      http://javawebsoa.iteye.com/blog/1558776
 
6. jvm 如何分配直接内存, new 对象如何不分配在堆而是栈上,常量池解析
 
7. 数组多大放在 JVM 老年代(不仅是设置 PretenureSizeThreshold ,问一般多大,没作过一问便知)     
 
8. 老年代中数组的访问方式
     
9. GC 算法,永久代对象如何 GC , GC 有环怎么处理
     

针对HotSpot VM的实现,它里面的GC其实准确分类只有两大种:

  • Partial GC:并不收集整个GC堆的模式
    • Young GC:只收集young gen的GC
    • Old GC:只收集old gen的GC。只有CMS的concurrent collection是这个模式
    • Mixed GC:收集整个young gen以及部分old gen的GC。只有G1有这个模式
  • Full GC:收集整个堆,包括young gen、old gen、perm gen(若是存在的话)等全部部分的模式。

Major GC一般是跟full GC是等价的,收集整个GC堆。但由于HotSpot VM发展了这么多年,外界对各类名词的解读已经彻底混乱了,当有人说“major GC”的时候必定要问清楚他想要指的是上面的full GC仍是old gen。

最简单的分代式GC策略,按HotSpot VM的serial GC的实现来看,触发条件是:

  • young GC:当young gen中的eden区分配满的时候触发。注意young GC中有部分存活对象会晋升到old gen,因此young GC后old gen的占用量一般会有所升高。
  • full GC:当准备要触发一次young GC时,若是发现统计数听说以前young GC的平均晋升大小比目前old gen剩余的空间大,则不会触发young GC而是转为触发full GC(由于HotSpot VM的GC里,除了CMS的concurrent collection以外,其它能收集old gen的GC都会同时收集整个GC堆,包括young gen,因此不须要事先触发一次单独的young GC);或者,若是有perm gen的话,要在perm gen分配空间但已经没有足够空间时,也要触发一次full GC;或者System.gc()、heap dump带GC,默认也是触发full GC。

HotSpot VM里其它非并发GC的触发条件复杂一些,不过大体的原理与上面说的其实同样。
固然也总有例外。Parallel Scavenge(-XX:+UseParallelGC)框架下,默认是在要触发full GC前先执行一次young GC,而且两次GC之间能让应用程序稍微运行一小下,以期下降full GC的暂停时间(由于young GC会尽可能清理了young gen的死对象,减小了full GC的工做量)。这是HotSpot VM里的奇葩嗯。

并发GC的触发条件就不太同样。以CMS GC为例,它主要是定时去检查old gen的使用量,当使用量超过了触发比例就会启动一次CMS GC,对old gen作并发收集。(RednaxelaFX——知乎)

Java的GC原理不是引用计数,因此即便有环,只要他是从GC Root不可达的,一样也会被收集。
 
10. 谁会被 GC ,何时 GC
      程序认为的死去的对象,也就是不可达对象会被GC。
 
11. 若是想不被 GC 怎么办
      不被GC,建立对象的强引用,并一直不释放
 
12. 若是想在 GC 中生存 1 次怎么办
      生存一次,释放掉对象的引用,可是在对象的finalize方法中从新创建引用,可是有一此方法只会被调用一次,因此能在GC中生存一次
 
13.如何在JVM虚拟机挂掉的时候,作一些操做,例如发邮件通知
      能够使用Runtime里面的addShutdownHook(Thread hook)方法,把JVM挂掉的时候所须要启动的线程注册到runtime中,就能够帮你完成这个动做
     

5、开源框架


 
1. hibernate和ibatis的区别
     
  1. hibernate 是当前最流行的o/r mapping框架,它出身于sf.net,如今已经成为jboss的一部分了。  
  2. ibatis 是另一种优秀的o/r mapping框架,目前属于apache的一个子项目了。   
  3. 相对hibernate“o/r”而言,ibatis是一种“sql mapping”的orm实现。   
  4. hibernate对数据库结构提供了较为完整的封装,hibernate的o/r mapping实现了pojo 和数据库表之间的映射,以及sql 的自动生成和执行。程序员每每只需定义好了pojo 到数据库表的映射关系,便可经过hibernate 提供的方法完成持久层操做。程序员甚至不须要对sql 的熟练掌握, hibernate/ojb 会根据制定的存储逻辑,自动生成对应的sql 并调用jdbc 接口加以执行。   
  5. 而ibatis 的着力点,则在于pojo 与sql之间的映射关系。也就是说,ibatis并不会为程序员在运行期自动生成sql 执行。具体的sql 须要程序员编写,而后经过映射配置文件,将sql所需的参数,以及返回的结果字段映射到指定pojo。   
  6. 使用ibatis 提供的orm机制,对业务逻辑实现人员而言,面对的是纯粹的java对象。  
  7. 这一层与经过hibernate 实现orm 而言基本一致,而对于具体的数据操做,hibernate会自动生成sql 语句,而ibatis 则要求开发者编写具体的sql 语句。相对hibernate而言,ibatis 以sql开发的工做量和数据库移植性上的让步,为系统设计提供了更大的自由空间。   
  8. hibernate与ibatis的对比:  
  9. 1.ibatis很是简单易学,hibernate相对较复杂,门槛较高。   
  10. 2.两者都是比较优秀的开源产品   
  11. 3.当系统属于二次开发,没法对数据库结构作到控制和修改,那ibatis的灵活性将比hibernate更适合   
  12. 4.系统数据处理量巨大,性能要求极为苛刻,这每每意味着咱们必须经过通过高度优化的sql语句(或存储过程)才能达到系统性能设计指标。在这种状况下ibatis会有更好的可控性和表现。   
  13. 5.ibatis须要手写sql语句,也能够生成一部分,hibernate则基本上能够自动生成,偶尔会写一些hql。一样的需求,ibatis的工做量比hibernate要大不少。相似的,若是涉及到数据库字段的修改,hibernate修改的地方不多,而ibatis要把那些sql mapping的地方一一修改。   
  14. 6.以数据库字段一一对应映射获得的po和hibernte这种对象化映射获得的po是大相径庭的,本质区别在于这种po是扁平化的,不像hibernate映射的po是能够表达立体的对象继承,聚合等等关系的,这将会直接影响到你的整个软件系统的设计思路。   
  15. 7.hibernate如今已是主流o/r mapping框架,从文档的丰富性,产品的完善性,版本的开发速度都要强于ibatis。  
 
2. 讲讲mybatis的链接池。
     参考: http://www.tuicool.com/articles/RvqEjeR   
 
3. spring框架中须要引用哪些jar包,以及这些jar包的用途
 
4. springMVC的原理
 
5. springMVC注解的意思
     参考:  http://aijuans.iteye.com/blog/2160141  
 
6. spring中beanFactory和ApplicationContext的联系和区别
  1. 做用:  
  2.   
  3. 1. BeanFactory负责读取bean配置文档,管理bean的加载,实例化,维护bean之间的依赖关系,负责bean的声明周期。  
  4. 2. ApplicationContext除了提供上述BeanFactory所能提供的功能以外,还提供了更完整的框架功能:  
  5.   
  6. a. 国际化支持  
  7. b. 资源访问:Resource rs = ctx. getResource(“classpath:config.properties”), “file:c:/config.properties”  
  8. c. 事件传递:经过实现ApplicationContextAware接口  
  9. 3. 经常使用的获取ApplicationContext的方法:  
  10. FileSystemXmlApplicationContext:从文件系统或者url指定的xml配置文件建立,参数为配置文件名或文件名数组  
  11. ClassPathXmlApplicationContext:从classpath的xml配置文件建立,能够从jar包中读取配置文件  
  12. WebApplicationContextUtils:从web应用的根目录读取配置文件,须要先在web.xml中配置,能够配置监听器或者servlet来实现  
  13. <listener>  
  14. <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>  
  15. </listener>  
  16. <servlet>  
  17. <servlet-name>context</servlet-name>  
  18. <servlet-class>org.springframework.web.context.ContextLoaderServlet</servlet-class>  
  19. <load-on-startup>1</load-on-startup>  
  20. </servlet>  
  21. 这两种方式都默认配置文件为web-inf/applicationContext.xml,也可以使用context-param指定配置文件  
  22. <context-param>  
  23. <param-name>contextConfigLocation</param-name>  
  24. <param-value>/WEB-INF/myApplicationContext.xml</param-value>  
  25. </context-param>  
7. spring注入的几种方式(循环注入)
 
8. spring如何实现事物管理的
 
9. springIOC
 
10. spring AOP的原理
 
11. hibernate中的1级和2级缓存的使用方式以及区别原理(Lazy-Load的理解)
     参考:  http://www.jb51.net/article/75161.htm   
 
12. Hibernate的原理体系架构,五大核心接口,Hibernate对象的三种状态转换,事务管理。

6、多线程


 
1. Java建立线程以后,直接调用start()方法和run()的区别
     参考:  http://www.tuicool.com/articles/7nyEziU   
 
2. 经常使用的线程池模式以及不一样线程池的使用场景
 
3. newFixedThreadPool此种线程池若是线程数达到最大值后会怎么办,底层原理。
 
4. 多线程之间通讯的同步问题,synchronized锁的是对象,衍伸出和synchronized相关不少的具体问题,例如同一个类不一样方法都有synchronized锁,一个对象是否能够同时访问。或者一个类的static构造方法加上synchronized以后的锁的影响。
 
5. 了解可重入锁的含义,以及ReentrantLock 和synchronized的区别
 
6. 同步的数据结构,例如concurrentHashMap的源码理解以及内部实现原理,为何他是同步的且效率高
 
7. atomicinteger和volatile等线程安全操做的关键字的理解和使用
 
8. 线程间通讯,wait和notify
     参考:  http://www.jb51.net/article/40746.htm   
 3. 为何在执行wait, notify时,必须得到该对象的锁?
这是由于,若是没有锁,wait和notify有可能会产生竞态条件(Race Condition)。考虑如下生产者和消费者的情景:
1.1生产者检查条件(如缓存满了)-> 1.2生产者必须等待
2.1消费者消费了一个单位的缓存 -> 2.2从新设置了条件(如缓存没满) -> 2.3调用notifyAll()唤醒生产者
咱们但愿的顺序是: 1.1->1.2->2.1->2.2->2.3
但在多线程状况下,顺序有多是 1.1->2.1->2.2->2.3->1.2。也就是说,在生产者还没wait以前,消费者就已经notifyAll了,这样的话,生产者会一直等下去。
因此,要解决这个问题,必须在wait和notifyAll的时候,得到该对象的锁,以保证同步
9. 定时线程的使用
     参考:  http://www.2cto.com/kf/201502/376021.html   
 
10. 场景:在一个主线程中,要求有大量(不少不少)子线程执行完以后,主线程才执行完成。多种方式,考虑效率。
     参考:  http://www.tuicool.com/articles/ZvAFny   
 
11. 进程和线程的区别
 
12. 什么叫线程安全?举例说明
     
  1. 线程安全:若是你的代码所在的进程中有多个线程在同时运行,而这些线程可能会同时运行这段代码。若是每次运行结果和单线程运行的结果是同样的,并且其余的变量的值也和预期的是同样的,就是线程安全的。或者说:一个类或者程序所提供的接口对于线程来讲是原子操做或者多个线程之间的切换不会致使该接口的执行结果存在二义性,也就是说咱们不用考虑同步的问题  
 
13. 线程的几种状态
 
14. 并发、同步的接口或方法
     
  1. 1:线程池  
  2.   
  3.    与每次须要时都建立线程相比,线程池能够下降建立线程的开销,这也是由于线程池在线程执行结束后进行的是回收操做,而不是真正的  
  4.   
  5.  销毁线程。  
  6.   
  7. 2:ReentrantLock  
  8.   
  9.     ReentrantLock提供了tryLock方法,tryLock调用的时候,若是锁被其余线程持有,那么tryLock会当即返回,返回结果为false,若是锁没有被  
  10.   
  11. 其余线程持有,那么当前调用线程会持有锁,而且tryLock返回的结果是true,  
  12.   
  13.   lock.lock();  
  14.   
  15.   try {  
  16.   
  17.       //do something   
  18.   
  19.   } finally {  
  20.   
  21.       lock.unlock();  
  22.   
  23.    }  
  24.   
  25. 3:volatile  
  26.   
  27.      保证了同一个变量在多线程中的可见性,不能够被缓存,由于volatile保证了只有一份主存中的数据。  
  28.   
  29. 4:Atomics  
  30.   
  31.        public class Count {  
  32.   
  33.             private AtomicInteger counter = new AtomicInteger();  
  34.   
  35.            public int increase() {  
  36.   
  37.                 return counter.incrementAndGet();  
  38.   
  39.            }  
  40.   
  41.           public int decrease() {  
  42.   
  43.                return counter.decrementAndGet();  
  44.   
  45.           }  
  46.   
  47.       }  
  48.   
  49.  AtomicInteger内部经过JNI的方式使用了硬件支持的CAS指令。  
  50.   
  51. 5:CountDownLatch  
  52.   
  53.       它是java.util.concurrent包中的一个类,它主要提供的机制是当多个(具体数量等于初始化CountDown时的count参数的值)线程都到达了预期状态  
  54.   
  55. 或完成预期工做时触发事件,其余线程能够等待这个事件来出发本身后续的工做,等待的线程能够是多个,即CountDownLatch是能够唤醒多个等待  
  56.   
  57. 的线程的,到达本身预期状态的线程会调用CountDownLatch的countDown方法,而等待的线程会调用CountDownLatch的await方法  
  58.   
  59. 6:CyclicBarrier  
  60.     循环屏障,CyclicBarrier能够协同多个线程,让多个线程在这个屏障前等待,直到全部线程都到达了这个屏障时,再一块儿继续执行后面的动做。  
  61.    CyclicBarrier和CountDownLatch都是用于多个线程间的协调的,两者的一个很大的差异是,CountDownLatch是在多个线程都进行了latch.countDown  
  62. 后才会触发事件,唤醒await在latch上的线程,而执行countDown的线程,执行完countDown后,会继续本身线程的工做;  
  63.    CyclicBarrier是一个栅栏,用于同步全部调用await方法的线程,而且等全部线程都到了await方法,这些线程才一块儿返回继续各自的工做,由于使用CyclicBarrier的线程都会阻塞在await方法上,因此在线程池中使用CyclicBarrier时要特别当心,若是线程池的线程 数过少,那么就会发生死锁了,  
  64. CyclicBarrier能够循环使用,CountDownLatch不能循环使用。  
  65. 7:Semaphore  
  66.    是用于管理信号量的,构造的时候传入可供管理的信号量的数值,信号量对量管理的信号就像令牌,构造时传入个数,总数就是控制并发的数量。  
  67.     semaphore.acquire();  
  68.     try {  
  69.         //调用远程通讯的方法 
  70.     } finally () {    
  71.        semahore.release();  
  72.     }  
  73. 8:Exchanger  
  74.    Exchanger,从名字上讲就是交换,它用于在两个线程之间进行数据交换,线程会阻塞在Exchanger的exchange方法上,直到另外一个线程也到了   
  75. 同一个Exchanger的exchange方法时,两者进行交换,而后两个线程会继续执行自身相关的代码。  
  76. 9:Future和FutureTask  
  77.   
  78.    Future<HashMap> future = getDataFromRemote2();  
  79.   
  80.    //do something  
  81.   
  82.    HashMap data = (HashMap)future.get();  
  83.   
  84.     
  85.   
  86.   private Future<HashMap> getDateFromRemote2() {  
  87.   
  88.       return threadPool.submit(new Callable<HashMap>() {  
  89.   
  90.             public HashMap call() {  
  91.   
  92.                    return getDataFromRemote();  
  93.             }  
  94.       });  
  95.   }  
  96.   
  97. 思路:调用函数后立刻返回,而后继续向下执行,急须要数据时再来用,或者说再来等待这个数据,具体实现方式有两种,一个是用Future,另外一个使用回调。  
     
 
15. HashMap 是否线程安全,为什么不安全。 ConcurrentHashMap,线程安全,为什么安全。底层实现是怎么样的。
 
16. J.U.C下的常见类的使用。 ThreadPool的深刻考察; BlockingQueue的使用。(take,poll的区别,put,offer的区别);原子类的实现。
 
17. 简单介绍下多线程的状况,从创建一个线程开始。而后怎么控制同步过程,多线程经常使用的方法和结构
 
18. volatile的理解
 
19. 实现多线程有几种方式,多线程同步怎么作,说说几个线程里经常使用的方法
                    http://blog.csdn.net/you_off3/article/details/7572704   
    

7、网络通讯


 
1. http是无状态通讯,http的请求方式有哪些,能够本身定义新的请求方式么。
 
2. socket通讯,以及长链接,分包,链接异常断开的处理。
 
3. socket通讯模型的使用,AIO和NIO。
     参考:AIO: http://www.52im.net/thread-306-1-1.html 
               NIO: http://www.cnblogs.com/dolphin0520/p/3916526.html 
 
4. socket框架netty的使用,以及NIO的实现原理,为何是异步非阻塞。
              
 
5. 同步和异步,阻塞和非阻塞。
 
6. OSI七层模型,包括TCP,IP的一些基本知识
 
7. http中,get post的区别
 
8. 说说http,tcp,udp之间关系和区别。
 

.TCP/IP表明传输控制协议/网际协议,指的是一系列协组。

  可分为四个层次:数据链路层、网络层、传输层和应用层。

在网络层:有IP协议、ICMP协议、ARP协议、RARP协议和BOOTP协议。
在传输层:中有TCP协议与UDP协议。
在应用层:有FTP、HTTP、TELNET、SMTP、DNS等协议。

  TCP和UDP使用IP协议从一个网络传送数据包到另外一个网络。把IP想像成一种高速公路,它容许其它协议在上面行驶并找到到其它电脑的出口。TCP和UDP是高速公路上的“卡车”,它们携带的货物就是像HTTP,文件传输协议FTP这样的协议等。
       TCP和UDP是FTP,HTTP和SMTP之类使用的传输层协议。虽然TCP和UDP都是用来传输其余协议的,它们却有一个显著的不一样:TCP提供有保证的数据传输,而UDP不提供。这意味着TCP有一个特殊的机制来确保数据安全的不出错的从一个端点传到另外一个端点,而UDP不提供任何这样的保证。

二.HTTP自己就是一个协议,是从Web服务器传输超文本到本地浏览器的传送协议。

  HTTP(超文本传输协议)是利用TCP在两台电脑(一般是Web服务器和客户端)之间传输信息的协议。客户端使用Web浏览器发起HTTP请求给Web服务器,Web服务器发送被请求的信息给客户端。

复制代码
    HTTP协议是创建在请求/响应模型上的。首先由客户创建一条与服务器的TCP连接,并发送一个请求到服务器,请求中包含请求方法、URL、协议版本以及
相关的MIME样式的消息。服务器响应一个状态行,包含消息的协议版本、一个成功和失败码以及相关的MIME式样的消息。 HTTP/1.0为每一次HTTP的请求/响应创建一条新的TCP连接,所以一个包含HTML内容和图片的页面将须要创建屡次的短时间的TCP连接。一次TCP连接的创建
将须要3次握手。 另外,为了得到适当的传输速度,则须要TCP花费额外的回路连接时间(RTT)。每一次连接的创建须要这种常常性的开销,而其并不带有实际有用的数据
,只是保证连接的可靠性,所以HTTP/1.1提出了可持续连接的实现方法。HTTP/1.1将只创建一次TCP的连接而重复地使用它传输一系列的请求/响应消息,
所以减小了连接创建的次数和常常性的连接开销。
复制代码

  虽然HTTP自己是一个协议,但其最终仍是基于TCP的。

三.SOCKET:TCP/IP网络的API。

 

  Socket是应用层与TCP/IP协议族通讯的中间软件抽象层,它是一组接口。在设计模式中,Socket其实就是一个门面模式,它把复杂的TCP/IP协议族隐藏在Socket接口后面,对用户来讲,一组简单的接口就是所有,让Socket去组织数据,以符合指定的协议。

  Socket 接口是TCP/IP网络的API,Socket接口定义了许多函数或例程,用以开发TCP/IP网络上的应用程序。

    这是为了实现以上的通讯过程而创建成来的通讯管道,其真实的表明是客户端和服务器端的一个通讯进程,双方进程经过socket进行通讯,而通讯的规则
采用指定的协议。socket只是一种链接模式,不是协议,tcp,udp,简单的说(虽然不许确)是两个最基本的协议,不少其它协议都是基于这两个协议如,http
就是基于tcp的,用socket能够建立tcp链接,也能够建立udp链接,这意味着,用socket能够建立任何协议的链接,由于其它协议都是基于此的。

 

综上所述:须要IP协议来链接网络;TCP是一种容许咱们安全传输数据的机制,使用TCP协议来传输数据的HTTP是Web服务器和客户端使用的特殊协议。HTTP基于TCP协议,可是却能够使用socket去创建一个TCP链接。

9. 说说浏览器访问www.taobao.com,经历了怎样的过程。
 

假设你用一个全新的浏览器(第一次启动的那种),访问百度(http://www.baidu.com/),在你敲入网址并按下回车以后,将会发生如下神奇的事情:

浏览器先尝试从Host文件中获取http://www.baidu.com/对应的IP地址,若是能取到固然万事大吉你们都能嗨,若是不能,就使用DNS协议来获取IP咯。
在DNS协议中,PC会向你的本地DNS服务器求助(通常是路由器),但愿从本地DNS服务器那里获得百度的IP,获得就好,得不到还得向更高层次的DNS服务器求助,最终总能获得百度的IP。

获得百度的IP,下一步是使用TCP协议,创建TCP链接。
在TCP协议中,创建TCP须要与百度服务器握手三次,你先告诉服务器你要给服务器发东西(SYN),服务器应答你并告诉你它也要给你发东西(SYN、ACK),而后你应答服务器(ACK),总共来回了3次,称为3次握手。

不过,创建TCP链接有个前提(或者说给服务器发消息有个前提):你必须能成功地把消息发到服务器上。虽然已经知道IP,但并没有啥用(好比说,你在广东,你知道北京的地理坐标经纬度就能到北京了?你得知道有哪些路通往北京吧你得准备盘缠吧你得花时间吧)。

为了将消息从你的PC上传到服务器上,须要用到IP协议、ARP协议和OSPF协议。
咱们都知道,你的PC和百度服务器之间通常会有许多路由器之类的东西,IP协议指定了出发地(你的PC)和目的地(服务器);你的数据会通过一个又一个路由器,OSPF决定了会通过那些路由器(用一种叫路由算法的玩意,找出最佳路径);从一个路由器怎么传给下一个路由器?这是ARP协议的JOB,ARP负责求下一个节点的地址(咱们不止是要目的地,还要中间节点的地址)。
IP协议使用的是IP地址,整个发送过程当中只涉及出发地和目的地2个IP地址,而ARP协议使用的是MAC地址,整个发送过程当中涉及到每个节点的MAP地址

如今,咱们能和服务器通讯,还创建了TCP链接,下一步干吗,固然是用HTTP协议请求网页内容咯。

你发个HTTP请求报文给服务器,若是服务器禁止你访问它就给你回个"Forbidden",若是它暂时挂掉了就给你回个“内部服务错误”,若是它正常才给你回个“OK“并将你要的数据传给你;若是你还须要其它的东西再去跟它要(它通常还会给你的-_-)。

你收到了服务器的回复,是一坨HTML形式的文本。浏览器必需要可以理解文本的内容,并快速地渲染到屏幕上(浏览器通常用有限自动机来理解文本内容,渲染的话就各看本事了,之因此微软IE卡成狗而谷歌浏览器很6,就是它们的渲染速度不一样...)

渲染出来后,你就看到百度的首页了
 
 
10. HTTP协议、  HTTPS协议,SSL协议及完整交互过程;
 

5.     HTTP与HTTPS的区别:

1)     https协议须要申请证书。

2)     http是超文本传输协议,

3)     http端口80,;https端口443。

4)     http链接简单无状态;https由SSL+HTTP协议构件的可进行加密传输、身份验证的网络协议。

11. tcp的拥塞,快回传,ip的报文丢弃
 

拥塞避免

从慢启动能够看到,cwnd能够很快的增加上来,从而最大程度的利用网络带宽资源,可是cwnd不能一直这样无限增加下去,必定须要某个限制。TCP使用了一个叫慢启动门限(ssthresh)的变量,当cwnd超过该值后,慢启动过程结束,进入拥塞避免阶段。对于大多数TCP实现来讲,ssthresh的值是65536(一样以字节计算)。拥塞避免的主要思想是加法增大,也就是cwnd的值再也不指数级往上升,开始加法增长。此时当窗口中全部的报文段都被确认时,cwnd的大小加1,cwnd的值就随着RTT开始线性增长,这样就能够避免增加过快致使网络拥塞,慢慢的增长调整到网络的最佳值。

快速重传

其实TCP还有一种状况会进行重传:那就是收到3个相同的ACK。TCP在收到乱序到达包时就会当即发送ACK,TCP利用3个相同的ACK来断定数据包的丢失,此时进行快速重传,快速重传作的事情有: 
1.把ssthresh设置为cwnd的一半 
2.把cwnd再设置为ssthresh的值+3 
3.从新进入拥塞避免阶段

12. https处理的一个过程,对称加密和非对称加密
 
13. head各个特色和区别
     参考:
 
8、数据库MySql

 
1. MySql的存储引擎的不一样
 
2. 单个索引、联合索引、主键索引
     
 
3. Mysql怎么分表,以及分表后若是想按条件分页查询怎么办(若是不是按分表字段来查询的话,几乎效率低下,无解)

1)、作mysql集群,例如:利用mysql cluster ,mysql proxy,mysql replication,drdb等等

优势:扩展性好,没有多个分表后的复杂操做(php代码)

缺点:单个表的数据量仍是没有变,一次操做所花的时间仍是那么多,硬件开销大。

2)、预先估计会出现大数据量而且访问频繁的表,将其分为若干个表

优势:避免一张表出现几百万条数据,缩短了一条sql的执行时间

缺点:当一种规则肯定时,打破这条规则会很麻烦,上面的例子中我用的hash算法是crc32,若是我如今不想用这个算法了,改用md5后,会使同一个用户的消息被存储到不一样的表中,这样数

据乱套了。扩展性不好。

3)、利用merge存储引擎来实现分表

优势:扩展性好,而且程序代码改动的不是很大

缺点:这种方法的效果比第二种要差一点
 
4. 分表以后想让一个id多个表是自增的,效率实现
 
5. MySql的主从实时备份同步的配置,以及原理(从库读主库的binlog),读写分离

6. 写SQL语句。。。

 
7. 索引的数据结构,B+树

MySQL数据库支持多种索引类型,如BTree索引,哈希索引,全文索引等等

MySQL就广泛使用B+Tree实现其索引结构
 
8. 事务的四个特性,以及各自的特色(原子、隔离)等等,项目怎么解决这些问题
 
 
9. 数据库的锁:行锁,表锁;乐观锁,悲观锁
     

mysql中有一种机制是表锁定和行锁定,为何要出现这种机制,是为了保证数据的完整性

举个例子来讲吧,若是有二个sql都要修改同一张表的同一条数据,这个时候怎么办呢,是否是二个sql均可以同时修改这条数据呢?

很显然mysql对这种状况的处理是,一种是表锁定(myisam存储引擎),一个是行锁定(innodb存储引擎)。

表锁定表示大家都不能对这张表进行操做,必须等我对表操做完才行。行锁定同样
 
10. 数据库事务的几种粒度;
     数据库级、表级、记录级(行级)和属性级(字段级)
 
11. 关系型和非关系型数据库区别
 nosql和关系型数据库比较?
优势:
1)成本:nosql数据库简单易部署,基本都是开源软件,不须要像使用oracle那样花费大量成本购买使用,相比关系型数据库价格便宜。
2)查询速度:nosql数据库将数据存储于缓存之中,关系型数据库将数据存储在硬盘中,天然查询速度远不及nosql数据库。
3)存储数据的格式:nosql的存储格式是key,value形式、文档形式、图片形式等等,因此能够存储基础类型以及对象或者是集合等各类格式,而数据库则只支持基础类型。
4)扩展性:关系型数据库有相似join这样的多表查询机制的限制致使扩展很艰难。
缺点:
1)维护的工具和资料有限,由于nosql是属于新的技术,不能和关系型数据库10几年的技术同日而语。
2)不提供对sql的支持,若是不支持sql这样的工业标准,将产生必定用户的学习和使用成本。

3)不提供关系型数据库对事物的处理。

 

 

非关系型数据库的优点:1. 性能NOSQL是基于键值对的,能够想象成表中的主键和值的对应关系,并且不须要通过SQL层的解析,因此性能很是高。2. 可扩展性一样也是由于基于键值对,数据之间没有耦合性,因此很是容易水平扩展。

关系型数据库的优点:1. 复杂查询能够用SQL语句方便的在一个表以及多个表之间作很是复杂的数据查询。2. 事务支持使得对于安全性能很高的数据访问要求得以实现。对于这两类数据库,对方的优点就是本身的弱势,反之亦然。

 

12.数据库的隔离级别:

脏读: 脏读就是指当一个事务正在访问数据,而且对数据进行了修改,而这种修改尚未提交到数据库中,这时,另一个事务也访问这个数据,而后使用了这个数据。

不可重复读:是指在一个事务内,屡次读同一数据。在这个事务尚未结束时,另一个事务也访问该同一数据。那么,在第一个事务中的两次读数据之间,因为第二个事务的修改,那么第一

个事务两次读到的的数据多是不同的。这样就发生了在一个事务内两次读到的数据是不同的,所以称为是不可重复读。

幻读:第一个事务对一个表中的数据进行了修改,这种修改涉及到表中的所有数据行。同时,第二个事务也修改这个表中的数据,这种修改是向表中插入一行新数据。那么,之后就会发生操做第

一个事务的用户发现表中还有没有修改的数据行,就好象发生了幻觉同样。

未提交读(Read Uncommitted):容许脏读,也就是可能读取到其余会话中未提交事务修改的数据

提交读(Read Committed):只能读取到已经提交的数据。Oracle等多数数据库默认都是该级别 (不重复读)

可重复读(Repeated Read):可重复读。在同一个事务内的查询都是事务开始时刻一致的,InnoDB默认级别。在SQL标准中,该隔离级别消除了不可重复读,可是还存在幻象读

串行读(Serializable):彻底串行化的读,每次读都须要得到表级共享锁,读写相互都会阻塞

9、设计模式


 
1. 单例模式:饱汉、饿汉。以及饿汉中的延迟加载,双重检查
 
2. 工厂模式、装饰者模式、观察者模式。
 
3. 工厂方法模式的优势(低耦合、高内聚,开放封闭原则)

10、算法


 
1. 使用随机算法产生一个数,要求把1-1000W之间这些数所有生成。(考察高效率,解决产生冲突的问题)
 
2. 两个有序数组的合并排序
 
3. 一个数组的倒序
  public class T { 

  public static void main(String[] args) { 
char[] chars={'1','3','4','5','6'}; 
for(int i= 0 ; i < chars.length;i++){ 
char top =chars[0];//把数组的第一个提取出来,放进top 

         for(int j=1;j<chars.length-i;j++){ 

          chars[j-1]= chars[j];//将组数除第一个以外的其他数 向左边挪一位 


         chars[chars.length-i-1]=top;//将top 即原来数组的第一个数 赋予到数组的最后一位 




     System.out.println(chars); 
4. 计算一个正整数的正平方根
 
5. 说白了就是常见的那些查找、排序算法以及各自的时间复杂度
 
6. 二叉树的遍历算法
 
7. DFS,BFS算法
 
9. 比较重要的数据结构,如链表,队列,栈的基本理解及大体实现。
 
10. 排序算法与时空复杂度(快排为何不稳定,为何你的项目还在用)
 
11. 逆波兰计算器
 
12. Hoffman 编码
 
13. 查找树与红黑树
     

11、并发与性能调优


 
1. 有个每秒钟5k个请求,查询手机号所属地的笔试题(记得不完整,没列出),如何设计算法?请求再多,好比5w,如何设计整个系统?
 

这不是算法的问题吧,是架构设计。

一、服务器直接用数据库链接池从数据库拿数据,数据加索引,这是最原始方式,看看这个的承载量

二、1方式达不到需求就用数据缓存,好比redis,先从缓存取,取不到再从数据库取,取出来放入缓存,记得加个缓存时效,避免内存暴增。

三、利用集群和负载均衡,结合缓存技术,别说5k,就算5w都行

 
2. 高并发状况下,咱们系统是如何支撑大量的请求的

认清系统的高并发由3个层面致使:

1. 传输层

大量用户对系统请求后,将会形成网络带宽和Web服务器的I/O瓶颈

2. 计算层

接收大量用户请求进行计算,将会形成业务服务器和业务支撑服务器的瓶颈

3. 存储层

传输层和计算层将会产生大量的数据,数据量暴增将会致使数据库和储存上的瓶颈

高并发的解决方法有两种一种是使用缓存、另外一种是使用生成静态页面;

1.用分布式应用设计二、分布式缓存数据库三、代码优化

1.不要频繁的new对象,对于在整个应用中只须要存在一个实例的类使用单例模式.对于String的链接操做,使用StringBuffer或者

StringBuilder.对于utility类型的类经过静态方法来访问。

2. 避免使用错误的方式,如Exception能够控制方法推出,可是Exception要保留stacktrace消耗性能,除非必要不要使用 instanceof作条件判

断,尽可能使用比的条件判断方式.使用JAVA中效率高的类,好比ArrayList比Vector性能好。)

三、使用静态页面

补充:页面静态化
 
3. 集群如何同步会话状态
 
4. 负载均衡的原理
 
5 .若是有一个特别大的访问量,到数据库上,怎么作优化(DB设计,DBIO,SQL优化,Java优化)

表的设计具体注意的问题:

    一、数据行的长度不要超过8020字节,若是超过这个长度的话在物理页中这条数据会占用两行从而形成存储碎片,下降查询效率。
    二、可以用数字类型的字段尽可能选择数字类型而不用字符串类型的(电话号码),这会下降查询和链接的性能,并会增长存储开销。这是由于引擎在处理查询和链接回逐个比较字符串中每个字符,而对于数字型而言只须要比较一次就够了

    三、对于不可变字符类型char和可变字符类型varchar 都是8000字节,char查询快,可是耗存储空间,varchar查询相对慢一些可是节省存储空间。在设计字段的时候能够灵活选择,例如用户名、密码等长度变化不大的字段能够选择CHAR,对于评论等长度变化大的字段能够选择VARCHAR。

    四、字段的长度在最大限度的知足可能的须要的前提下应该尽量的设得短一些,这样能够提升查询的效率,并且在创建索引的时候也能够减小资源的消耗。


2、查询的优化 
保证在实现功能的基础上,尽可能减小对数据库的访问次数;经过搜索参数,尽可能减小对表的访问行数,最小化结果集,从而减轻网络负担;可以分开的操做尽可能分开处理,提升每次的响应速度;在数据窗口使用SQL时,尽可能把使用的索引放在选择的首列;算法的结构尽可能简单;在查询时,不要过多地使用通配符如SELECT * FROM T1语句,要用到几列就选择几列如:SELECT COL1,COL2 FROM T1;在可能的状况下尽可能限制尽可能结果集行数如:SELECT TOP 300 COL1,COL2,COL3 FROM T1,由于某些状况下用户是不须要那么多的数据的。   
在没有建索引的状况下,数据库查找某一条数据,就必须进行全表扫描了,对全部数据进行一次遍历,查找出符合条件的记录。在数据量比较小的状况下,也许看不出明显的差异,可是当数据量大的状况下,这种状况就是极为糟糕的了。
SQL语句在SQL SERVER中是如何执行的,他们担忧本身所写的SQL语句会被SQL SERVER误解。好比: 
select * from table1 where name='zhangsan' and tID > 10000 
和执行: 
select * from table1 where tID > 10000 and name='zhangsan' 
一些人不知道以上两条语句的执行效率是否同样,由于若是简单的从语句前后上看,这两个语句的确是不同,若是tID是一个聚合索引,那么后一句仅仅从表的10000条之后的记录中查找就好了;而前一句则要先从全表中查找看有几个name='zhangsan'的,然后再根据限制条件条件tID>10000来提出查询结果。 
事实上,这样的担忧是没必要要的。SQL SERVER中有一个“查询分析优化器”,它能够计算出where子句中的搜索条件并肯定哪一个索引能缩小表扫描的搜索空间,也就是说,它能实现自动优化。虽然查询优化器能够根据where子句自动的进行查询优化,但有时查询优化器就会不按照您的本意进行快速查询。 
在查询分析阶段,查询优化器查看查询的每一个阶段并决定限制须要扫描的数据量是否有用。若是一个阶段能够被用做一个扫描参数(SARG),那么就称之为可优化的,而且能够利用索引快速得到所需数据。 
SARG的定义:用于限制搜索的一个操做,由于它一般是指一个特定的匹配,一个值的范围内的匹配或者两个以上条件的AND链接。形式以下: 
列名 操做符 <常数 或 变量> 或 <常数 或 变量> 操做符 列名 
列名能够出如今操做符的一边,而常数或变量出如今操做符的另外一边。如: 
Name=’张三’ 
价格>5000 
5000<价格 
Name=’张三’ and 价格>5000 
若是一个表达式不能知足SARG的形式,那它就没法限制搜索的范围了,也就是SQL SERVER必须对每一行都判断它是否知足WHERE子句中的全部条件。因此一个索引对于不知足SARG形式的表达式来讲是无用的。 
    因此,优化查询最重要的就是,尽可能使语句符合查询优化器的规则避免全表扫描而使用索引查询。

具体要注意的:

1.应尽可能避免在 where 子句中对字段进行 null 值判断,不然将致使引擎放弃使用索引而进行全表扫描,如:
select id from t where num is null
能够在num上设置默认值0,确保表中num列没有null值,而后这样查询:
select id from t where num=0

2.应尽可能避免在 where 子句中使用!=或<>操做符,不然将引擎放弃使用索引而进行全表扫描。优化器将没法经过索引来肯定将要命中的行数,所以须要搜索该表的全部行。

3.应尽可能避免在 where 子句中使用 or 来链接条件,不然将致使引擎放弃使用索引而进行全表扫描,如:
select id from t where num=10 or num=20
能够这样查询:
select id from t where num=10
union all
select id from t where num=20

4.in 和 not in 也要慎用,由于IN会使系统没法使用索引,而只能直接搜索表中的数据。如:
select id from t where num in(1,2,3)
对于连续的数值,能用 between 就不要用 in 了:
select id from t where num between 1 and 3

5.尽可能避免在索引过的字符数据中,使用非打头字母搜索。这也使得引擎没法利用索引。 
见以下例子: 
SELECT * FROM T1 WHERE NAME LIKE ‘%L%’ 
SELECT * FROM T1 WHERE SUBSTING(NAME,2,1)=’L’ 
SELECT * FROM T1 WHERE NAME LIKE ‘L%’ 
即便NAME字段建有索引,前两个查询依然没法利用索引完成加快操做,引擎不得不对全表全部数据逐条操做来完成任务。而第三个查询可以使用索引来加快操做。

6.必要时强制查询优化器使用某个索引,如在 where 子句中使用参数,也会致使全表扫描。由于SQL只有在运行时才会解析局部变量,但优化程序不能将访问计划的选择推迟到运行时;它必须在编译时进行选择。然而,若是在编译时创建访问计划,变量的值仍是未知的,于是没法做为索引选择的输入项。以下面语句将进行全表扫描:
select id from t where num=@num
能够改成强制查询使用索引:
select id from t with(index(索引名)) where num=@num

7.应尽可能避免在 where 子句中对字段进行表达式操做,这将致使引擎放弃使用索引而进行全表扫描。如:
SELECT * FROM T1 WHERE F1/2=100 
应改成: 
SELECT * FROM T1 WHERE F1=100*2

SELECT * FROM RECORD WHERE SUBSTRING(CARD_NO,1,4)=’5378’ 
应改成: 
SELECT * FROM RECORD WHERE CARD_NO LIKE ‘5378%’

SELECT member_number, first_name, last_name FROM members 
WHERE DATEDIFF(yy,datofbirth,GETDATE()) > 21 
应改成: 
SELECT member_number, first_name, last_name FROM members 
WHERE dateofbirth < DATEADD(yy,-21,GETDATE()) 
即:任何对列的操做都将致使表扫描,它包括数据库函数、计算表达式等等,查询时要尽量将操做移至等号右边。

8.应尽可能避免在where子句中对字段进行函数操做,这将致使引擎放弃使用索引而进行全表扫描。如:
select id from t where substring(name,1,3)='abc'--name以abc开头的id
select id from t where datediff(day,createdate,'2005-11-30')=0--‘2005-11-30’生成的id
应改成:
select id from t where name like 'abc%'
select id from t where createdate>='2005-11-30' and createdate<'2005-12-1'

9.不要在 where 子句中的“=”左边进行函数、算术运算或其余表达式运算,不然系统将可能没法正确使用索引。

10.在使用索引字段做为条件时,若是该索引是复合索引,那么必须使用到该索引中的第一个字段做为条件时才能保证系统使用该索引,不然该索引将不会被使用,而且应尽量的让字段顺序与索引顺序相一致。

11.不少时候用 exists是一个好的选择:
elect num from a where num in(select num from b)
用下面的语句替换:
select num from a where exists(select 1 from b where num=a.num)

SELECT SUM(T1.C1)FROM T1 WHERE( 
(SELECT COUNT(*)FROM T2 WHERE T2.C2=T1.C2>0) 
SELECT SUM(T1.C1) FROM T1WHERE EXISTS( 
SELECT * FROM T2 WHERE T2.C2=T1.C2) 
二者产生相同的结果,可是后者的效率显然要高于前者。由于后者不会产生大量锁定的表扫描或是索引扫描。

若是你想校验表里是否存在某条纪录,不要用count(*)那样效率很低,并且浪费服务器资源。能够用EXISTS代替。如: 
IF (SELECT COUNT(*) FROM table_name WHERE column_name = 'xxx') 
能够写成: 
IF EXISTS (SELECT * FROM table_name WHERE column_name = 'xxx')

常常须要写一个T_SQL语句比较一个父结果集和子结果集,从而找到是否存在在父结果集中有而在子结果集中没有的记录,如: 
SELECT a.hdr_key FROM hdr_tbl a---- tbl a 表示tbl用别名a代替 
WHERE NOT EXISTS (SELECT * FROM dtl_tbl b WHERE a.hdr_key = b.hdr_key) 
SELECT a.hdr_key FROM hdr_tbl a 
LEFT JOIN dtl_tbl b ON a.hdr_key = b.hdr_key WHERE b.hdr_key IS NULL 
SELECT hdr_key FROM hdr_tbl 
WHERE hdr_key NOT IN (SELECT hdr_key FROM dtl_tbl) 
三种写法均可以获得一样正确的结果,可是效率依次下降。

12.尽可能使用表变量来代替临时表。若是表变量包含大量数据,请注意索引很是有限(只有主键索引)。

13.避免频繁建立和删除临时表,以减小系统表资源的消耗。

14.临时表并非不可以使用,适当地使用它们能够使某些例程更有效,例如,当须要重复引用大型表或经常使用表中的某个数据集时。可是,对于一次性事件,最好使用导出表。

15.在新建临时表时,若是一次性插入数据量很大,那么能够使用 select into 代替 create table,避免形成大量 log ,以提升速度;若是数据量不大,为了缓和系统表的资源,应先create table,而后insert。

16.若是使用到了临时表,在存储过程的最后务必将全部的临时表显式删除,先 truncate table ,而后 drop table ,这样能够避免系统表的较长时间锁定。 
17.在全部的存储过程和触发器的开始处设置 SET NOCOUNT ON ,在结束时设置 SET NOCOUNT OFF 。无需在执行存储过程和触发器的每一个语句后向客户端发送 DONE_IN_PROC 消息。

18.尽可能避免大事务操做,提升系统并发能力。

19.尽可能避免向客户端返回大数据量,若数据量过大,应该考虑相应需求是否合理。 
20. 避免使用不兼容的数据类型。例如float和int、char和varchar、binary和varbinary是不兼容的。数据类型的不兼容可能使优化器没法执行一些原本能够进行的优化操做。例如: 
SELECT name FROM employee WHERE salary > 60000 
在这条语句中,如salary字段是money型的,则优化器很难对其进行优化,由于60000是个整型数。咱们应当在编程时将整型转化成为钱币型,而不要等到运行时转化。

21.充分利用链接条件,在某种状况下,两个表之间可能不仅一个的链接条件,这时在 WHERE 子句中将链接条件完整的写上,有可能大大提升查询速度。 
例: 
SELECT SUM(A.AMOUNT) FROM ACCOUNT A,CARD B WHERE A.CARD_NO = B.CARD_NO 
SELECT SUM(A.AMOUNT) FROM ACCOUNT A,CARD B WHERE A.CARD_NO = B.CARD_NO AND A.ACCOUNT_NO=B.ACCOUNT_NO 
第二句将比第一句执行快得多。

2二、使用视图加速查询 
把表的一个子集进行排序并建立视图,有时能加速查询。它有助于避免多重排序 操做,并且在其余方面还能简化优化器的工做。例如:
SELECT cust.name,rcvbles.balance,……other columns 
FROM cust,rcvbles 
WHERE cust.customer_id = rcvlbes.customer_id 
AND rcvblls.balance>0 
AND cust.postcode>“98000” 
ORDER BY cust.name

若是这个查询要被执行屡次而不止一次,能够把全部未付款的客户找出来放在一个视图中,并按客户的名字进行排序: 
CREATE VIEW DBO.V_CUST_RCVLBES 
AS 
SELECT cust.name,rcvbles.balance,……other columns 
FROM cust,rcvbles 
WHERE cust.customer_id = rcvlbes.customer_id 
AND rcvblls.balance>0 
ORDER BY cust.name 
而后如下面的方式在视图中查询: 
SELECT * FROM V_CUST_RCVLBES 
WHERE postcode>“98000” 
视图中的行要比主表中的行少,并且物理顺序就是所要求的顺序,减小了磁盘I/O,因此查询工做量能够获得大幅减小。

2三、能用DISTINCT的就不用GROUP BY 
SELECT OrderID FROM Details WHERE UnitPrice > 10 GROUP BY OrderID 
可改成: 
SELECT DISTINCT OrderID FROM Details WHERE UnitPrice > 10

24.能用UNION ALL就不要用UNION 
UNION ALL不执行SELECT DISTINCT函数,这样就会减小不少没必要要的资源 
35.尽可能不要用SELECT INTO语句。 
SELECT INOT 语句会致使表锁定,阻止其余用户访问该表。

    上面咱们提到的是一些基本的提升查询速度的注意事项,可是在更多的状况下,每每须要反复试验比较不一样的语句以获得最佳方案。最好的方法固然是测试,看实现相同功能的SQL语句哪一个执行时间最少,可是数据库中若是数据量不多,是比较不出来的,这时能够用查看执行计划,即:把实现相同功能的多条SQL语句考到查询分析器,按CTRL+L看查所利用的索引,表扫描次数(这两个对性能影响最大),整体上看询成本百分比便可。 
3、算法的优化

尽可能避免使用游标,由于游标的效率较差,若是游标操做的数据超过1万行,那么就应该考虑改写。.使用基于游标的方法或临时表方法以前,应先寻找基于集的解决方案来解决问题,基于集的方法一般更有效。与临时表同样,游标并非不可以使用。对小型数据集使用 FAST_FORWARD 游标一般要优于其余逐行处理方法,尤为是在必须引用几个表才能得到所需的数据时。在结果集中包括“合计”的例程一般要比使用游标执行的速度快。若是开发时间容许,基于游标的方法和基于集的方法均可以尝试一下,看哪种方法的效果更好。
  游标提供了对特定集合中逐行扫描的手段,通常使用游标逐行遍历数据,根据取出的数据不一样条件进行不一样的操做。尤为对多表和大表定义的游标(大的数据集合)循环很容易使程序进入一个漫长的等特甚至死机。 
  在有些场合,有时也非得使用游标,此时也可考虑将符合条件的数据行转入临时表中,再对临时表定义游标进行操做,可时性能获得明显提升。
(例如:对内统计初版)
封装存储过程

4、创建高效的索引

  建立索引通常有如下两个目的:维护被索引列的惟一性和提供快速访问表中数据的策略。大型数据库有两种索引即簇索引和非簇索引,一个没有簇索引的表是按堆结构存储数据,全部的数据均添加在表的尾部,而创建了簇索引的表,其数据在物理上会按照簇索引键的顺序存储,一个表只容许有一个簇索引,所以,根据B树结构,能够理解添加任何一种索引均能提升按索引列查询的速度,但会下降插入、更新、删除操做的性能,尤为是当填充因子(Fill Factor)较大时。因此对索引较多的表进行频繁的插入、更新、删除操做,建表和索引时因设置较小的填充因子,以便在各数据页中留下较多的自由空间,减小页分割及从新组织的工做。 

 
6. 若是出现大面积并发,在不增长服务器的基础上,如何解决服务器响应不及时问题“
 

1. 提升CPU并发计算能力

多进程 & 多线程

 

减小进程切换

最简单的作法就是减小进程数,尽可能使用线程并配合其它I/O模型来设计并发策略

减小使用没必要要的锁

服务器处理大量并发请求时,多个请求处理任务时存在一些资源抢占竞争,这时通常采用“锁”机制来控制资源的占用,当一个任务占用资源时,咱们锁住资源,这时其它任务都在等待锁的释放,这个现象称为锁竞争。

进程调度器会动态调整运行队列中进程的优先级,经过top观察进程的PR值

2. 考虑减小内存分配和释放

例如Apache,在运行开始时一次申请大片的内存做为内存池,若随后须要时就在内存池中直接获取不须要再次分配避免了频繁的内存分配和释放引发的内存整理时间

3. 考虑使用持久链接

持久链接也为长链接,它自己是TCP通讯的一种普通方式,即在一次TCP链接中持续发送多分数据而不断开链接

4. 改进I/O 模型

2. 异步I/O

异步I/O指主动请求数据后即可以继续处理其它任务,随后等待I/O操做的通知,这样进程在数据读写时不发生阻塞。

异步I/O是非阻塞的,当函数返回时,真正的I/O传输已经完成,这让CPU处理和I/O操做达到很好的重叠。

6. 改进硬件环境

 
7. 假如你的项目出现性能瓶颈了,你以为可能会是哪些方面,怎么解决问题。
     
 
8. 如何查找 形成 性能瓶颈出现的位置,是哪一个位置照成性能瓶颈。
 
9. 你的项目中使用过缓存机制吗?有没用用户非本地缓存
     redis 缓存 hibernate 的session一级缓存 

12、其余


1.经常使用的linux下的命令

 

Java抽象类与接口的区别

不少常见的面试题都会出诸如抽象类和接口有什么区别,什么状况下会使用抽象类和什么状况你会使用接口这样的问题。本文咱们将仔细讨论这些话题。

在讨论它们之间的不一样点以前,咱们先看看抽象类、接口各自的特性。

抽象类

抽象类是用来捕捉子类的通用特性的 。它不能被实例化,只能被用做子类的超类。抽象类是被用来建立继承层级里子类的模板。以JDK中的GenericServlet为例:

1
2
3
4
5
6
7
8
9
public abstract class GenericServlet implements Servlet, ServletConfig, Serializable {
     // abstract method
     abstract void service(ServletRequest req, ServletResponse res);
 
     void init() {
         // Its implementation
     }
     // other method related to Servlet
}

HttpServlet类继承GenericServlet时,它提供了service方法的实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class HttpServlet extends GenericServlet {
     void service(ServletRequest req, ServletResponse res) {
         // implementation
     }
 
     protected void doGet(HttpServletRequest req, HttpServletResponse resp) {
         // Implementation
     }
 
     protected void doPost(HttpServletRequest req, HttpServletResponse resp) {
         // Implementation
     }
 
     // some other methods related to HttpServlet
}

接口

接口是抽象方法的集合。若是一个类实现了某个接口,那么它就继承了这个接口的抽象方法。这就像契约模式,若是实现了这个接口,那么就必须确保使用这些方法。接口只是一种形式,接口自身不能作任何事情。以Externalizable接口为例

1
2
3
4
5
6
public interface Externalizable extends Serializable {
 
     void writeExternal(ObjectOutput out) throws IOException;
 
     void readExternal(ObjectInput in) throws IOException, ClassNotFoundException;
}

当你实现这个接口时,你就须要实现上面的两个方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public class Employee implements Externalizable {
 
     int employeeId;
     String employeeName;
 
     @Override
     public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
         employeeId = in.readInt();
         employeeName = (String) in.readObject();
 
     }
 
     @Override
     public void writeExternal(ObjectOutput out) throws IOException {
 
         out.writeInt(employeeId);
         out.writeObject(employeeName);
     }
}

抽象类和接口的对比

参数 抽象类 接口
默认的方法实现 它能够有默认的方法实现 接口彻底是抽象的。它根本不存在方法的实现
实现 子类使用extends关键字来继承抽象类。若是子类不是抽象类的话,它须要提供抽象类中全部声明的方法的实现。 子类使用关键字implements来实现接口。它须要提供接口中全部声明的方法的实现
构造器 抽象类能够有构造器 接口不能有构造器
与正常Java类的区别 除了你不能实例化抽象类以外,它和普通Java类没有任何区别 接口是彻底不一样的类型
访问修饰符 抽象方法能够有public、protected和default这些修饰符 接口方法默认修饰符是public。你不能够使用其它修饰符。
main方法 抽象方法能够有main方法而且咱们能够运行它 接口没有main方法,所以咱们不能运行它。
多继承 抽象方法能够继承一个类和实现多个接口 接口只能够继承一个或多个其它接口
速度 它比接口速度要快 接口是稍微有点慢的,由于它须要时间去寻找在类中实现的方法。
添加新方法 若是你往抽象类中添加新的方法,你能够给它提供默认的实现。所以你不须要改变你如今的代码。 若是你往接口中添加方法,那么你必须改变实现该接口的类。

何时使用抽象类和接口

  • 若是你拥有一些方法而且想让它们中的一些有默认实现,那么使用抽象类吧。
  • 若是你想实现多重继承,那么你必须使用接口。因为Java不支持多继承,子类不可以继承多个类,但能够实现多个接口。所以你就能够使用接口来解决它。
相关文章
相关标签/搜索