面试总结

基础篇

基本功

1、面向对象的特征

2、final, finally, finalize 的区别

3、int 和 Integer 有什么区别

4、重载和重写的区别

5、抽象类和接口有什么区别

6、说说反射的用途及实现

7、说说自定义注解的场景及实现

8、HTTP 请求的 GET 与 POST 方式的区别

9、session 与 cookie 区别

10、session 分布式处理

11、JDBC 流程

12、MVC 设计思想

13、equals 与 == 的区别

14、

java自动装箱拆箱深入剖析
谈谈Java反射机制
如何写一个不可变类?

15、

Switch能否用string做参数?

a.在 Java 7 之前, switch 只能支持byte,short,char,int 或者其对应的封装类以及 Enum 类型。在Java 7中,String 支持被加上了。

16、

Object有哪些公用方法?

a.方法equals测试的是两个对象是否相等

b.方法clone进行对象拷贝

c.方法getClass返回和当前对象相关的Class对象

d.方法notify,notifyall,wait都是用来对给定对象进行线程同步的

17、

Hashcode的作用,与 equal 有什么区别?

a.同样用于鉴定2个对象是否相等的,java集合中有 list 和 set 两类,其中 set不允许元素重复实现,那个这个不允许重复实现的方法,如果用 equal 去比较的话,如果存在1000个元素,你 new 一个新的元素出来,需要去调用1000次 equal 去逐个和他们比较是否是同一个对象,这样会大大降低效率。hashcode实际上是返回对象的存储地址,如果这个位置上没有元素,就把元素直接存储在上面,如果这个位置上已经存在元素,这个时候才去调用equal方法与新元素进行比较,相同的话就不存了,散列到其他地址上。

18、

Override和Overload的含义以及区别
a.Overload顾名思义是重新加载,它可以表现类的多态性,可以是函数里面可以有相同的函数名但是参数名、返回值、类型不能相同;或者说可以改变参数、类型、返回值但是函数名字依然不变。
b.就是ride(重写)的意思,在子类继承父类的时候子类中可以定义某方法与其父类有相同的名称和参数,当子类在调用这一函数时自动调用子类的方法,而父类相当于被覆盖(重写)了。
具体可前往C++中重载、重写(覆盖)的区别实例分析查看

 19、

抽象类和接口的区别

a.一个类只能继承单个类,但是可以实现多个接口

b.抽象类中可以有构造方法,接口中不能有构造方法

c.抽象类中的所有方法并不一定要是抽象的,你可以选择在抽象类中实现一些基本的方法。而接口要求所有的方法都必须是抽象的

d.抽象类中可以包含静态方法,接口中不可以

e.抽象类中可以有普通成员变量,接口中不可以

20、

解析XML的几种方式的原理与特点:DOM、SAX、PULL

a.DOM:消耗内存:先把xml文档都读到内存中,然后再用DOM API来访问树形结构,并获取数据。这个写起来很简单,但是很消耗内存。要是数据过大,手机不够牛逼,可能手机直接死机

b.SAX:解析效率高,占用内存少,基于事件驱动的:更加简单地说就是对文档进行顺序扫描,当扫描到文档(document)开始与结束、元素(element)开始与结束、文档(document)结束等地方时通知事件处理函数,由事件处理函数做相应动作,然后继续同样的扫描,直至文档结束。

c.PULL:与 SAX 类似,也是基于事件驱动,我们可以调用它的next()方法,来获取下一个解析事件(就是开始文档,结束文档,开始标签,结束标签),当处于某个元素时可以调用XmlPullParser的getAttributte()方法来获取属性的值,也可调用它的nextText()获取本节点的值。

 

21、Java面相对象的思想的理解(主要是多态): 
http://blog.csdn.net/zhaojw_420/article/details/70477636

22、final finally finalize

23、Java反射

24、cloneable接口实现原理

25、异常分类以及处理机制

26、hashcode()equals()的关系

A:根据JVM标准,equals()相等的对象,hashcode()应该永远相对,反之则不一定,详见HashMap的实现。

这个问题其实挺好的,但如果只是简单的问一下,没有任何意义,仍然考的是记忆力。

27、Java的多态表现在哪里

主要有两种表现形式:重载和重写

重载:

是发生在同一类中,具有相同的方法名,主要是看参数的个数,类型,顺序不同实现方法的重载的,返回值的类型可以不同。

重写:

是发生在两个类中(父类和子类),具有相同的方法名,主要看方法中参数,个数,类型必须相同,返回值的类型必须相同。

28、String和StringBuffer、StringBuild的区别:http://blog.csdn.net/rmn190/article/details/1492013 

29、hashcode和equals方法的关系:http://blog.csdn.net/lijiecao0226/article/details/24609559

30、自动装箱和拆箱:https://www.cnblogs.com/danne823/archive/2011/04/22/2025332.html

 31、java中的异常:http://www.importnew.com/26613.html

32、

Java中的equals和hashCode方法详解

参考:http://www.cnblogs.com/Qian123/p/5703507.html

33、

comparable与comparator的区别?

参考:http://www.cnblogs.com/szlbm/p/5504634.html

34、

Java中object常用方法

1、clone() 
2、equals() 
3、finalize() 
4、getclass() 
5、hashcode() 
6、notify() 
7、notifyAll() 
8、toString()

35、

对于Java中多态的理解

所谓多态就是指程序中定义的引用变量所指向的具体类型和通过该引用变量发出的方法调用在编程时并不确定,而是在程序运行期间才确定,即一个引用变量到底会指向哪个类的实例对象,该引用变量发出的方法调用到底是哪个类中实现的方法,必须在由程序运行期间才能决定。因为在程序运行时才确定具体的类,这样,不用修改源程序代码,就可以让引用变量绑定到各种不同的类实现上,从而导致该引用调用的具体方法随之改变,即不修改程序代码就可以改变程序运行时所绑定的具体代码,让程序可以选择多个运行状态,这就是多态性。

多态的定义:指允许不同类的对象对同一消息做出响应。即同一消息可以根据发送对象的不同而采用多种不同的行为方式。(发送消息就是函数调用)

Java实现多态有三个必要条件:继承、重写、父类引用指向子类对象。

继承:在多态中必须存在有继承关系的子类和父类。

重写:子类对父类中某些方法进行重新定义,在调用这些方法时就会调用子类的方法。

父类引用指向子类对象:在多态中需要将子类的引用赋给父类对象,只有这样该引用才能够具备技能调用父类的方法和子类的方法。

实现多态的技术称为:动态绑定(dynamic binding),是指在执行期间判断所引用对象的实际类型,根据其实际的类型调用其相应的方法。

多态的作用:消除类型之间的耦合关系。

36、

Session机制?

参考 :http://justsee.iteye.com/blog/1570652

37、

Java序列化与反序列化是什么?为什么需要序列化与反序列化?如何实现Java序列化与反序列化?

参考 : http://blog.csdn.net/wangloveall/article/details/7992448/

 38、.面向对象和面向过程的区别

面向过程
优点:性能比面向对象高,因为类调用时需要实例化,开销比较大,比较消耗资源;比如单片机、嵌入式开发、Linux/Unix等一般采用面向过程开发,性能是最重要的因素。
缺点:没有面向对象易维护、易复用、易扩展
面向对象
优点:易维护、易复用、易扩展,由于面向对象有封装、继承、多态性的特性,可以设计出低耦合的系统,使系统更加灵活、更加易于维护
缺点:性能比面向过程低

39、.Java的四个基本特性(抽象、封装、继承,多态)

抽象:就是把现实生活中的某一类东西提取出来,用程序代码表示,我们通常叫做类或者接口。抽象包括两个方面:一个是数据抽象,一个是过程抽象。数据抽象也就是对象的属性。过程抽象是对象的行为特征。
封装:把客观事物封装成抽象的类,并且类可以把自己的数据和方法只让可信的类或者对象操作,对不可信的进行封装隐藏。封装分为属性的封装和方法的封装。
继承:是对有着共同特性的多类事物,进行再抽象成一个类。这个类就是多类事物的父类。父类的意义在于抽取多类事物的共性。
多态:允许不同类的对象对同一消息做出响应。方法的重载、类的覆盖正体现了多态。

40、.重载和重写的区别

重载:发生在同一个类中,方法名必须相同,参数类型不同、个数不同、顺序不同,方法返回值和访问修饰符可以不同,发生在编译时。
重写:发生在父子类中,方法名、参数列表必须相同,返回值小于等于父类,抛出的异常小于等于父类,访问修饰符大于等于父类;如果父类方法访问修饰符为private则子类中就不是重写。

41、.构造器Constructor是否可被override

构造器不能被重写,不能用static修饰构造器,只能用public
private protected这三个权限修饰符,且不能有返回语句。

42、.访问控制符public,protected,private,以及默认的区别

private只有在本类中才能访问;
public在任何地方都能访问;
protected在同包内的类及包外的子类能访问;
默认不写在同包内能访问。
6是否可以继承String类#
String类是final类故不可以继承,一切由final修饰过的都不能继承。

43、.String和StringBuffer、StringBuilder的区别#

可变性
String类中使用字符数组保存字符串,private
final char value[],所以string对象是不可变的。StringBuilder与StringBuffer都继承自AbstractStringBuilder类,在AbstractStringBuilder中也是使用字符数组保存字符串,char[]
value,这两种对象都是可变的。
线程安全性
String中的对象是不可变的,也就可以理解为常量,线程安全。AbstractStringBuilder是StringBuilder与StringBuffer的公共父类,定义了一些字符串的基本操作,如expandCapacity、append、insert、indexOf等公共方法。StringBuffer对方法加了同步锁或者对调用的方法加了同步锁,所以是线程安全的。StringBuilder并没有对方法进行加同步锁,所以是非线程安全的。
性能
每次对String 类型进行改变的时候,都会生成一个新的String 对象,然后将指针指向新的String 对象。StringBuffer每次都会对
StringBuffer 对象本身进行操作,而不是生成新的对象并改变对象引用。相同情况下使用
StirngBuilder 相比使用
StringBuffer 仅能获得10%~15% 左右的性能提升,但却要冒多线程不安全的风险。

44、.hashCode和equals方法的关系#

equals相等,hashcode必相等;hashcode相等,equals可能不相等。

45、抽象类和接口的区别#

语法层次
抽象类和接口分别给出了不同的语法定义。
设计层次
抽象层次不同,抽象类是对类抽象,而接口是对行为的抽象。抽象类是对整个类整体进行抽象,包括属性、行为,但是接口却是对类局部(行为)进行抽象。抽象类是自底向上抽象而来的,接口是自顶向下设计出来的。
跨域不同
抽象类所体现的是一种继承关系,要想使得继承关系合理,父类和派生类之间必须存在"is-a"
关系,即父类和派生类在概念本质上应该是相同的。对于接口则不然,并不要求接口的实现者和接口定义在概念本质上是一致的,仅仅是实现了接口定义的契约而已,"like-a"的关系。

46、自动装箱与拆箱#

装箱:将基本类型用它们对应的引用类型包装起来;
拆箱:将包装类型转换为基本数据类型;
Java使用自动装箱和拆箱机制,节省了常用数值的内存开销和创建对象的开销,提高了效率,由编译器来完成,编译器会在编译期根据语法决定是否进行装箱和拆箱动作。

47、什么是泛型、为什么要使用以及泛型擦除#

泛型,即“参数化类型”。
创建集合时就指定集合元素的类型,该集合只能保存其指定类型的元素,避免使用强制类型转换。
Java编译器生成的字节码是不包涵泛型信息的,泛型类型信息将在编译处理是被擦除,这个过程即类型擦除。泛型擦除可以简单的理解为将泛型java代码转换为普通java代码,只不过编译器更直接点,将泛型java代码直接转换成普通java字节码。
类型擦除的主要过程如下:
1).将所有的泛型参数用其最左边界(最顶级的父类型)类型替换。
2).移除所有的类型参数。

48、.Error、Exception区别#

Error类和Exception类的父类都是throwable类,他们的区别是:
Error类一般是指与虚拟机相关的问题,如系统崩溃,虚拟机错误,内存空间不足,方法调用栈溢等。对于这类错误的导致的应用程序中断,仅靠程序本身无法恢复和和预防,遇到这样的错误,建议让程序终止。
Exception类表示程序可以处理的异常,可以捕获且可能恢复。遇到这类异常,应该尽可能处理异常,使程序恢复运行,而不应该随意终止异常。

49、Unchecked

Exception和Checked Exception,各列举几个#
Unchecked Exception:
a. 指的是程序的瑕疵或逻辑错误,并且在运行时无法恢复。
b. 包括Error与RuntimeException及其子类,如:OutOfMemoryError,
UndeclaredThrowableException, IllegalArgumentException,
IllegalMonitorStateException, NullPointerException, IllegalStateException,
IndexOutOfBoundsException等。
c. 语法上不需要声明抛出异常。

Checked Exception:
a. 代表程序不能直接控制的无效外界情况(如用户输入,数据库问题,网络异常,文件丢失等)
b. 除了Error和RuntimeException及其子类之外,如:ClassNotFoundException,
NamingException, ServletException, SQLException, IOException等。
c. 需要try catch处理或throws声明抛出异常。

50、.Java中如何实现代理机制(JDK、CGLIB)#

JDK动态代理:代理类和目标类实现了共同的接口,用到InvocationHandler接口。
CGLIB动态代理:代理类是目标类的子类,用到MethodInterceptor接口。

51、八种基本数据类型的大小,以及他们的封装类

八种基本数据类型:int、short、float、double、long、boolean、byte、char。

封装类分别是:Integer、Short、Float、Double、Long、Boolean、Byte、Character。

引用数据类型

引用数据类型是由类的编辑器定义的,他们是用于访问对象的。这些变量被定义为不可更改的特定类型。

例如:Employee, Puppy 等等

  • 类对象和数组变量就是这种引用数据类型。
  • 任何引用数据类型的默认值都为空。
  • 一个引用数据类型可以被用于任何声明类型和兼容类型的对象。

52、Switch能否用string做参数

jdk7之前 switch 只能支持 byte、short、char、int 这几个基本数据类型和其对应的封装类型。

switch后面的括号里面只能放int类型的值,但由于byte,short,char类型,它们会?自动?转换为int类型(精精度小的向大的转化),所以它们也支持

jdk1.7后 整形,枚举类型,字符串都可以。

原理

1
2
3
4
5
6
7
8
9
10
11
switch (expression)  // 括号里是一个表达式,结果是个整数{
  case constant1:   // case 后面的标号,也是个整数
     group of statements 1;
     break;
  case constant2:
     group of statements 2;
     break;
  ...
  default:
     default group of statements
}

jdk1.7后,整形,枚举类,字符串都可以。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class TestString {
 
    static String string = "123";
    public static void main(String[] args) {
        switch (string) {
        case "123":
            System.out.println("123");
            break;
        case "abc":
            System.out.println("abc");
            break;
        default:
            System.out.println("defauls");
            break;
        }
    }
}

为什么jdk1.7后又可以用string类型作为switch参数呢?

其实,jdk1.7并没有新的指令来处理switch string,而是通过调用switch中string.hashCode,将string转换为int从而进行判断

53、equals与==的区别

使用==比较原生类型如:boolean、int、char等等,使用equals()比较对象。

1、==是判断两个变量或实例是不是指向同一个内存空间。 equals是判断两个变量或实例所指向的内存空间的值是不是相同。

2、==是指对内存地址进行比较。 equals()是对字符串的内容进行比较。

3、==指引用是否相同。 equals()指的是值是否相同。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public static void main(String[] args) {
 
        String a = new String("ab"); // a 为一个引用
        String b = new String("ab"); // b为另一个引用,对象的内容一样
        String aa = "ab"// 放在常量池中
        String bb = "ab"// 从常量池中查找
 
        System.out.println(aa == bb); // true
        System.out.println(a == b); // false,非同一对象
        System.out.println(a.equals(b)); // true
        System.out.println(42 == 42.0);  // true
    }
 
public static void main(String[] args) {
    Object obj1 = new Object();
    Object obj2 = new Object();
    System.out.println(obj1.equals(obj2));//false
    System.out.println(obj1==obj2);//false
    obj1=obj2;
    System.out.println(obj1==obj2);//true
    System.out.println(obj2==obj1);//true
}

自动装箱,常量池

自动装箱 在jdk?1.5之前,如果你想要定义一个value为100的Integer对象,则需要如下定义:

1
2
3
4
5
6
Integer i = new Integer(100);
 
int intNum1 = 100//普通变量
Integer intNum2 = intNum1; //自动装箱
int intNum3 = intNum2; //自动拆箱
Integer intNum4 = 100//自动装箱

上面的代码中,intNum2为一个Integer类型的实例,intNum1为Java中的基础数据类型,将intNum1赋值给intNum2便是自动装箱;而将intNum2赋值给intNum3则是自动拆箱。

八种基本数据类型: boolean byte char shrot int long float double ,所生成的变量相当于常量。

基本类型包装类:Boolean Byte Character Short Integer Long Float Double。

自动拆箱和自动装箱定义:

自动装箱是将一个java定义的基本数据类型赋值给相应封装类的变量。 拆箱与装箱是相反的操作,自动拆箱则是将一个封装类的变量赋值给相应基本数据类型的变量。

54、Object有哪些公用方法

Object是所有类的父类,任何类都默认继承Object

clone 保护方法,实现对象的浅复制,只有实现了Cloneable接口才可以调用该方法,否则抛出CloneNotSupportedException异常。

equals 在Object中与==是一样的,子类一般需要重写该方法。

hashCode 该方法用于哈希查找,重写了equals方法一般都要重写hashCode方法。这个方法在一些具有哈希功能的Collection中用到。

getClass final方法,获得运行时类型

wait 使当前线程等待该对象的锁,当前线程必须是该对象的拥有者,也就是具有该对象的锁。 wait() 方法一直等待,直到获得锁或者被中断。 wait(long timeout) 设定一个超时间隔,如果在规定时间内没有获得锁就返回。

调用该方法后当前线程进入睡眠状态,直到以下事件发生

1、其他线程调用了该对象的notify方法。 2、其他线程调用了该对象的notifyAll方法。 3、其他线程调用了interrupt中断该线程。 4、时间间隔到了。 5、此时该线程就可以被调度了,如果是被中断的话就抛出一个InterruptedException异常。

notify 唤醒在该对象上等待的某个线程。

notifyAll 唤醒在该对象上等待的所有线程。

toString 转换成字符串,一般子类都有重写,否则打印句柄。

55、Java的四种引用,强弱软虚,用到的场景

从JDK1.2版本开始,把对象的引用分为四种级别,从而使程序能更加灵活的控制对象的生命周期。这四种级别由高到低依次为:强引用、软引用、弱引用和虚引用。

1、强引用

最普遍的一种引用方式,如String s = "abc",变量s就是字符串“abc”的强引用,只要强引用存在,则垃圾回收器就不会回收这个对象。

2、软引用(SoftReference)

用于描述还有用但非必须的对象,如果内存足够,不回收,如果内存不足,则回收。一般用于实现内存敏感的高速缓存,软引用可以和引用队列ReferenceQueue联合使用,如果软引用的对象被垃圾回收,JVM就会把这个软引用加入到与之关联的引用队列中。

3、弱引用(WeakReference)

弱引用和软引用大致相同,弱引用与软引用的区别在于:只具有弱引用的对象拥有更短暂的生命周期。在垃圾回收器线程扫描它所管辖的内存区域的过程中,一旦发现了只具有弱引用的对象,不管当前内存空间足够与否,都会回收它的内存。

4、虚引用(PhantomReference)

就是形同虚设,与其他几种引用都不同,虚引用并不会决定对象的生命周期。如果一个对象仅持有虚引用,那么它就和没有任何引用一样,在任何时候都可能被垃圾回收器回收。 虚引用主要用来跟踪对象被垃圾回收器回收的活动。

虚引用与软引用和弱引用的一个区别在于:

虚引用必须和引用队列 (ReferenceQueue)联合使用。当垃圾回收器准备回收一个对象时,如果发现它还有虚引,就会在回收对象的内存之前,把这个虚引用加入到与之关联的引用队列中。

56、Hashcode的作用

http://blog.csdn.net/seu_calvin/article/details/52094115

1、HashCode的特性

(1)HashCode的存在主要是用于查找的快捷性,如Hashtable,HashMap等,HashCode经常用于确定对象的存储地址

(2)如果两个对象相同,?equals方法一定返回true,并且这两个对象的HashCode一定相同

(3)两个对象的HashCode相同,并不一定表示两个对象就相同,即equals()不一定为true,只能够说明这两个对象在一个散列存储结构中。

(4)如果对象的equals方法被重写,那么对象的HashCode也尽量重写

2、HashCode作用

Java中的集合有两类,一类是List,再有一类是Set。前者集合内的元素是有序的,元素可以重复;后者元素无序,但元素不可重复

equals方法可用于保证元素不重复,但如果每增加一个元素就检查一次,若集合中现在已经有1000个元素,那么第1001个元素加入集合时,就要调用1000次equals方法。这显然会大大降低效率。?于是,Java采用了哈希表的原理

哈希算法也称为散列算法,是将数据依特定算法直接指定到一个地址上。

这样一来,当集合要添加新的元素时,先调用这个元素的HashCode方法,就一下子能定位到它应该放置的物理位置上

(1)如果这个位置上没有元素,它就可以直接存储在这个位置上,不用再进行任何比较了。

(2)如果这个位置上已经有元素了,就调用它的equals方法与新元素进行比较,相同的话就不存了。

(3)不相同的话,也就是发生了Hash key相同导致冲突的情况,那么就在这个Hash key的地方产生一个链表,将所有产生相同HashCode的对象放到这个单链表上去,串在一起(很少出现)。

这样一来实际调用equals方法的次数就大大降低了,几乎只需要一两次。

如何理解HashCode的作用:

从Object角度看,JVM每new一个Object,它都会将这个Object丢到一个Hash表中去,这样的话,下次做Object的比较或者取这个对象的时候(读取过程),它会根据对象的HashCode再从Hash表中取这个对象。这样做的目的是提高取对象的效率。若HashCode相同再去调用equal。

3、HashCode实践(如何用来查找)

HashCode是用于查找使用的,而equals是用于比较两个对象是否相等的

(1)例如内存中有这样的位置

0  1  2  3  4  5  6  7

而我有个类,这个类有个字段叫ID,我要把这个类存放在以上8个位置之一,如果不用HashCode而任意存放,那么当查找时就需要到这八个位置里挨个去找,或者用二分法一类的算法。

但以上问题如果用HashCode就会使效率提高很多 定义我们的HashCode为ID%8,比如我们的ID为9,9除8的余数为1,那么我们就把该类存在1这个位置,如果ID是13,求得的余数是5,那么我们就把该类放在5这个位置。依此类推。

(2)但是如果两个类有相同的HashCode,例如9除以8和17除以8的余数都是1,也就是说,我们先通过?HashCode来判断两个类是否存放某个桶里,但这个桶里可能有很多类,那么我们就需要再通过equals在这个桶里找到我们要的类

请看下面这个例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
public class HashTest {
    private int i;
 
    public int getI() {
        return i;
    }
 
    public void setI(int i) {
        this.i = i;
    }
 
    public int hashCode() {
        return i % 10;
    }
 
    public final static void main(String[] args) {
        HashTest a = new HashTest();
        HashTest b = new HashTest();
        a.setI(1);
        b.setI(1);
        Set<HashTest> set = new HashSet<HashTest>();
        set.add(a);
        set.add(b);
        System.out.println(a.hashCode() == b.hashCode());
        System.out.println(a.equals(b));
        System.out.println(set);
    }
}

输出结果为:

1
2
3
true
False
[HashTest@1, HashTest@1]

以上这个示例,我们只是重写了HashCode方法,从上面的结果可以看出,虽然两个对象的HashCode相等,但是实际上两个对象并不是相等因为我们没有重写equals方法,那么就会调用Object默认的equals方法,显示这是两个不同的对象。

这里我们将生成的对象放到了HashSet中,而HashSet中只能够存放唯一的对象,也就是相同的(适用于equals方法)的对象只会存放一个,但是这里实际上是两个对象ab都被放到了HashSet中,这样HashSet就失去了他本身的意义了。

下面我们继续重写equals方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
public class HashTest {
    private int i;
 
    public int getI() {
        return i;
    }
 
    public void setI(int i) {
        this.i = i;
    }
 
    public boolean equals(Object object) {
        if (object == null) {
            return false;
        }
        if (object == this) {
            return true;
        }
        if (!(object instanceof HashTest)) {
            return false;
        }
        HashTest other = (HashTest) object;
        if (other.getI() == this.getI()) {
            return true;
        }
        return false;
    }
 
    public int hashCode() {
        return i % 10;
    }
 
    public final static void main(String[] args) {
        HashTest a = new HashTest();
        HashTest b = new HashTest();
        a.setI(1);
        b.setI(1);
        Set<HashTest> set = new HashSet<HashTest>();
        set.add(a);
        set.add(b);
        System.out.println(a.hashCode() == b.hashCode());
        System.out.println(a.equals(b));
        System.out.println(set);
    }
}

输出结果如下所示。

从结果我们可以看出,现在两个对象就完全相等了,HashSet中也只存放了一份对象。

注意:

hashCode()只是简单示例写的,真正的生产换将不是这样的

1
2
3
true
true
[HashTest@1]

HashMap的hashcode的作用

hashCode的存在主要是用于查找的快捷性,如Hashtable,HashMap等,hashCode是用来在散列存储结构中确定对象的存储地址的。

如果两个对象相同,就是适用于equals(java.lang.Object) 方法,那么这两个对象的hashCode一定要相同。

如果对象的equals方法被重写,那么对象的hashCode也尽量重写,并且产生hashCode使用的对象,一定要和equals方法中使用的一致,否则就会违反上面提到的第2点。

两个对象的hashCode相同,并不一定表示两个对象就相同,也就是不一定适用于equals(java.lang.Object) 方法,只能够说明这两个对象在散列存储结构中,如Hashtable,他们“存放在同一个篮子里”。

什么时候需要重写?

一般的地方不需要重载hashCode,只有当类需要放在HashTable、HashMap、HashSet等等hash结构的集合时才会重载hashCode,那么为什么要重载hashCode呢?

要比较两个类的内容属性值,是否相同时候,根据hashCode 重写规则,重写类的 指定字段的hashCode(),equals()方法。

例如

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
public class EmpWorkCondition{
 
    /**
     * 员工ID
     */
    private Integer empId;
 
    /**
     * 员工服务总单数
     */
    private Integer orderSum;
 
    @Override
    public boolean equals(Object o) {
        if (this == o) {
            return true;
        }
        if (o == null || getClass() != o.getClass()) {
            return false;
        }
        EmpWorkCondition that = (EmpWorkCondition) o;
        return Objects.equals(empId, that.empId);
    }
 
    @Override
    public int hashCode() {
        return Objects.hash(empId);
    }
 
    // 省略 getter setter
}

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public static void main(String[] args) {
 
    List<EmpWorkCondition> list1 = new ArrayList<EmpWorkCondition>();
 
    EmpWorkCondition emp1 = new EmpWorkCondition();
    emp1.setEmpId(100);
    emp1.setOrderSum(90000);
    list1.add(emp1);
 
    List<EmpWorkCondition> list2 = new ArrayList<EmpWorkCondition>();
 
    EmpWorkCondition emp2 = new EmpWorkCondition();
    emp2.setEmpId(100);
    list2.add(emp2);
 
    System.out.println(list1.contains(emp2));
 
}

输出结果:true

上面的方法,做的事情就是,比较两个集合中的,实体类对象属性值,是否一致

OrderSum 不在比较范围内,因为没有重写它的,equals()和hashCode()方法

为什么要重载equal方法?

因为Object的equal方法默认是两个对象的引用的比较,意思就是指向同一内存,地址则相等,否则不相等;如果你现在需要利用对象里面的值来判断是否相等,则重载equal方法。

为什么重载hashCode方法?

一般的地方不需要重载hashCode,只有当类需要放在HashTable、HashMap、HashSet等等hash结构的集合时才会重载hashCode,那么为什么要重载hashCode呢?

如果你重写了equals,比如说是基于对象的内容实现的,而保留hashCode的实现不变,那么很可能某两个对象明明是“相等”,而hashCode却不一样。

这样,当你用其中的一个作为键保存到hashMap、hasoTable或hashSet中,再以“相等的”找另一个作为键值去查找他们的时候,则根本找不到。

为什么equals()相等,hashCode就一定要相等,而hashCode相等,却不要求equals相等?

1、因为是按照hashCode来访问小内存块,所以hashCode必须相等。 2、HashMap获取一个对象是比较key的hashCode相等和equal为true。

之所以hashCode相等,却可以equal不等,就比如ObjectA和ObjectB他们都有属性name,那么hashCode都以name计算,所以hashCode一样,但是两个对象属于不同类型,所以equal为false。

为什么需要hashCode?

1、通过hashCode可以很快的查到小内存块。 2、通过hashCode比较比equal方法快,当get时先比较hashCode,如果hashCode不同,直接返回false。

58、String、StringBuffer与StringBuilder的区别

String:适用于少量的字符串操作的情况。 StringBuilder:适用于单线程下在字符缓冲区进行大量操作的情况。 StringBuffer:适用多线程下在字符缓冲区进行大量操作的情况。 StringBuilder:是线程不安全的,而StringBuffer是线程安全的。

这三个类之间的区别主要是在两个方面,即运行速度和线程安全这两方面。 首先说运行速度,或者说是执行速度,在这方面运行速度快慢为:StringBuilder > StringBuffer > String

String最慢的原因

String为字符串常量,而StringBuilder和StringBuffer均为字符串变量,即String对象一旦创建之后该对象是不可更改的,但后两者的对象是变量,是可以更改的。

再来说线程安全

在线程安全上,StringBuilder是线程不安全的,而StringBuffer是线程安全的

如果一个StringBuffer对象在字符串缓冲区被多个线程使用时,StringBuffer中很多方法可以带有synchronized关键字,所以可以保证线程是安全的,但StringBuilder的方法则没有该关键字,所以不能保证线程安全,有可能会出现一些错误的操作。所以如果要进行的操作是多线程的,那么就要使用StringBuffer,但是在单线程的情况下,还是建议使用速度比较快的StringBuilder。

59、Java对象的生命周期

答:创建阶段 、 应用阶段 、不可见阶段 、不可达阶段 、收集阶段 、终结阶段、 对象空间重新分配阶段等等,具体参照:Java 对象的生命周期

60、Java Object类中有哪些方法?

答:Object有哪些方法

61、weblogic 负载均衡的原理和集群的配置

解答:a、WEBLOGIC负载均衡原理    b、负载均衡和集群的配置(参考)

62、Nginx+Tomcat+Redis实现负载均衡、资源分离、session共享 

解答:配置参考

63、nginx配置文件详解——nginx.conf

解答:Nginx配置文件详细说明

64、一个类对象属性发生改变时,如何让调用者知道?

答:Java event时间监听  ,即在set方法改变属性时,触发 ,这种模式也可以理解为观察者模式,具体查看:观察者模式简单案例和说明

65、重写equals为何要重写hashCode?

答:判断两个对象是否相等,比较的就是其hashCode, 如果你重载了equals,比如说是基于对象的内容实现的,而保留hashCode的实现不变,那么很可能某两个对象明明是“相等”,而hashCode却不一样。  hashcode不一样,就无法认定两个对象相等了

66、面向对象的特性有哪些?

答:封装、继承和多态。

67、Java 中覆盖和重载是什么意思?

解析:覆盖和重载是比较重要的基础知识点,并且容易混淆,所以面试中常见。
答:覆盖(Override)是指子类对父类方法的一种重写,只能比父类抛出更少的异常,访问权限不能比父类的小。

被覆盖的方法不能是 private 的,否则只是在子类中重新定义了一个方法;重载(Overload)表示同一个类中可以有多个名称相同的方法,但这些方法的参数列表各不相同。

面试官: 那么构成重载的条件有哪些?

答:参数类型不同、参数个数不同、参数顺序不同。

面试官: 函数的返回值不同可以构成重载吗?为什么?

答:不可以,因为 Java 中调用函数并不需要强制赋值。举例如下:

如下两个方法:

1
2
void f(){}
int f(){ return 1;}

只要编译器可以根据语境明确判断出语义,比如在 int x = f();中,那么的确可以据此区分重载方法。不过, 有时你并不关心方法的返回值,你想要的是方法调用的其他效果 (这常被称为 “为了副作用而调用”),这时你可能会调用方法而忽略其返回值,所以如果像下面的调用:

1
fun();

此时 Java 如何才能判断调用的是哪一个 f() 呢?别人如何理解这种代码呢?所以,根据方法返回值来区分重载方法是行不通的。

68、抽象类和接口的区别有哪些?

答:

  1. 抽象类中可以没有抽象方法;接口中的方法必须是抽象方法;
  2. 抽象类中可以有普通的成员变量;接口中的变量必须是 static final 类型的,必须被初始化 , 接口中只有常量,没有变量。
  3. 抽象类只能单继承,接口可以继承多个父接口;
  4. Java8 中接口中会有 default 方法,即方法可以被实现。

面试官:抽象类和接口如何选择?

答:

  1. 如果要创建不带任何方法定义和成员变量的基类,那么就应该选择接口而不是抽象类。
  2. 如果知道某个类应该是基类,那么第一个选择的应该是让它成为一个接口,只有在必须要有方法定义和成员变量的时候,才应该选择抽象类。因为抽象类中允许存在一个或多个被具体实现的方法,只要方法没有被全部实现该类就仍是抽象类。

69、Java 中的值传递和引用传递

解析:这类题目,面试官会手写一个例子,让你说出函数执行结果,详细举例请查阅我的博客:Java 值传递和引用传递基础分析。

答:值传递是指对象被值传递,意味着传递了对象的一个副本,即使副本被改变,也不会影响源对象。引用传递是指对象被引用传递,意味着传递的并不是实际的对象,而是对象的引用。

因此,外部对引用对象的改变会反映到所有的对象上。

70、JDK 中常用的包有哪些?

答:java.lang、java.util、、java.sql。

71、JDK,JRE 和 JVM 的联系和区别:

答:JDK 是 java 开发工具包,是 java 开发环境的核心组件,并提供编译、调试和运行一个 java 程序所需要的所有工具,可执行文件和二进制文件,是一个平台特定的软件。

JRE 是 java 运行时环境,是 JVM 的实施实现,提供了运行 java 程序的平台。JRE 包含了 JVM,但是不包含 java 编译器 / 调试器之类的开发工具。

JVM 是 java 虚拟机,当我们运行一个程序时,JVM 负责将字节码转换为特定机器代码,JVM 提供了内存管理 / 垃圾回收和安全机制等。

这种独立于硬件和操作系统,正是 java 程序可以一次编写多处执行的原因。

区别:

  1. JDK 用于开发,JRE 用于运行 java 程序;
  2. JDK 和 JRE 中都包含 JVM;
  3. JVM 是 java 编程语言的核心并且具有平台独立性。

Others:限于篇幅,面试中 Java 基础知识点还有:反射、泛型、注解等。

小结:本节主要阐述了 Java 基础知识点,这些问题主要是一面面试官在考察,难度不大,适当复习下,应该没什么问题。

 

 

 

 

集合

1、List 和 Set 区别

2、List 和 Map 区别

3、Arraylist 与 LinkedList 区别

4、ArrayList 与 Vector 区别

5、HashMap 和 Hashtable 的区别

6、HashSet 和 HashMap 区别

7、HashMap 和 ConcurrentHashMap 的区别

8、HashMap 的工作原理及代码实现

9、ConcurrentHashMap 的工作原理及代码实现

10、

HashMap与HashTable的区别。
1、HashMap是非线程安全的,HashTable是线程安全的。
2、HashMap的键和值都允许有null值存在,而HashTable则不行。
3、因为线程安全的问题,HashMap效率比HashTable的要高。

HashMap的实现机制:

  1. 维护一个每个元素是一个链表的数组,而且链表中的每个节点是一个Entry[]键值对的数据结构。
  2. 实现了数组+链表的特性,查找快,插入删除也快。
  3. 对于每个key,他对应的数组索引下标是 int i = hash(key.hashcode)&(len-1);
  4. 每个新加入的节点放在链表首,然后该新加入的节点指向原链表首

HashMap和TreeMap区别
友情链接: Java中HashMap和TreeMap的区别深入理解

HashMap冲突
友情链接: HashMap冲突的解决方法以及原理分析
友情链接: HashMap的工作原理
友情链接: HashMap和Hashtable的区别
友情链接: 2种办法让HashMap线程安全

11、

HashMap,ConcurrentHashMap与LinkedHashMap的区别

  1. ConcurrentHashMap是使用了锁分段技术技术来保证线程安全的,锁分段技术:首先将数据分成一段一段的存储,然后给每一段数据配一把锁,当一个线程占用锁访问其中一个段数据的时候,其他段的数据也能被其他线程访问
  2. ConcurrentHashMap 是在每个段(segment)中线程安全的
  3. LinkedHashMap维护一个双链表,可以将里面的数据按写入的顺序读出

ConcurrentHashMap应用场景
1:ConcurrentHashMap的应用场景是高并发,但是并不能保证线程安全,而同步的HashMap和HashMap的是锁住整个容器,而加锁之后ConcurrentHashMap不需要锁住整个容器,只需要锁住对应的Segment就好了,所以可以保证高并发同步访问,提升了效率。
2:可以多线程写。
ConcurrentHashMap把HashMap分成若干个Segmenet
1.get时,不加锁,先定位到segment然后在找到头结点进行读取操作。而value是volatile变量,所以可以保证在竞争条件时保证读取最新的值,如果读到的value是null,则可能正在修改,那么就调用ReadValueUnderLock函数,加锁保证读到的数据是正确的。
2.Put时会加锁,一律添加到hash链的头部。
3.Remove时也会加锁,由于next是final类型不可改变,所以必须把删除的节点之前的节点都复制一遍。
4.ConcurrentHashMap允许多个修改操作并发进行,其关键在于使用了锁分离技术。它使用了多个锁来控制对Hash表的不同Segment进行的修改。

ConcurrentHashMap的应用场景是高并发,但是并不能保证线程安全,而同步的HashMap和HashTable的是锁住整个容器,而加锁之后ConcurrentHashMap不需要锁住整个容器,只需要锁住对应的segment就好了,所以可以保证高并发同步访问,提升了效率。

ConcurrentHashMap能够保证每一次调用都是原子操作,但是并不保证多次调用之间也是原子操作。
友情链接:Java集合—ConcurrentHashMap原理分析

 12、

Vector和ArrayList的区别
友情链接:Java中Vector和ArrayList的区别

13、

集合类:List和Set比较,各自的子类比较(ArrayList,Vector,LinkedList;HashSet,TreeSet)

14、

HashMap的底层实现,之后会问ConcurrentHashMap的底层实现;

15、

如何实现HashMap顺序存储:可以参考LinkedHashMap的底层实现;

16、

HashTable和ConcurrentHashMap的区别;

17、

集合:ArrayList,LinkedList,HashMap,LinkedHashMap,ConcurrentHashMap,HashTable,HashSet的底层源码实现原理

18、异常 

http://blog.csdn.net/zhaojw_420/article/details/70477751

19、String,StringBuffer,StringBuilder区别 
http://blog.csdn.net/zhaojw_420/article/details/70477718

20、值传递与引用传递: 
http://blog.csdn.net/zhaojw_420/article/details/70477680

21、Java中的equals和hashCode方法详解 
http://blog.csdn.net/zhaojw_420/article/details/70477705

22、List 和 Set 的区别

23、HashSet 是如何保证不重复的

24、HashMap 是线程安全的吗,为什么不是线程安全的(最好画图说明多线程环境下不安全)?

25、HashMap 的扩容过程

26、HashMap 1.7 与 1.8 的 区别,说明 1.8 做了哪些优化,如何优化的?

27、强引用 、软引用、 弱引用、虚引用

28、Arrays.sort 实现原理和 Collection 实现原理

29、LinkedHashMap的应用

30、LinkedList的实现原理

A:它是一个双向列表,实现了ListDequeCloneable等接口

老实说,Deque(双向队列)这个东西见过几次,但没用过,所以现在也说不太清楚它的特征和实际使用场景,所以也不想胡侃。

31. ConcurrentHashMap的实现原理

A:它是一个对写操作加了锁的HashMap,不同的是它做了二次分割,元素被存储在不同的桶里,以见效锁的数据范围,提升性能。

在JDK8中对这种实现又进行了修改,JDK8中的ConcurrentHashmap基于CAS和TreeBin实现的,不需要对segment或者全局加锁,只需要对单行枷锁(hashCode相同),后边的链表是链表加红黑树。对于单个值的修改使用CAS。

面试官很可能想听到的是这样,但这里重要的是分治的概念。其实完全可以让候选人尝试自己去设计一个ConcurrentHashMap,然后引导他去拆分HashMap,这样才是正道啊。

32. TransferQueue的算法是什么样的,它和BlockingQueue有哪些不同

A:源代码里有。

33. Arraylist与LinkedList的比较

1、ArrayList是实现了基于动态数组的数据结构,因为地址连续,一旦数据存储好了,查询操作效率会比较高(在内存里是连着放的)。

2、因为地址连续, ArrayList要移动数据,所以插入和删除操作效率比较低。   

3、LinkedList基于链表的数据结构,地址是任意的,所以在开辟内存空间的时候不需要等一个连续的地址,对于新增和删除操作add和remove,LinedList比较占优势。

4、因为LinkedList要移动指针,所以查询操作性能比较低。

适用场景分析:

当需要对数据进行对此访问的情况下选用ArrayList,当需要对数据进行多次增加删除修改时采用LinkedList。

 

34. ArrayList与Vector的比较

1、Vector的方法都是同步的,是线程安全的,而ArrayList的方法不是,由于线程的同步必然要影响性能。因此,ArrayList的性能比Vector好。 
2、当Vector或ArrayList中的元素超过它的初始大小时,Vector会将它的容量翻倍,而ArrayList只增加50%的大小,这样。ArrayList就有利于节约内存空间。

3、大多数情况不使用Vector,因为性能不好,但是它支持线程的同步,即某一时刻只有一个线程能够写Vector,避免多线程同时写而引起的不一致性。

4、Vector可以设置增长因子,而ArrayList不可以。

适用场景分析:

1、Vector是线程同步的,所以它也是线程安全的,而ArrayList是线程异步的,是不安全的。如果不考虑到线程的安全因素,一般用ArrayList效率比较高。

2、如果集合中的元素的数目大于目前集合数组的长度时,在集合中使用数据量比较大的数据,用Vector有一定的优势。

 

35.HashSet与TreeSet的比较

1.TreeSet 是二叉树实现的,Treeset中的数据是自动排好序的,不允许放入null值 。

2.HashSet 是哈希表实现的,HashSet中的数据是无序的,可以放入null,但只能放入一个null,两者中的值都不能重复,就如数据库中唯一约束 。

3.HashSet要求放入的对象必须实现HashCode()方法,放入的对象,是以hashcode码作为标识的,而具有相同内容的String对象,hashcode是一样,所以放入的内容不能重复。但是同一个类的对象可以放入不同的实例。

适用场景分析:

HashSet是基于Hash算法实现的,其性能通常都优于TreeSet。我们通常都应该使用HashSet,在我们需要排序的功能时,我们才使用TreeSet。

 

36. HashMap和ConcurrentHashMap的区别

1、HashMap不是线程安全的,而ConcurrentHashMap是线程安全的。

2、ConcurrentHashMap采用锁分段技术,将整个Hash桶进行了分段segment,也就是将这个大的数组分成了几个小的片段segment,而且每个小的片段segment上面都有锁存在,那么在插入元素的时候就需要先找到应该插入到哪一个片段segment,然后再在这个片段上面进行插入,而且这里还需要获取segment锁。

3、ConcurrentHashMap让锁的粒度更精细一些,并发性能更好。

至于两者的底层实现,你如果想通过一篇文章就理解了,那就too young了,好好找些博文+看源码去吧。

 

37. HashTable和ConcurrentHashMap的区别

它们都可以用于多线程的环境,但是当Hashtable的大小增加到一定的时候,性能会急剧下降,因为迭代时需要被锁定很长的时间。因为ConcurrentHashMap引入了分割(segmentation),不论它变得多么大,仅仅需要锁定map的某个部分,而其它的线程不需要等到迭代完成才能访问map。简而言之,在迭代的过程中,ConcurrentHashMap仅仅锁定map的某个部分,而Hashtable则会锁定整个map。

 

36、java中的集合类:https://www.cnblogs.com/leeplogs/p/5891861.html

37、HashMap与HashTable、ConcurrentHashMap区别:https://www.cnblogs.com/wang-meng/p/5808006.html

38、

List接口、Set接口和Map接口的区别

参考:http://blog.csdn.net/zcg_java/article/details/43232251

39、

Arrays和Collections 对于sort的不同实现原理?

1、Arrays.sort() 
该算法是一个经过调优的快速排序,此算法在很多数据集上提供N*log(N)的性能,这导致其他快速排序会降低二次型性能。

2、Collections.sort() 
该算法是一个经过修改的合并排序算法(其中,如果低子列表中的最高元素效益高子列表中的最低元素,则忽略合并)。此算法可提供保证的N*log(N)的性能,此实现将指定列表转储到一个数组中,然后再对数组进行排序,在重置数组中相应位置处每个元素的列表上进行迭代。

40、HashMap的源码,实现原理,JDK8中对HashMap做了怎样的优化。

41、HaspMap扩容是怎样扩容的,为什么都是2的N次幂的大小。

42、HashMap,HashTable,ConcurrentHashMap的区别。

43、极高并发下HashTable和ConcurrentHashMap哪个性能更好,为什么,如何实现的。

44、HashMap在高并发下如果没有处理线程安全会有怎样的安全隐患,具体表现是什么。

45、.Java中的集合类及关系图#
List和Set继承自Collection接口。
Set无序不允许元素重复。HashSet和TreeSet是两个主要的实现类。
List有序且允许元素重复。ArrayList、LinkedList和Vector是三个主要的实现类。
Map也属于集合系统,但和Collection接口没关系。Map是key对value的映射集合,其中key列就是一个集合。key不能重复,但是value可以重复。HashMap、TreeMap和Hashtable是三个主要的实现类。
SortedSet和SortedMap接口对元素按指定规则排序,SortedMap是对key列进行排序。

46、.HashMap实现原理#
具体原理参考文章:
http://zhangshixi.iteye.com/blog/672697
http://www.admin10000.com/document/3322.html

47、.HashTable实现原理#
具体原理参考文章:
http://www.cnblogs.com/skywang12345/p/3310887.html
http://blog.csdn.net/chdjj/article/details/38581035

48、.HashMap和HashTable区别#
1).HashTable的方法前面都有synchronized来同步,是线程安全的;HashMap未经同步,是非线程安全的。
2).HashTable不允许null值(key和value都不可以) ;HashMap允许null值(key和value都可以)。
3).HashTable有一个contains(Object
value)功能和containsValue(Object
value)功能一样。
4).HashTable使用Enumeration进行遍历;HashMap使用Iterator进行遍历。
5).HashTable中hash数组默认大小是11,增加的方式是old*2+1;HashMap中hash数组的默认大小是16,而且一定是2的指数。
6).哈希值的使用不同,HashTable直接使用对象的hashCode; HashMap重新计算hash值,而且用与代替求模。

49、.ArrayList和vector区别#
ArrayList和Vector都实现了List接口,都是通过数组实现的。
Vector是线程安全的,而ArrayList是非线程安全的。
List第一次创建的时候,会有一个初始大小,随着不断向List中增加元素,当List 认为容量不够的时候就会进行扩容。Vector缺省情况下自动增长原来一倍的数组长度,ArrayList增长原来的50%。

50、.ArrayList和LinkedList区别及使用场景#
区别
ArrayList底层是用数组实现的,可以认为ArrayList是一个可改变大小的数组。随着越来越多的元素被添加到ArrayList中,其规模是动态增加的。
LinkedList底层是通过双向链表实现的, LinkedList和ArrayList相比,增删的速度较快。但是查询和修改值的速度较慢。同时,LinkedList还实现了Queue接口,所以他还提供了offer(),
peek(), poll()等方法。
使用场景
LinkedList更适合从中间插入或者删除(链表的特性)。
ArrayList更适合检索和在末尾插入或删除(数组的特性)。

51、.Collection和Collections的区别#
java.util.Collection 是一个集合接口。它提供了对集合对象进行基本操作的通用接口方法。Collection接口在Java 类库中有很多具体的实现。Collection接口的意义是为各种具体的集合提供了最大化的统一操作方式。
java.util.Collections 是一个包装类。它包含有各种有关集合操作的静态多态方法。此类不能实例化,就像一个工具类,服务于Java的Collection框架。

52、.Concurrenthashmap实现原理#
具体原理参考文章:
http://www.cnblogs.com/ITtangtang/p/3948786.html
http://ifeve.com/concurrenthashmap/

53、ArrayList、LinkedList、Vector的区别
List的三个子类的特点

ArrayList:

底层数据结构是数组,查询快,增删慢。
线程不安全,效率高。
Vector:

底层数据结构是数组,查询快,增删慢。
线程安全,效率低。
Vector相对ArrayList查询慢(线程安全的)。
Vector相对LinkedList增删慢(数组结构)。
LinkedList

底层数据结构是链表,查询慢,增删快。
线程不安全,效率高。
Vector和ArrayList的区别

Vector是线程安全的,效率低。
ArrayList是线程不安全的,效率高。
共同点:底层数据结构都是数组实现的,查询快,增删慢。
ArrayList和LinkedList的区别

ArrayList底层是数组结果,查询和修改快。
LinkedList底层是链表结构的,增和删比较快,查询和修改比较慢。
共同点:都是线程不安全的

List有三个子类使用

查询多用ArrayList。
增删多用LinkedList。
如果都多ArrayList。

54、Map、Set、List、Queue、Stack的特点与用法
Map

Map是键值对,键Key是唯一不能重复的,一个键对应一个值,值可以重复。
TreeMap可以保证顺序。
HashMap不保证顺序,即为无序的。
Map中可以将Key和Value单独抽取出来,其中KeySet()方法可以将所有的keys抽取正一个Set。而Values()方法可以将map中所有的values抽取成一个集合。
Set

不包含重复元素的集合,set中最多包含一个null元素。
只能用Lterator实现单项遍历,Set中没有同步方法。
List

有序的可重复集合。
可以在任意位置增加删除元素。
用Iterator实现单向遍历,也可用ListIterator实现双向遍历。
Queue

Queue遵从先进先出原则。
使用时尽量避免add()和remove()方法,而是使用offer()来添加元素,使用poll()来移除元素,它的优点是可以通过返回值来判断是否成功。
LinkedList实现了Queue接口。
Queue通常不允许插入null元素。
Stack

Stack遵从后进先出原则。
Stack继承自Vector。
它通过五个操作对类Vector进行扩展,允许将向量视为堆栈,它提供了通常的push和pop操作,以及取堆栈顶点的peek()方法、测试堆栈是否为空的empty方法等。
用法

如果涉及堆栈,队列等操作,建议使用List。
对于快速插入和删除元素的,建议使用LinkedList。
如果需要快速随机访问元素的,建议使用ArrayList。
更为精炼的总结

Collection 是对象集合, Collection 有两个子接口 List 和 Set

List 可以通过下标 (1,2..) 来取得值,值可以重复。 Set 只能通过游标来取值,并且值是不能重复的。

ArrayList , Vector , LinkedList 是 List 的实现类

ArrayList 是线程不安全的, Vector 是线程安全的,这两个类底层都是由数组实现的。
LinkedList 是线程不安全的,底层是由链表实现的。
Map 是键值对集合

HashTable 和 HashMap 是 Map 的实现类。
HashTable 是线程安全的,不能存储 null 值。
HashMap 不是线程安全的,可以存储 null 值。
Stack类:继承自Vector,实现一个后进先出的栈。提供了几个基本方法,push、pop、peak、empty、search等。

Queue接口:提供了几个基本方法,offer、poll、peek等。已知实现类有LinkedList、PriorityQueue等。

55、HashMap和HashTable的区别
https://segmentfault.com/a/1190000008101567

Hashtable是基于陈旧的Dictionary类的,HashMap是Java 1.2引进的Map接口的一个实现,它们都是集合中将数据无序存放的。

1、hashMap去掉了HashTable?的contains方法,但是加上了containsValue()和containsKey()方法

HashTable Synchronize同步的,线程安全,HashMap不允许空键值为空?,效率低。 HashMap 非Synchronize线程同步的,线程不安全,HashMap允许空键值为空?,效率高。 Hashtable是基于陈旧的Dictionary类的,HashMap是Java 1.2引进的Map接口的一个实现,它们都是集合中将数据无序存放的。

Hashtable的方法是同步的,HashMap未经同步,所以在多线程场合要手动同步HashMap这个区别就像Vector和ArrayList一样。

查看Hashtable的源代码就可以发现,除构造函数外,Hashtable的所有 public 方法声明中都有 synchronized 关键字,而HashMap的源代码中则连 synchronized 的影子都没有,当然,注释除外。

2、Hashtable不允许 null 值(key 和 value 都不可以),HashMap允许 null 值(key和value都可以)。

3、两者的遍历方式大同小异,Hashtable仅仅比HashMap多一个elements方法。

1
2
3
4
5
6
7
Hashtable table = new Hashtable();
table.put("key", "value");
Enumeration em = table.elements();
while (em.hasMoreElements()) {
String obj = (String) em.nextElement();
System.out.println(obj);
}
4、HashTable使用Enumeration,HashMap使用Iterator

从内部机制实现上的区别如下:

哈希值的使用不同,Hashtable直接使用对象的hashCode
1
2
int hash = key.hashCode();
int index = (hash & 0x7FFFFFFF) % tab.length;
而HashMap重新计算hash值,而且用与代替求模:

1
2
3
4
5
6
7
8
9
10
11
12
int hash = hash(k);
int i = 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;
}

1
2
static int indexFor(int h, int length) {
  return h & (length-1);
Hashtable中hash数组默认大小是11,增加的方式是 old*2+1。HashMap中hash数组的默认大小是16,而且一定是2的指数。
JDK7与JDK8中HashMap的实现
JDK7中的HashMap

HashMap底层维护一个数组,数组中的每一项都是一个Entry。

1
transient Entry<K,V>[] table;
我们向 HashMap 中所放置的对象实际上是存储在该数组当中。 而Map中的key,value则以Entry的形式存放在数组中。

1
2
3
4
5
static class Entry<K,V> implements Map.Entry<K,V> {
final K key;
V value;
Entry<K,V> next;
int hash;
总结一下map.put后的过程:

当向 HashMap 中 put 一对键值时,它会根据 key的 hashCode 值计算出一个位置, 该位置就是此对象准备往数组中存放的位置。

如果该位置没有对象存在,就将此对象直接放进数组当中;如果该位置已经有对象存在了,则顺着此存在的对象的链开始寻找(为了判断是否是否值相同,map不允许<key,value>键值对重复), 如果此链上有对象的话,再去使用 equals方法进行比较,如果对此链上的每个对象的 equals 方法比较都为 false,则将该对象放到数组当中,然后将数组中该位置以前存在的那个对象链接到此对象的后面。

JDK8中的HashMap

JDK8中采用的是位桶+链表/红黑树(有关红黑树请查看红黑树)的方式,也是非线程安全的。当某个位桶的链表的长度达到某个阀值的时候,这个链表就将转换成红黑树。

JDK8中,当同一个hash值的节点数不小于8时,将不再以单链表的形式存储了,会被调整成一颗红黑树(上图中null节点没画)。这就是JDK7与JDK8中HashMap实现的最大区别。

接下来,我们来看下JDK8中HashMap的源码实现。

JDK中Entry的名字变成了Node,原因是和红黑树的实现TreeNode相关联。

transient Node<K,V>[] table;
当冲突节点数不小于8-1时,转换成红黑树。

static final int TREEIFY_THRESHOLD = 8;
HashMap和ConcurrentHashMap的区别,HashMap的底层源码
为了线程安全从ConcurrentHashMap代码中可以看出,它引入了一个“分段锁”的概念,具体可以理解为把一个大的Map拆分成N个小的HashTable,根据key.hashCode()来决定把key放到哪个HashTable中。

Hashmap本质是数组加链表。根据key取得hash值,然后计算出数组下标,如果多个key对应到同一个下标,就用链表串起来,新插入的在前面。

ConcurrentHashMap:在hashMap的基础上,ConcurrentHashMap将数据分为多个segment,默认16个(concurrency level),然后每次操作对一个segment加锁,避免多线程锁的几率,提高并发效率。

总结

JDK6,7中的ConcurrentHashmap主要使用Segment来实现减小锁粒度,把HashMap分割成若干个Segment,在put的时候需要锁住Segment,get时候不加锁,使用volatile来保证可见性,当要统计全局时(比如size),首先会尝试多次计算modcount来确定,这几次尝试中,是否有其他线程进行了修改操作,如果没有,则直接返回size。如果有,则需要依次锁住所有的Segment来计算。

jdk7中ConcurrentHashmap中,当长度过长碰撞会很频繁,链表的增改删查操作都会消耗很长的时间,影响性能。

jdk8 中完全重写了concurrentHashmap,代码量从原来的1000多行变成了 6000多 行,实现上也和原来的分段式存储有很大的区别。

JDK8中采用的是位桶+链表/红黑树(有关红黑树请查看红黑树)的方式,也是非线程安全的。当某个位桶的链表的长度达到某个阀值的时候,这个链表就将转换成红黑树。

JDK8中,当同一个hash值的节点数不小于8时,将不再以单链表的形式存储了,会被调整成一颗红黑树(上图中null节点没画)。这就是JDK7与JDK8中HashMap实现的最大区别。

主要设计上的变化有以下几点

1.jdk8不采用segment而采用node,锁住node来实现减小锁粒度。 2.设计了MOVED状态 当resize的中过程中 线程2还在put数据,线程2会帮助resize。 3.使用3个CAS操作来确保node的一些操作的原子性,这种方式代替了锁。 4.sizeCtl的不同值来代表不同含义,起到了控制的作用。

至于为什么JDK8中使用synchronized而不是ReentrantLock,我猜是因为JDK8中对synchronized有了足够的优化吧。

ConcurrentHashMap能完全替代HashTable吗
hashTable虽然性能上不如ConcurrentHashMap,但并不能完全被取代,两者的迭代器的一致性不同的,hash table的迭代器是强一致性的,而concurrenthashmap是弱一致的。

ConcurrentHashMap的get,clear,iterator 都是弱一致性的。 Doug Lea 也将这个判断留给用户自己决定是否使用ConcurrentHashMap。

ConcurrentHashMap与HashTable都可以用于多线程的环境,但是当Hashtable的大小增加到一定的时候,性能会急剧下降,因为迭代时需要被锁定很长的时间。因为ConcurrentHashMap引入了分割(segmentation),不论它变得多么大,仅仅需要锁定map的某个部分,而其它的线程不需要等到迭代完成才能访问map。简而言之,在迭代的过程中,ConcurrentHashMap仅仅锁定map的某个部分,而Hashtable则会锁定整个map。

那么既然ConcurrentHashMap那么优秀,为什么还要有Hashtable的存在呢?ConcurrentHashMap能完全替代HashTable吗?

HashTable虽然性能上不如ConcurrentHashMap,但并不能完全被取代,两者的迭代器的一致性不同的,HashTable的迭代器是强一致性的,而ConcurrentHashMap是弱一致的。 ConcurrentHashMap的get,clear,iterator 都是弱一致性的。 Doug Lea 也将这个判断留给用户自己决定是否使用ConcurrentHashMap。

那么什么是强一致性和弱一致性呢?

get方法是弱一致的,是什么含义?可能你期望往ConcurrentHashMap底层数据结构中加入一个元素后,立马能对get可见,但ConcurrentHashMap并不能如你所愿。换句话说,put操作将一个元素加入到底层数据结构后,get可能在某段时间内还看不到这个元素,若不考虑内存模型,单从代码逻辑上来看,却是应该可以看得到的。

下面将结合代码和java内存模型相关内容来分析下put/get方法。put方法我们只需关注Segment#put,get方法只需关注Segment#get,在继续之前,先要说明一下Segment里有两个volatile变量:count和table;HashEntry里有一个volatile变量:value。

总结

ConcurrentHashMap的弱一致性主要是为了提升效率,是一致性与效率之间的一种权衡。要成为强一致性,就得到处使用锁,甚至是全局锁,这就与Hashtable和同步的HashMap一样了。

为什么HashMap是线程不安全的
HashMap 在并发执行 put 操作时会引起死循环,导致 CPU 利用率接近100%。因为多线程会导致 HashMap 的 Node 链表形成环形数据结构,一旦形成环形数据结构,Node 的 next 节点永远不为空,就会在获取 Node 时产生死循环。

如何线程安全的使用HashMap
了解了 HashMap 为什么线程不安全,那现在看看如何线程安全的使用 HashMap。这个无非就是以下三种方式:

Hashtable ConcurrentHashMap Synchronized Map

Hashtable

例子

//Hashtable
Map<String, String> hashtable = new Hashtable<>();
//synchronizedMap
Map<String, String> synchronizedHashMap = Collections.synchronizedMap(new HashMap<String, String>());
//ConcurrentHashMap
Map<String, String> concurrentHashMap = new ConcurrentHashMap<>();
Hashtable
先稍微吐槽一下,为啥命名不是 HashTable 啊,看着好难受不管了就装作它叫HashTable 吧。这货已经不常用了,就简单说说吧。HashTable 源码中是使用?synchronized?来保证线程安全的,比如下面的 get 方法和 put 方法:

public synchronized V get(Object key) {
// 省略实现
}
public synchronized V put(K key, V value) {
// 省略实现
}
所以当一个线程访问 HashTable 的同步方法时,其他线程如果也要访问同步方法,会被阻塞住。举个例子,当一个线程使用 put 方法时,另一个线程不但不可以使用 put 方法,连 get 方法都不可以,好霸道啊!!!so~~,效率很低,现在基本不会选择它了。

ConcurrentHashMap

ConcurrentHashMap 于 Java 7 的,和8有区别,在8中 CHM 摒弃了 Segment(锁段)的概念,而是启用了一种全新的方式实现,利用 CAS 算法,有时间会重新总结一下。

SynchronizedMap

synchronizedMap() 方法后会返回一个 SynchronizedMap 类的对象,而在 SynchronizedMap 类中使用了 synchronized 同步关键字来保证对 Map 的操作是线程安全的。

性能对比

这是要靠数据说话的时代,所以不能只靠嘴说 CHM 快,它就快了。写个测试用例,实际的比较一下这三种方式的效率(源码来源),下面的代码分别通过三种方式创建 Map 对象,使用 ExecutorService 来并发运行5个线程,每个线程添加/获取500K个元素。

Test started for: class java.util.Hashtable
2500K entried added/retrieved in 2018 ms
2500K entried added/retrieved in 1746 ms
2500K entried added/retrieved in 1806 ms
2500K entried added/retrieved in 1801 ms
2500K entried added/retrieved in 1804 ms
For class java.util.Hashtable the average time is 1835 ms

Test started for: class java.util.Collections$SynchronizedMap
2500K entried added/retrieved in 3041 ms
2500K entried added/retrieved in 1690 ms
2500K entried added/retrieved in 1740 ms
2500K entried added/retrieved in 1649 ms
2500K entried added/retrieved in 1696 ms
For class java.util.Collections$SynchronizedMap the average time is 1963 ms

Test started for: class java.util.concurrent.ConcurrentHashMap
2500K entried added/retrieved in 738 ms
2500K entried added/retrieved in 696 ms
2500K entried added/retrieved in 548 ms
2500K entried added/retrieved in 1447 ms
2500K entried added/retrieved in 531 ms
For class java.util.concurrent.ConcurrentHashMap the average time is 792 ms
ConcurrentHashMap 性能是明显优于 Hashtable 和 SynchronizedMap 的,CHM 花费的时间比前两个的一半还少。

多并发情况下HashMap是否还会产生死循环
今天本来想看下了ConcurrentHashMap的源码,ConcurrentHashMap是Java 5中支持高并发、高吞吐量的线程安全HashMap实现。

在看很多博客在介绍ConcurrentHashMap之前,都说HashMap适用于单线程访问,这是因为HashMap的所有方法都没有进行锁同步,因此是线程不安全的,不仅如此,当多线程访问的时候还容易产生死循环。

虽然自己在前几天的时候看过HashMap的源码,感觉思路啥啥的都还清楚,对于多线程访问只知道HashMap是线程不安全的,但是不知道HashMap在多线程并发的情况下会产生死循环呢,为什么会产生,何种情况下才会产生死循环呢???

《Java困惑》:多并发情况下HashMap是否还会产生死循环。

blog.csdn.net/u010412719/…

既然会产生死循环,为什么并发情况下,还是用ConcurrentHashMap。 jdk 好像有,但是Jdk8 已经修复了这个问题。

TreeMap、HashMap、LindedHashMap的区别
LinkedHashMap可以保证HashMap集合有序,存入的顺序和取出的顺序一致。

TreeMap实现SortMap接口,能够把它保存的记录根据键排序,默认是按键值的升序排序,也可以指定排序的比较器,当用Iterator遍历TreeMap时,得到的记录是排过序的。

HashMap不保证顺序,即为无序的,具有很快的访问速度。 HashMap最多只允许一条记录的键为Null;允许多条记录的值为 Null。 HashMap不支持线程的同步。

我们在开发的过程中使用HashMap比较多,在Map中在Map 中插入、删除和定位元素,HashMap 是最好的选择。

但如果您要按自然顺序或自定义顺序遍历键,那么TreeMap会更好。

如果需要输出的顺序和输入的相同,那么用LinkedHashMap 可以实现,它还可以按读取顺序来排列。

 

56、Collection包结构,与Collections的区别
blog.sina.com.cn/s/blog_1058…

Collection 是集合类的上级接口,子接口主要有Set、List 、Map。

Collecions 是针对集合类的一个帮助类, 提供了操作集合的工具方法,一系列静态方法实现对各种集合的搜索、排序线性、线程安全化等操作。

例如

Map<String, Object> map4 = Collections.synchronizedMap(new HashMap<String, Object>()); 线程安全 的HashMap
Collections.sort(List<T> list, Comparator<? super T> c); 排序 List
Collection

Collection 是单列集合

List

元素是有序的、可重复。 有序的 collection,可以对列表中每个元素的插入位置进行精确地控制。 可以根据元素的整数索引(在列表中的位置)访问元素,并搜索列表中的元素。 可存放重复元素,元素存取是有序的。

List接口中常用类

Vector:线程安全,但速度慢,已被ArrayList替代。底层数据结构是数组结构。 ArrayList:线程不安全,查询速度快。底层数据结构是数组结构。 LinkedList:线程不安全。增删速度快。底层数据结构是列表结构。

Set

Set接口中常用的类

Set(集) 元素无序的、不可重复。 取出元素的方法只有迭代器。不可以存放重复元素,元素存取是无序的。

HashSet:线程不安全,存取速度快。它是如何保证元素唯一性的呢?依赖的是元素的hashCode方法和euqals方法。 TreeSet:线程不安全,可以对Set集合中的元素进行排序。它的排序是如何进行的呢?通过compareTo或者compare方法中的来保证元素的唯一性。元素是以二叉树的形式存放的。

Map

map是一个双列集合

Hashtable:线程安全,速度快。底层是哈希表数据结构。是同步的。不允许null作为键,null作为值。

Properties:用于配置文件的定义和操作,使用频率非常高,同时键和值都是字符串。是集合中可以和IO技术相结合的对象。

HashMap:线程不安全,速度慢。底层也是哈希表数据结构。是不同步的。允许null作为键,null作为值,替代了Hashtable。

LinkedHashMap: 可以保证HashMap集合有序。存入的顺序和取出的顺序一致。

TreeMap:可以用来对Map集合中的键进行排序

57、Map或者HashMap的存储原理

答:HashMap是由数组+链表的一个结构组成,具体参照:HashMap的实现原理

58、ArrayList和LinkedList、Vector的区别?

答:总得来说可以理解为:.

     1.ArrayList是实现了基于动态数组的数据结构,LinkedList基于链表的数据结构。 
     2.对于随机访问get和set,ArrayList觉得优于LinkedList,因为LinkedList要移动指针。 
     3.对于新增和删除操作add和remove,LinedList比较占优势,因为ArrayList要移动数据

Vector和ArrayList类似,但属于强同步类,即线程安全的,具体比较参照:比较ArrayList、LinkedList、Vector

 

59、说说常见的集合有哪些吧?

答:Map 接口和 Collection 接口是所有集合框架的父接口:

  1. Collection 接口的子接口包括:Set 接口和 List 接口;
  2. Map 接口的实现类主要有:HashMap、TreeMap、Hashtable、ConcurrentHashMap 以及 Properties 等;
  3. Set 接口的实现类主要有:HashSet、TreeSet、LinkedHashSet 等;
  4. List 接口的实现类主要有:ArrayList、LinkedList、Stack 以及 Vector 等。

60、HashMap 和 Hashtable 的区别有哪些?(必问)

答:

  1. HashMap 没有考虑同步,是线程不安全的;Hashtable 使用了 synchronized 关键字,是线程安全的;
  2. 前者允许 null 作为 Key;后者不允许 null 作为 Key。

61、HashMap 的底层实现你知道吗?

答:在 Java8 之前,其底层实现是数组 + 链表实现,Java8 使用了数组 + 链表 + 红黑树实现。此时你可以简单的在纸上画图分析:

62、ConcurrentHashMap 和 Hashtable 的区别? (必问)

答:ConcurrentHashMap 结合了 HashMap 和 HashTable 二者的优势。HashMap 没有考虑同步,hashtable 考虑了同步的问题。但是 hashtable 在每次同步执行时都要锁住整个结构。 ConcurrentHashMap 锁的方式是稍微细粒度的。 ConcurrentHashMap 将 hash 表分为 16 个桶(默认值),诸如 get,put,remove 等常用操作只锁当前需要用到的桶。

面试官:ConcurrentHashMap 的具体实现知道吗?

答:

  1. 该类包含两个静态内部类 HashEntry 和 Segment;前者用来封装映射表的键值对,后者用来充当锁的角色;
  2. Segment 是一种可重入的锁 ReentrantLock,每个 Segment 守护一个 HashEntry 数组里得元素,当对 HashEntry 数组的数据进行修改时,必须首先获得对应的 Segment 锁。

63、HashMap 的长度为什么是 2 的幂次方?

答:

  1. 通过将 Key 的 hash 值与 length-1 进行 & 运算,实现了当前 Key 的定位,2 的幂次方可以减少冲突(碰撞)的次数,提高 HashMap 查询效率;
  2. 如果 length 为 2 的次幂 则 length-1 转化为二进制必定是 11111……的形式,在于 h 的二进制与操作效率会非常的快,而且空间不浪费;
  3. 如果 length 不是 2 的次幂,比如 length 为 15,则 length-1 为 14,对应的二进制为 1110,在于 h 与操作,最后一位都为 0,而 0001,0011,0101,1001,1011,0111,1101 这几个位置永远都不能存放元素了,空间浪费相当大。

更糟的是这种情况中,数组可以使用的位置比数组长度小了很多,这意味着进一步增加了碰撞的几率,减慢了查询的效率!这样就会造成空间的浪费。

64、List 和 Set 的区别是啥?

答:List 元素是有序的,可以重复;Set 元素是无序的,不可以重复。

65、List、Set 和 Map 的初始容量和加载因子

答:

1. List

  • ArrayList 的初始容量是 10;加载因子为 0.5; 扩容增量:原容量的 0.5 倍 +1;一次扩容后长度为 16。
  • Vector 初始容量为 10,加载因子是 1。扩容增量:原容量的 1 倍,如 Vector 的容量为 10,一次扩容后是容量为 20。

2. Set

HashSet,初始容量为 16,加载因子为 0.75; 扩容增量:原容量的 1 倍; 如 HashSet 的容量为 16,一次扩容后容量为 32

3. Map

HashMap,初始容量 16,加载因子为 0.75; 扩容增量:原容量的 1 倍; 如 HashMap 的容量为 16,一次扩容后容量为 32

66、Comparable 接口和 Comparator 接口有什么区别?

答:

  1. 前者简单,但是如果需要重新定义比较类型时,需要修改源代码。
  2. 后者不需要修改源代码,自定义一个比较器,实现自定义的比较方法。
    具体解析参考我的博客:Java 集合框架—Set

67、Java 集合的快速失败机制 “fail-fast”

答:它是 java 集合的一种错误检测机制,当多个线程对集合进行结构上的改变的操作时,有可能会产生 fail-fast 机制。

例如 :假设存在两个线程(线程 1、线程 2),线程 1 通过 Iterator 在遍历集合 A 中的元素,在某个时候线程 2 修改了集合 A 的结构(是结构上面的修改,而不是简单的修改集合元素的内容),那么这个时候程序就会抛出 ConcurrentModificationException 异常,从而产生 fail-fast 机制。

原因: 迭代器在遍历时直接访问集合中的内容,并且在遍历过程中使用一个 modCount 变量。集合在被遍历期间如果内容发生变化,就会改变 modCount 的值。

每当迭代器使用 hashNext()/next() 遍历下一个元素之前,都会检测 modCount 变量是否为 expectedmodCount 值,是的话就返回遍历;否则抛出异常,终止遍历。

解决办法:

  1. 在遍历过程中,所有涉及到改变 modCount 值得地方全部加上 synchronized;
  2. 使用 CopyOnWriteArrayList 来替换 ArrayList。
小结:本小节是 Java 中关于集合的考察,是 Java 岗位面试中必考的知识点,除了应该掌握以上的问题,包括各个集合的底层实现也建议各位同学阅读,加深理解。

 

 

 

多线程

1、创建线程的方式及实现

2、sleep() 、join()、yield()有什么区别

3、说说 CountDownLatch 原理

4、说说 CyclicBarrier 原理

5、说说 Semaphore 原理

6、说说 Exchanger 原理

7、说说 CountDownLatch 与 CyclicBarrier 区别

8、ThreadLocal 原理分析

9、讲讲线程池的实现原理

10、线程池的几种方式

11、线程的生命周期

12、

ThreadLocal(线程变量副本)
Synchronized实现内存共享,ThreadLocal为每个线程维护一个本地变量。
采用空间换时间,它用于线程间的数据隔离,为每一个使用该变量的线程提供一个副本,每个线程都可以独立地改变自己的副本,而不会和其他线程的副本冲突。
ThreadLocal类中维护一个Map,用于存储每一个线程的变量副本,Map中元素的键为线程对象,而值为对应线程的变量副本。
ThreadLocal在Spring中发挥着巨大的作用,在管理Request作用域中的Bean、事务管理、任务调度、AOP等模块都出现了它的身影。
Spring中绝大部分Bean都可以声明成Singleton作用域,采用ThreadLocal进行封装,因此有状态的Bean就能够以singleton的方式在多线程中正常工作了。
友情链接:深入研究java.lang.ThreadLocal类

13、

StringBuffer是线程安全的,每次操作字符串,String会生成一个新的对象,而StringBuffer不会;StringBuilder是非线程安全的
友情链接:String、StringBuffer与StringBuilder之间区别

14、

fail-fast:机制是java集合(Collection)中的一种错误机制。当多个线程对同一个集合的内容进行操作时,就可能会产生fail-fast事件。
例如:当某一个线程A通过iterator去遍历某集合的过程中,若该集合的内容被其他线程所改变了;那么线程A访问集合时,就会抛出ConcurrentModificationException异常,产生fail-fast事件

15、

happens-before:如果两个操作之间具有happens-before 关系,那么前一个操作的结果就会对后面一个操作可见。
1.程序顺序规则:一个线程中的每个操作,happens- before 于该线程中的任意后续操作。
2.监视器锁规则:对一个监视器锁的解锁,happens- before 于随后对这个监视器锁的加锁。
3.volatile变量规则:对一个volatile域的写,happens- before于任意后续对这个volatile域的读。
4.传递性:如果A happens- before B,且B happens- before C,那么A happens- before C。
5.线程启动规则:Thread对象的start()方法happens- before于此线程的每一个动作。

16、

Volatile和Synchronized四个不同点:
1 粒度不同,前者针对变量 ,后者锁对象和类
2 syn阻塞,volatile线程不阻塞
3 syn保证三大特性,volatile不保证原子性
4 syn编译器优化,volatile不优化 volatile具备两种特性:

1.保证此变量对所有线程的可见性,指一条线程修改了这个变量的值,新值对于其他线程来说是可见的,但并不是多线程安全的。
2.禁止指令重排序优化。

Volatile如何保证内存可见性:

1.当写一个volatile变量时,JMM会把该线程对应的本地内存中的共享变量刷新到主内存。
2.当读一个volatile变量时,JMM会把该线程对应的本地内存置为无效。线程接下来将从主内存中读取共享变量。

同步:就是一个任务的完成需要依赖另外一个任务,只有等待被依赖的任务完成后,依赖任务才能完成。
异步:不需要等待被依赖的任务完成,只是通知被依赖的任务要完成什么工作,只要自己任务完成了就算完成了,被依赖的任务是否完成会通知回来。(异步的特点就是通知)。 打电话和发短信来比喻同步和异步操作。
阻塞:CPU停下来等一个慢的操作完成以后,才会接着完成其他的工作。
非阻塞:非阻塞就是在这个慢的执行时,CPU去做其他工作,等这个慢的完成后,CPU才会接着完成后续的操作。
非阻塞会造成线程切换增加,增加CPU的使用时间能不能补偿系统的切换成本需要考虑。
友情链接:Java并发编程之volatile关键字解析

17、

线程池的作用: 在程序启动的时候就创建若干线程来响应处理,它们被称为线程池,里面的线程叫工作线程
第一:降低资源消耗。通过重复利用已创建的线程降低线程创建和销毁造成的消耗。
第二:提高响应速度。当任务到达时,任务可以不需要等到线程创建就能立即执行。
第三:提高线程的可管理性。
常用线程池:ExecutorService 是主要的实现类,其中常用的有 Executors.newSingleThreadPool(),newFixedThreadPool(),newcachedTheadPool(),newScheduledThreadPool()。
友情链接:线程池原理
友情链接:线程池原理解析

 

18、

ExecutorService service = Executors…. ExecutorService service = new ThreadPoolExecutor() ExecutorService service = new ScheduledThreadPoolExecutor();

ThreadPoolExecutor源码分析

线程池本身的状态:

等待任务队列和工作集:

线程池的主要状态锁:

线程池的存活时间和大小:

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

  1. 如果当前池大小 poolSize 小于 corePoolSize ,则创建新线程执行任务。
  2. 如果当前池大小 poolSize 大于 corePoolSize ,且等待队列未满,则进入等待队列
  3. 如果当前池大小 poolSize 大于 corePoolSize 且小于 maximumPoolSize ,且等待队列已满,则创建新线程执行任务。
  4. 如果当前池大小 poolSize 大于 corePoolSize 且大于 maximumPoolSize ,且等待队列已满,则调用拒绝策略来处理该任务。
  5. 线程池里的每个线程执行完任务后不会立刻退出,而是会去检查下等待队列里是否还有线程任务需要执行,如果在 keepAliveTime 里等不到新的任务了,那么线程就会退出。

Executor包结构

CopyOnWriteArrayList : 写时加锁,当添加一个元素的时候,将原来的容器进行copy,复制出一个新的容器,然后在新的容器里面写,写完之后再将原容器的引用指向新的容器,而读的时候是读旧容器的数据,所以可以进行并发的读,但这是一种弱一致性的策略。
使用场景:CopyOnWriteArrayList适合使用在读操作远远大于写操作的场景里,比如缓存。

19、

wait()和sleep()的区别

sleep来自Thread类,和wait来自Object类

调用sleep()方法的过程中,线程不会释放对象锁。而 调用 wait 方法线程会释放对象锁

sleep睡眠后不出让系统资源,wait让出系统资源其他线程可以占用CPU

sleep(milliseconds)需要指定一个睡眠时间,时间一到会自动唤醒

20、

String,StringBuffer和StringBuilder的区别;

21、Object的方法有哪些:比如有wait方法,为什么会有;

22、wait和sleep的区别,必须理解;

23、说说阻塞队列的实现:可以参考ArrayBlockingQueue的底层实现(锁和同步都行);

24、用过并发包的哪些类;

25、什么地方用了多线程;

26、Excutors可以产生哪些线程池;

27、为什么要用线程池;

28、volatile关键字的用法:使多线程中的变量可见;

29、多线程 
(1)实现线程同步: 
http://blog.csdn.net/zhaojw_420/article/details/67823750 
(2)生产者消费者问题: 
http://blog.csdn.net/zhaojw_420/article/details/67826902 
(3)线程安全 
(4)线程死锁 
(5)Synchronize实现原理 
(7)happen-before规则: 
http://blog.csdn.net/zhaojw_420/article/details/70477874 
(8)线程池 
(9)DCL失效原因以及解决办法: 
http://blog.csdn.net/zhaojw_420/article/details/70477921 
(10)线程实现方式:Thread,Runable,Callable的区别

30、wait和sleep的区别

31、synchronized 的实现原理以及锁优化?

32、volatile 的实现原理?

33、Java 的信号灯?

34、synchronized 在静态方法和普通方法的区别?

35、怎么实现所有线程在等待某个事件的发生才会去执行?

36、CAS?CAS 有什么缺陷,如何解决?

37、synchronized 和 lock 有什么区别?

38、Hashtable 是怎么加锁的 ?

39、HashMap 的并发问题?

40、ConcurrenHashMap 介绍?1.8 中为什么要用红黑树?

41、AQS

42、Java 内存模型?

43、如何保证多线程下 i++ 结果正确?

44、线程池的种类,区别和使用场景?

45、分析线程池的实现原理和线程的调度过程?

46、线程池如何调优,最大数目如何确认?

47、ThreadLocal原理,用的时候需要注意什么?

48、CountDownLatch 和 CyclicBarrier 的用法,以及相互之间的差别?

49、LockSupport工具

50、Condition接口及其实现原理

51、Fork/Join框架的理解

52、分段锁的原理,锁力度减小的思考

53、八种阻塞队列以及各个阻塞队列的特性

54. ThreadLocal的实现原理

A:就是一个只有当前线程可访问的以ThreadLocal实例为Key的HashMap,其内部的Map实现和HashMap的实现差不多,这个Map的实例存储在Thread对象上,所以通过封装,能保证线程只访问自己的ThreadLocal变量。

好吧,很可能面试官想听到的就是这样一句话。

但ThreadLocal之所以重要其实是其背后的设计思想,它将变量从共享的和需要多线程同步的环境转移到了线程私有和不需要同步的环境内,这种思想可以用来解决很多不同的场景下的问题。

但是,谁关心这些呢?

55. 多个线程同时读写,读线程的数量远远⼤于写线程,你认为应该如何解决 并发的问题?你会选择加什么样的锁?

56. JAVA的AQS是否了解,它是⼲嘛的?

57. 除了synchronized关键字之外,你是怎么来保障线程安全的?

58. 什么时候需要加volatile关键字?它能保证线程安全吗?

59. 线程池内的线程如果全部忙,提交⼀个新的任务,会发⽣什么?队列全部 塞满了之后,还是忙,再提交会发⽣什么?

60. Tomcat本身的参数你⼀般会怎么调整?

61. synchronized关键字锁住的是什么东⻄?在字节码中是怎么表示的?在内 存中的对象上表现为什么?

62. wait/notify/notifyAll⽅法需不需要被包含在synchronized块中?这是为什 么?

63. ExecutorService你⼀般是怎么⽤的?是每个service放⼀个还是⼀个项⽬ ⾥⾯放⼀个?有什么好处?

64、 什么是线程?

65、 线程和进程有什么区别?

66、 如何在Java中实现线程?

67、 用Runnable还是Thread?

68、Thread 类中的start() 和 run() 方法有什么区别?

69、 Java中CyclicBarrier 和 CountDownLatch有什么不同?

70、 Java中的volatile 变量是什么?

71、 Java中的同步集合与并发集合有什么区别?

72、 如何避免死锁?

73、Java中活锁和死锁有什么区别?

74、 Java中synchronized 和 ReentrantLock 有什么不同?

75、 Java中ConcurrentHashMap的并发度是什么?

76、 如何在Java中创建Immutable对象?

77、 单例模式的双检锁是什么?

78、写出3条你遵循的多线程最佳实践

79、. 常用的线程池模式以及不同线程池的使用场景

80. String,StringBuffer和StringBuilder的区别

1、运行速度,或者说是执行速度,在这方面运行速度快慢为:StringBuilder > StringBuffer > String。

2、线程安全上,StringBuilder是线程不安全的,而StringBuffer是线程安全的。

适用场景分析:

String:适用于少量的字符串操作的情况

StringBuilder:适用于单线程下在字符缓冲区进行大量操作的情况

StringBuffer:适用多线程下在字符缓冲区进行大量操作的情况

81. wait和sleep的区别

1、sleep()方法是属于Thread类中的,而wait()方法,则是属于Object类中的。

2、sleep()方法导致了程序暂停执行指定的时间,让出cpu给其他线程,但是他的监控状态依然保持着,当指定的时间到了又会自动恢复运行状态。所以在调用sleep()方法的过程中,线程不会释放对象锁。

3、调用wait()方法的时候,线程会放弃对象锁,进入等待此对象的等待锁定池,只有针对此对象调用notify()方法后本线程才进入对象锁定池准备获取对象锁进入运行状态。

 

82、为什么要用线程池

那先要明白什么是线程池

线程池是指在初始化一个多线程应用程序过程中创建一个线程集合,然后在需要执行新的任务时重用这些线程而不是新建一个线程。

使用线程池的好处

1、线程池改进了一个应用程序的响应时间。由于线程池中的线程已经准备好且等待被分配任务,应用程序可以直接拿来使用而不用新建一个线程。

2、线程池节省了CLR 为每个短生存周期任务创建一个完整的线程的开销并可以在任务完成后回收资源。

3、线程池根据当前在系统中运行的进程来优化线程时间片。 

4、线程池允许我们开启多个任务而不用为每个线程设置属性。

5、线程池允许我们为正在执行的任务的程序参数传递一个包含状态信息的对象引用。

6、线程池可以用来解决处理一个特定请求最大线程数量限制问题。

 

83、多线程实现方式:https://www.cnblogs.com/felixzh/p/6036074.html 

84、线程的状态转换:http://blog.csdn.net/sinat_36042530/article/details/52565296

85、如何停止一个线程:https://www.cnblogs.com/greta/p/5624839.html

86、什么是线程安全:http://blog.csdn.net/ghevinn/article/details/37764791

87、synchronized和lock的区别:http://blog.csdn.net/u012403290/article/details/64910926?locationNum=11&fps=1

88、sleep和wait区别:http://blog.csdn.net/u012050154/article/details/50903326
89、.java线程池:http://www.importnew.com/19011.html
90、.并发工具类:http://blog.csdn.net/sunxianghuang/article/details/52277394
91、.并发容器类:http://blog.csdn.net/jianghuxiaojin/article/details/52006183
92、.volatile关键字:http://blog.csdn.net/victor_cindy1/article/details/44310195

93、Volatile的特征:

A、禁止指令重排(有例外) 
B、可见性

Volatile的内存语义:

当写一个volatile变量时,JMM会把线程对应的本地内存中的共享变量值刷新到主内存。

 

当读一个volatile变量时,JMM会把线程对应的本地内存置为无效,线程接下来将从主内存中读取共享变量。

 

Volatile的重排序

1、当第二个操作为volatile写操做时,不管第一个操作是什么(普通读写或者volatile读写),都不能进行重排序。这个规则确保volatile写之前的所有操作都不会被重排序到volatile之后;

2、当第一个操作为volatile读操作时,不管第二个操作是什么,都不能进行重排序。这个规则确保volatile读之后的所有操作都不会被重排序到volatile之前;

3、当第一个操作是volatile写操作时,第二个操作是volatile读操作,不能进行重排序。

这个规则和前面两个规则一起构成了:两个volatile变量操作不能够进行重排序;

除以上三种情况以外可以进行重排序。

比如:

1、第一个操作是普通变量读/写,第二个是volatile变量的读; 
2、第一个操作是volatile变量的写,第二个是普通变量的读/写;

 

94、内存屏障/内存栅栏

内存屏障(Memory Barrier,或有时叫做内存栅栏,Memory Fence)是一种CPU指令,用于控制特定条件下的重排序和内存可见性问题。Java编译器也会根据内存屏障的规则禁止重排序。(也就是让一个CPU处理单元中的内存状态对其它处理单元可见的一项技术。)

内存屏障可以被分为以下几种类型:

LoadLoad屏障:对于这样的语句Load1; LoadLoad; Load2,在Load2及后续读取操作要读取的数据被访问前,保证Load1要读取的数据被读取完毕。

StoreStore屏障:对于这样的语句Store1; StoreStore; Store2,在Store2及后续写入操作执行前,保证Store1的写入操作对其它处理器可见。

LoadStore屏障:对于这样的语句Load1; LoadStore; Store2,在Store2及后续写入操作被刷出前,保证Load1要读取的数据被读取完毕。

StoreLoad屏障:对于这样的语句Store1; StoreLoad; Load2,在Load2及后续所有读取操作执行前,保证Store1的写入对所有处理器可见。它的开销是四种屏障中最大的。

在大多数处理器的实现中,这个屏障是个万能屏障,兼具其它三种内存屏障的功能。

内存屏障阻碍了CPU采用优化技术来降低内存操作延迟,必须考虑因此带来的性能损失。为了达到最佳性能,最好是把要解决的问题模块化,这样处理器可以按单元执行任务,然后在任务单元的边界放上所有需要的内存屏障。采用这个方法可以让处理器不受限的执行一个任务单元。合理的内存屏障组合还有一个好处是:缓冲区在第一次被刷后开销会减少,因为再填充改缓冲区不需要额外工作了。

 

95、happens-before原则

 

96、

 

Java 线程有哪些状态,这些状态之间是如何转化的?

 

  1. 新建(new):新创建了一个线程对象。

  2. 可运行(runnable):线程对象创建后,其他线程(比如main线程)调用了该对象的start()方法。该状态的线程位于可运行线程池中,等待被线程调度选中,获取cpu 的使用权 。

  3. 运行(running):可运行状态(runnable)的线程获得了cpu 时间片(timeslice) ,执行程序代码。

  4. 阻塞(block):阻塞状态是指线程因为某种原因放弃了cpu 使用权,也即让出了cpu timeslice,暂时停止运行。直到线程进入可运行(runnable)状态,才有机会再次获得cpu timeslice 转到运行(running)状态。阻塞的情况分三种:

(一). 等待阻塞:运行(running)的线程执行o.wait()方法,JVM会把该线程放入等待队列(waitting queue)中。

(二). 同步阻塞:运行(running)的线程在获取对象的同步锁时,若该同步锁被别的线程占用,则JVM会把该线程放入锁池(lock pool)中。

(三). 其他阻塞:运行(running)的线程执行Thread.sleep(long ms)或t.join()方法,或者发出了I/O请求时,JVM会把该线程置为阻塞状态。当sleep()状态超时、join()等待线程终止或者超时、或者I/O处理完毕时,线程重新转入可运行(runnable)状态。

  1. 死亡(dead):线程run()、main() 方法执行结束,或者因异常退出了run()方法,则该线程结束生命周期。死亡的线程不可再次复生。

97、

Java中CAS算法

参考:http://www.kancloud.cn/seaboat/java-concurrent/117870

98、

Java线程间的通信方式?

参考1:http://www.cnblogs.com/mengdd/archive/2013/02/20/2917956.html

参考2:http://www.jb51.net/article/84213.htm

99、Java实现多线程有哪几种方式。
100、Callable和Future的了解。
101、线程池的参数有哪些,在线程池创建一个线程的过程。
102、volitile关键字的作用,原理。
103、synchronized关键字的用法,优缺点。
104、Lock接口有哪些实现类,使用场景是什么。
105、可重入锁的用处及实现原理,写时复制的过程,读写锁,分段锁(ConcurrentHashMap中的segment)。
106、悲观锁,乐观锁,优缺点,CAS有什么缺陷,该如何解决。
107、ABC三个线程如何保证顺序执行。
108、线程的状态都有哪些。
109、sleep和wait的区别。
110、notify和notifyall的区别。
111、ThreadLocal的了解,实现原理。

112.多线程的实现方式#

继承Thread类、实现Runnable接口、使用ExecutorService、Callable、Future实现有返回结果的多线程。

113、.线程的状态转换#

 

114、.如何停止一个线程#
参考文章:
http://www.cnblogs.com/greta/p/5624839.html

115、.什么是线程安全#
线程安全就是多线程访问同一代码,不会产生不确定的结果。

116、.如何保证线程安全#
对非安全的代码进行加锁控制;
使用线程安全的类;
多线程并发情况下,线程共享的变量改为方法级的局部变量。

17、.synchronized如何使用#
synchronized是Java中的关键字,是一种同步锁。它修饰的对象有以下几种:
1). 修饰一个代码块,被修饰的代码块称为同步语句块,其作用的范围是大括号{}括起来的代码,作用的对象是调用这个代码块的对象;
2). 修饰一个方法,被修饰的方法称为同步方法,其作用的范围是整个方法,作用的对象是调用这个方法的对象;
3). 修改一个静态的方法,其作用的范围是整个静态方法,作用的对象是这个类的所有对象;
4). 修改一个类,其作用的范围是synchronized后面括号括起来的部分,作用主的对象是这个类的所有对象。

118、.synchronized和Lock的区别#
主要相同点:Lock能完成synchronized所实现的所有功能
主要不同点:Lock有比synchronized更精确的线程语义和更好的性能。Lock的锁定是通过代码实现的,而synchronized是在JVM层面上实现的,synchronized会自动释放锁,而Lock一定要求程序员手工释放,并且必须在finally从句中释放。Lock还有更强大的功能,例如,它的tryLock方法可以非阻塞方式去拿锁。Lock锁的范围有局限性,块范围,而synchronized可以锁住块、对象、类。

119、.多线程如何进行信息交互#
void notify() 唤醒在此对象监视器上等待的单个线程。
void notifyAll() 唤醒在此对象监视器上等待的所有线程。
void wait() 导致当前的线程等待,直到其他线程调用此对象的notify()方法或notifyAll()方法。
void wait(long timeout) 导致当前的线程等待,直到其他线程调用此对象的notify()方法或notifyAll()方法,或者超过指定的时间量。
void wait(long timeout, int nanos) 导致当前的线程等待,直到其他线程调用此对象的notify()方法或notifyAll()方法,或者其他某个线程中断当前线程,或者已超过某个实际时间量。

120、.sleep和wait的区别(考察的方向是是否会释放锁)#
sleep()方法是Thread类中方法,而wait()方法是Object类中的方法。
sleep()方法导致了程序暂停执行指定的时间,让出cpu该其他线程,但是他的监控状态依然保持者,当指定的时间到了又会自动恢复运行状态,在调用sleep()方法的过程中,线程不会释放对象锁。而当调用wait()方法的时候,线程会放弃对象锁,进入等待此对象的等待锁定池,只有针对此对象调用notify()方法后本线程才进入对象锁定池准备。

121、.多线程与死锁#
死锁是指两个或两个以上的进程在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外力作用,它们都将无法推进下去。
产生死锁的原因:
一.因为系统资源不足。
二.进程运行推进的顺序不合适。
三.资源分配不当。

122、.如何才能产生死锁#
产生死锁的四个必要条件:
一.互斥条件:所谓互斥就是进程在某一时间内独占资源。
二.请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放。
三.不剥夺条件:进程已获得资源,在末使用完之前,不能强行剥夺。
四.循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系。

123、.死锁的预防#
打破产生死锁的四个必要条件中的一个或几个,保证系统不会进入死锁状态。
一.打破互斥条件。即允许进程同时访问某些资源。但是,有的资源是不允许被同时访问的,像打印机等等,这是由资源本身的属性所决定的。所以,这种办法并无实用价值。
二.打破不可抢占条件。即允许进程强行从占有者那里夺取某些资源。就是说,当一个进程已占有了某些资源,它又申请新的资源,但不能立即被满足时,它必须释放所占有的全部资源,以后再重新申请。它所释放的资源可以分配给其它进程。这就相当于该进程占有的资源被隐蔽地强占了。这种预防死锁的方法实现起来困难,会降低系统性能。
三.打破占有且申请条件。可以实行资源预先分配策略。即进程在运行前一次性地向系统申请它所需要的全部资源。如果某个进程所需的全部资源得不到满足,则不分配任何资源,此进程暂不运行。只有当系统能够满足当前进程的全部资源需求时,才一次性地将所申请的资源全部分配给该进程。由于运行的进程已占有了它所需的全部资源,所以不会发生占有资源又申请资源的现象,因此不会发生死锁。
四.打破循环等待条件,实行资源有序分配策略。采用这种策略,即把资源事先分类编号,按号分配,使进程在申请,占用资源时不会形成环路。所有进程对资源的请求必须严格按资源序号递增的顺序提出。进程占用了小号资源,才能申请大号资源,就不会产生环路,从而预防了死锁。

124、.什么叫守护线程,用什么方法实现守护线程#
守护线程是为其他线程的运行提供服务的线程。
setDaemon(boolean on)方法可以方便的设置线程的Daemon模式,true为守护模式,false为用户模式。

125、.Java线程池技术及原理#
参考文章:
http://www.importnew.com/19011.html
http://www.cnblogs.com/dolphin0520/p/3932921.html

126、.java并发包concurrent及常用的类#
这个内容有点多,参考文章:
并发包诸类概览:http://www.raychase.net/1912
线程池:http://www.cnblogs.com/dolphin0520/p/3932921.html
锁:http://www.cnblogs.com/dolphin0520/p/3923167.html
集合:http://www.cnblogs.com/huangfox/archive/2012/08/16/2642666.html

 127、.volatile关键字#

用volatile修饰的变量,线程在每次使用变量的时候,都会读取变量修改后的最的值。volatile很容易被误用,用来进行原子性操作。
Java语言中的volatile变量可以被看作是一种“程度较轻的
synchronized”;与
synchronized 块相比,volatile 变量所需的编码较少,并且运行时开销也较少,但是它所能实现的功能也仅是synchronized的一部分。锁提供了两种主要特性:互斥(mutual
exclusion)和可见性(visibility)。互斥即一次只允许一个线程持有某个特定的锁,因此可使用该特性实现对共享数据的协调访问协议,这样,一次就只有一个线程能够使用该共享数据。可见性必须确保释放锁之前对共享数据做出的更改对于随后获得该锁的另一个线程是可见的,如果没有同步机制提供的这种可见性保证,线程看到的共享变量可能是修改前的值或不一致的值,这将引发许多严重问题。Volatile变量具有synchronized的可见性特性,但是不具备原子特性。这就是说线程能够自动发现volatile
变量的最新值。
要使volatile变量提供理想的线程安全,必须同时满足下面两个条件:对变量的写操作不依赖于当前值;该变量没有包含在具有其他变量的不变式中。
第一个条件的限制使volatile变量不能用作线程安全计数器。虽然增量操作(x++)看上去类似一个单独操作,实际上它是一个由读取-修改-写入操作序列组成的组合操作,必须以原子方式执行,而volatile不能提供必须的原子特性。实现正确的操作需要使x 的值在操作期间保持不变,而volatile
变量无法实现这点。
每一个线程运行时都有一个线程栈,线程栈保存了线程运行时候变量值信息。当线程访问某一个对象时候值的时候,首先通过对象的引用找到对应在堆内存的变量的值,然后把堆内存变量的具体值load到线程本地内存中,建立一个变量副本,之后线程就不再和对象在堆内存变量值有任何关系,而是直接修改副本变量的值,在修改完之后的某一个时刻(线程退出之前),自动把线程变量副本的值回写到对象在堆中变量。这样在堆中的对象的值就产生变化了。

 

 
 

 

read and load 从主存复制变量到当前工作内存
use and assign 执行代码,改变共享变量值
store and write 用工作内存数据刷新主存相关内容
其中use and
assign 可以多次出现,但是这一些操作并不是原子性,也就是在read load之后,如果主内存count变量发生修改之后,线程工作内存中的值由于已经加载,不会产生对应的变化,所以计算出来的结果会和预期不一样。

128、简单说说线程池的原理和实现

解答:线程原理及实现

129、SimpleDataFormat是非线程安全的,如何更好的使用而避免风险呢

答:关于SimpleDateFormat安全的时间格式化线程安全问题

130、另总结多线程相关面试题50道

131、说说线程安全的几种实现方式?

答:什么是线程安全? 我的理解是这样的,一个对象被多个线程同时访问,还能保持其内部属性的顺序性及同步性,则认定为线程安全。实现线程安全的三种方式:被volatile、synchronized等关键字修饰,或者使用java.util.concurrent下面的类库。  至于前两者的关系,参考:synchronized和volatile的用法区别

132、方法内部,如何实现更好的异步?

答:我们知道异步其实就是让另一个线程去跑,那么如何创建线程?  第一种直接new Thread ,第二种new 一个实现Runnable接口的实现类。 第三种,通过线程池来管理创建等 ,这里说到更好的实现异步,那就是说我们在方法内部避免频繁的new 线程,就可以考虑线程池了。 那么线程池如何创建? 这里可以new 一个线程池,但是需要考虑单例,或者在程序初始启东时,就创建一个线程池,让他跑着,然后在具体方法的时候,通过线程池来创建线程,实现异步

133、多线程和单线程的区别和联系:

答:

  1. 在单核 CPU 中,将 CPU 分为很小的时间片,在每一时刻只能有一个线程在执行,是一种微观上轮流占用 CPU 的机制。
  2. 多线程会存在线程上下文切换,会导致程序执行速度变慢,即采用一个拥有两个线程的进程执行所需要的时间比一个线程的进程执行两次所需要的时间要多一些。

结论:即采用多线程不会提高程序的执行速度,反而会降低速度,但是对于用户来说,可以减少用户的响应时间。

134、如何指定多个线程的执行顺序?

解析:面试官会给你举个例子,如何让 10 个线程按照顺序打印 0123456789?(写代码实现)

答:

  1. 设定一个 orderNum,每个线程执行结束之后,更新 orderNum,指明下一个要执行的线程。并且唤醒所有的等待线程。
  2. 在每一个线程的开始,要 while 判断 orderNum 是否等于自己的要求值!!不是,则 wait,是则执行本线程。

135、线程和进程的区别:(必考)

答:

  1. 进程是一个 “执行中的程序”,是系统进行资源分配和调度的一个独立单位;
  2. 线程是进程的一个实体,一个进程中拥有多个线程,线程之间共享地址空间和其它资源(所以通信和同步等操作线程比进程更加容易);
  3. 线程上下文的切换比进程上下文切换要快很多。
  • (1)进程切换时,涉及到当前进程的 CPU 环境的保存和新被调度运行进程的 CPU 环境的设置。
  • (2)线程切换仅需要保存和设置少量的寄存器内容,不涉及存储管理方面的操作。

136、多线程产生死锁的 4 个必要条件?

答:

  1. 互斥条件:一个资源每次只能被一个线程使用;
  2. 请求与保持条件:一个线程因请求资源而阻塞时,对已获得的资源保持不放;
  3. 不剥夺条件:进程已经获得的资源,在未使用完之前,不能强行剥夺;
  4. 循环等待条件:若干线程之间形成一种头尾相接的循环等待资源关系。

面试官:如何避免死锁?(经常接着问这个问题哦~)

答:指定获取锁的顺序,举例如下:

  1. 比如某个线程只有获得 A 锁和 B 锁才能对某资源进行操作,在多线程条件下,如何避免死锁?
  2. 获得锁的顺序是一定的,比如规定,只有获得 A 锁的线程才有资格获取 B 锁,按顺序获取锁就可以避免死锁!!!

137、sleep( ) 和 wait( n)、wait( ) 的区别:

答:

  1. sleep 方法:是 Thread 类的静态方法,当前线程将睡眠 n 毫秒,线程进入阻塞状态。当睡眠时间到了,会解除阻塞,进行可运行状态,等待 CPU 的到来。睡眠不释放锁(如果有的话);
  2. wait 方法:是 Object 的方法,必须与 synchronized 关键字一起使用,线程进入阻塞状态,当 notify 或者 notifyall 被调用后,会解除阻塞。但是,只有重新占用互斥锁之后才会进入可运行状态。睡眠时,释放互斥锁。

138、synchronized 关键字:

答:底层实现:

  1. 进入时,执行 monitorenter,将计数器 +1,释放锁 monitorexit 时,计数器-1;
  2. 当一个线程判断到计数器为 0 时,则当前锁空闲,可以占用;反之,当前线程进入等待状态。

含义:(monitor 机制)

Synchronized 是在加锁,加对象锁。对象锁是一种重量锁(monitor),synchronized 的锁机制会根据线程竞争情况在运行时会有偏向锁(单一线程)、轻量锁(多个线程访问 synchronized 区域)、对象锁(重量锁,多个线程存在竞争的情况)、自旋锁等。

该关键字是一个几种锁的封装。

139、volatile 关键字

答:该关键字可以保证可见性不保证原子性。

功能:

  1. 主内存和工作内存,直接与主内存产生交互,进行读写操作,保证可见性;
  2. 禁止 JVM 进行的指令重排序。

解析:关于指令重排序的问题,可以查阅 DCL 双检锁失效相关资料。

140、ThreadLocal(线程局部变量)关键字:

答:当使用 ThreadLocal 维护变量时,其为每个使用该变量的线程提供独立的变量副本,所以每一个线程都可以独立的改变自己的副本,而不会影响其他线程对应的副本。

ThreadLocal 内部实现机制:

  1. 每个线程内部都会维护一个类似 HashMap 的对象,称为 ThreadLocalMap,里边会包含若干了 Entry(K-V 键值对),相应的线程被称为这些 Entry 的属主线程;
  2. Entry 的 Key 是一个 ThreadLocal 实例,Value 是一个线程特有对象。Entry 的作用即是:为其属主线程建立起一个 ThreadLocal 实例与一个线程特有对象之间的对应关系;
  3. Entry 对 Key 的引用是弱引用;Entry 对 Value 的引用是强引用。

141、Atomic 关键字:

答:可以使基本数据类型以原子的方式实现自增自减等操作。参考我的博客:concurrent.atomic 包下的类 AtomicInteger 的使用。

142、线程池有了解吗?(必考)

答:java.util.concurrent.ThreadPoolExecutor 类就是一个线程池。客户端调用 ThreadPoolExecutor.submit(Runnable task) 提交任务,线程池内部维护的工作者线程的数量就是该线程池的线程池大小,有 3 种形态:

  • 当前线程池大小 :表示线程池中实际工作者线程的数量;
  • 最大线程池大小 (maxinumPoolSize):表示线程池中允许存在的工作者线程的数量上限;
  • 核心线程大小 (corePoolSize ):表示一个不大于最大线程池大小的工作者线程数量上限。
  1. 如果运行的线程少于 corePoolSize,则 Executor 始终首选添加新的线程,而不进行排队;
  2. 如果运行的线程等于或者多于 corePoolSize,则 Executor 始终首选将请求加入队列,而不是添加新线程;
  3. 如果无法将请求加入队列,即队列已经满了,则创建新的线程,除非创建此线程超出 maxinumPoolSize, 在这种情况下,任务将被拒绝。
小结:本小节内容涉及到 Java 中多线程编程,线程安全等知识,是面试中的重点和难点。

 

 

 

 

 


 

 

 

锁机制

1、说说线程安全问题

2、volatile 实现原理

3、synchronize 实现原理

4、synchronized 与 lock 的区别

5、CAS 乐观锁

6、ABA 问题

7、乐观锁的业务场景及实现方式

8、

Synchronized 与Lock都是可重入锁,同一个线程再次进入同步代码的时候.可以使用自己已经获取到的锁。
Synchronized是悲观锁机制,独占锁。而Locks.ReentrantLock是,每次不加锁而是假设没有冲突而去完成某项操作,如果因为冲突失败就重试,直到成功为止。 ReentrantLock适用场景

  1. 某个线程在等待一个锁的控制权的这段时间需要中断
  2. 需要分开处理一些wait-notify,ReentrantLock里面的Condition应用,能够控制notify哪个线程,锁可以绑定多个条件。
  3. 具有公平锁功能,每个到来的线程都将排队等候。

友情链接: Synchronized关键字、Lock,并解释它们之间的区别

9、

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

10、

死锁的必要条件

  1. 互斥 至少有一个资源处于非共享状态
  2. 占有并等待
  3. 非抢占
  4. 循环等待

解决死锁,第一个是死锁预防,就是不让上面的四个条件同时成立。二是,合理分配资源。
三是使用银行家算法,如果该进程请求的资源操作系统剩余量可以满足,那么就分配。

11、悲观锁和乐观锁的区别,怎么实现;

12、如何检测死锁?怎么预防死锁?

13、悲观锁和乐观锁的区别,怎么实现

悲观锁:一段执行逻辑加上悲观锁,不同线程同时执行时,只能有一个线程执行,其他的线程在入口处等待,直到锁被释放。

乐观锁:一段执行逻辑加上乐观锁,不同线程同时执行时,可以同时进入执行,在最后更新数据的时候要检查这些数据是否被其他线程修改了(版本和执行初是否相同),没有修改则进行更新,否则放弃本次操作。

悲观锁的实现:

1
2
3
4
5
6
7
8
9
10
//0.开始事务
begin;/begin work;/start transaction; (三者选一就可以)
//1.查询出商品信息
select status from t_goods where id=1 for update;
//2.根据商品信息生成订单
insert into t_orders (id,goods_id) values (null,1);
//3.修改商品status为2
update t_goods set status=2;
//4.提交事务
commit;/commit work;

乐观锁的实现:

1
2
3
4
5
6
7
1.查询出商品信息
select (status,status,version) from t_goods where id=#{id}
2.根据商品信息生成订单
3.修改商品status为2
update t_goods
set status=2,version=version+1
where id=#{id} and version=#{version};

 

 

 

JVM

1、

Java内存模型:
Java虚拟机规范中将Java运行时数据分为六种。
1.程序计数器:是一个数据结构,用于保存当前正常执行的程序的内存地址。Java虚拟机的多线程就是通过线程轮流切换并分配处理器时间来实现的,为了线程切换后能恢复到正确的位置,每条线程都需要一个独立的程序计数器,互不影响,该区域为“线程私有”。
2.Java虚拟机栈:线程私有的,与线程生命周期相同,用于存储局部变量表,操作栈,方法返回值。局部变量表放着基本数据类型,还有对象的引用。
3.本地方法栈:跟虚拟机栈很像,不过它是为虚拟机使用到的Native方法服务。
4.Java堆:所有线程共享的一块内存区域,对象实例几乎都在这分配内存。
5.方法区:各个线程共享的区域,储存虚拟机加载的类信息,常量,静态变量,编译后的代码。
6.运行时常量池:代表运行时每个class文件中的常量表。包括几种常量:编译时的数字常量、方法或者域的引用。
友情链接: Java中JVM虚拟机详解

2、

“你能不能谈谈,java GC是在什么时候,对什么东西,做了什么事情?”
在什么时候:
1.新生代有一个Eden区和两个survivor区,首先将对象放入Eden区,如果空间不足就向其中的一个survivor区上放,如果仍然放不下就会引发一次发生在新生代的minor GC,将存活的对象放入另一个survivor区中,然后清空Eden和之前的那个survivor区的内存。在某次GC过程中,如果发现仍然又放不下的对象,就将这些对象放入老年代内存里去。
2.大对象以及长期存活的对象直接进入老年区。
3.当每次执行minor GC的时候应该对要晋升到老年代的对象进行分析,如果这些马上要到老年区的老年对象的大小超过了老年区的剩余大小,那么执行一次Full GC以尽可能地获得老年区的空间。
对什么东西:从GC Roots搜索不到,而且经过一次标记清理之后仍没有复活的对象。
做什么: 新生代:复制清理; 老年代:标记-清除和标记-压缩算法; 永久代:存放Java中的类和加载类的类加载器本身。
GC Roots都有哪些: 1. 虚拟机栈中的引用的对象 2. 方法区中静态属性引用的对象,常量引用的对象 3. 本地方法栈中JNI(即一般说的Native方法)引用的对象。
友情链接:Java GC的那些事(上)
友情链接:Java GC的那些事(下)
友情链接:CMS垃圾收集器介绍

3、

类加载器工作机制:
1.装载:将Java二进制代码导入jvm中,生成Class文件。
2.连接:a)校验:检查载入Class文件数据的正确性 b)准备:给类的静态变量分配存储空间 c)解析:将符号引用转成直接引用
3:初始化:对类的静态变量,静态方法和静态代码块执行初始化工作。
双亲委派模型:类加载器收到类加载请求,首先将请求委派给父类加载器完成 用户自定义加载器->应用程序加载器->扩展类加载器->启动类加载器。
友情链接:深入理解Java虚拟机笔记—双亲委派模型 
友情链接:JVM类加载的那些事
友情链接:JVM(1):Java 类的加载机制

4、

Java的四种引用,强弱软虚,以及用到的场景

a.利用软引用和弱引用解决OOM问题:用一个HashMap来保存图片的路径和相应图片对象关联的软引用之间的映射关系,在内存不足时,JVM会自动回收这些缓存图片对象所占用的空间,从而有效地避免了OOM的问题。

b.通过软可及对象重获方法实现Java对象的高速缓存:比如我们创建了一Employee的类,如果每次需要查询一个雇员的信息。哪怕是几秒中之前刚刚查询过的,都要重新构建一个实例,这是需要消耗很多时间的。我们可以通过软引用和 HashMap 的结合,先是保存引用方面:以软引用的方式对一个Employee对象的实例进行引用并保存该引用到HashMap 上,key 为此雇员的 id,value为这个对象的软引用,另一方面是取出引用,缓存中是否有该Employee实例的软引用,如果有,从软引用中取得。如果没有软引用,或者从软引用中得到的实例是null,重新构建一个实例,并保存对这个新建实例的软引用。

c.强引用:如果一个对象具有强引用,它就不会被垃圾回收器回收。即使当前内存空间不足,JVM也不会回收它,而是抛出 OutOfMemoryError 错误,使程序异常终止。如果想中断强引用和某个对象之间的关联,可以显式地将引用赋值为null,这样一来的话,JVM在合适的时间就会回收该对象。

d.软引用:在使用软引用时,如果内存的空间足够,软引用就能继续被使用,而不会被垃圾回收器回收,只有在内存不足时,软引用才会被垃圾回收器回收。

e.弱引用:具有弱引用的对象拥有的生命周期更短暂。因为当 JVM 进行垃圾回收,一旦发现弱引用对象,无论当前内存空间是否充足,都会将弱引用回收。不过由于垃圾回收器是一个优先级较低的线程,所以并不一定能迅速发现弱引用对象。

f.虚引用:顾名思义,就是形同虚设,如果一个对象仅持有虚引用,那么它相当于没有引用,在任何时候都可能被垃圾回收器回收。

5、

JAVA 中堆和栈的区别,说下java 的内存机制

a.基本数据类型比变量和对象的引用都是在栈分配的

b.堆内存用来存放由new创建的对象和数组

c.类变量(static修饰的变量),程序在一加载的时候就在堆中为类变量分配内存,堆中的内存地址存放在栈中

d.实例变量:当你使用java关键字new的时候,系统在堆中开辟并不一定是连续的空间分配给变量,是根据零散的堆内存地址,通过哈希算法换算为一长串数字以表征这个变量在堆中的”物理位置”,实例变量的生命周期–当实例变量的引用丢失后,将被GC(垃圾回收器)列入可回收“名单”中,但并不是马上就释放堆中内存

e.局部变量: 由声明在某方法,或某代码段里(比如for循环),执行到它的时候在栈中开辟内存,当局部变量一但脱离作用域,内存立即释放

6、

JAVA多态的实现原理

a.抽象的来讲,多态的意思就是同一消息可以根据发送对象的不同而采用多种不同的行为方式。(发送消息就是函数调用)

b.实现的原理是动态绑定,程序调用的方法在运行期才动态绑定,追溯源码可以发现,JVM 通过参数的自动转型来找到合适的办法。

7、JVM的内存结构,JVM的算法;

8、强引用,软引用和弱引用的区别;

9、数组在内存中如何分配;

7、

java中常说的堆和栈,分别是什么数据结构;另外,为什么要分为堆和栈来存储数据。

8、Java虚拟机 
(1)组成以及各部分作用: 
http://blog.csdn.net/zhaojw_420/article/details/70477953 
(2)类加载器——ClassLoader: 
http://blog.csdn.net/zhaojw_420/article/details/53373898 
(3)类加载器的父亲委托机制深度详解: 
http://blog.csdn.net/zhaojw_420/article/details/53284225 
(4)JVM调优: 
http://blog.csdn.net/zhaojw_420/article/details/70527138 
(5)垃圾回收: 
http://blog.csdn.net/zhaojw_420/article/details/70527232

 9、Java内存模型 
http://blog.csdn.net/zhaojw_420/article/details/70477903

10、数组在内存中如何分配

11、详细jvm内存模型

12、讲讲什么情况下回出现内存溢出,内存泄漏?

13、说说Java线程栈

14、JVM 年轻代到年老代的晋升过程的判断条件是什么呢?

15、JVM 出现 fullGC 很频繁,怎么去线上排查问题?

16、类加载为什么要使用双亲委派模式,有没有什么场景是打破了这个模式?

17、类的实例化顺序

18、JVM垃圾回收机制,何时触发MinorGC等操作

19、JVM 中一次完整的 GC 流程(从 ygc 到 fgc)是怎样的

20、各种回收器,各自优缺点,重点CMS、G1

21、各种回收算法

22、OOM错误,stackoverflow错误,permgen space错误

22、 简单描述一下JVM的GC

A:随意发挥……可以参考Java 9中的GC调优基础

这是一个典型的比较有开放性的问题,面试者可以从自己了解的方面入手,如分代、运行时内存结构。如果对垃圾回收器比较了解,那更可以侃侃而谈。

如果被问到了比较有针对性的问题,那就看你面试前的课补的好不好了。

23、Java中有哪些多线程同步的手段

这个问题也可以延伸出很多知识,synchronized的实现原理、synchronized中的锁膨胀、为什么有时候使用volatile可以带来更好的性能、悲观锁&乐观锁的概念、新一代的基于Lock的锁机制,更甚者可能会问到Java的内存模型(JMM)。

24. 你知道哪些或者你们线上使⽤什么GC策略? 它有什么优势,适⽤于什么 场景?

25. JAVA类加载器包括⼏种?它们之间的⽗⼦关系是怎么样的?双亲委派机 制是什么意思?有什么好处?

26. 如何⾃定义⼀个类加载器?你使⽤过哪些或者你在什么场景下需要⼀个⾃ 定义的类加载器吗?

27. 堆内存设置的参数是什么? 5. Perm Space中保存什么数据? 会引起OutOfMemory吗? 6. 做gc时,⼀个对象在内存各个Space中被移动的顺序是什么?

28. 你有没有遇到过OutOfMemory问题?你是怎么来处理这个问题的?处理 过程中有哪些收获?

29. 1.8之后Perm Space有哪些变动? MetaSpace⼤⼩默认是⽆限的么? 还是 你们会通过什么⽅式来指定⼤⼩?

30. Jstack是⼲什么的? Jstat呢? 如果线上程序周期性地出现卡顿,你怀疑可 能是gc导致的,你会怎么来排查这个问题?线程⽇志⼀般你会看其中的什么 部分?

31. StackOverFlow异常有没有遇到过?⼀般你猜测会在什么情况下被触 发?如何指定⼀个线程的堆栈⼤⼩?⼀般你们写多少?

32. JVM的内存结构

根据 JVM 规范,JVM 内存共分为虚拟机栈、堆、方法区、程序计数器、本地方法栈五个部分。

1、Java虚拟机栈:

线程私有;每个方法在执行的时候会创建一个栈帧,存储了局部变量表,操作数栈,动态连接,方法返回地址等;每个方法从调用到执行完毕,对应一个栈帧在虚拟机栈中的入栈和出栈。

2、堆:

线程共享;被所有线程共享的一块内存区域,在虚拟机启动时创建,用于存放对象实例。

3、方法区:

线程共享;被所有线程共享的一块内存区域;用于存储已被虚拟机加载的类信息,常量,静态变量等。

4、程序计数器:

线程私有;是当前线程所执行的字节码的行号指示器,每条线程都要有一个独立的程序计数器,这类内存也称为“线程私有”的内存。

5、本地方法栈:

线程私有;主要为虚拟机使用到的Native方法服务。

 

33. 强引用,软引用和弱引用的区别

强引用:

只有这个引用被释放之后,对象才会被释放掉,只要引用存在,垃圾回收器永远不会回收,这是最常见的New出来的对象。

软引用:

内存溢出之前通过代码回收的引用。软引用主要用户实现类似缓存的功能,在内存足够的情况下直接通过软引用取值,无需从繁忙的真实来源查询数据,提升速度;当内存不足时,自动删除这部分缓存数据,从真正的来源查询这些数据。

弱引用:

第二次垃圾回收时回收的引用,短时间内通过弱引用取对应的数据,可以取到,当执行过第二次垃圾回收时,将返回null。弱引用主要用于监控对象是否已经被垃圾回收器标记为即将回收的垃圾,可以通过弱引用的isEnQueued方法返回对象是否被垃圾回收器标记。

34. 数组在内存中如何分配

1、简单的值类型的数组,每个数组成员是一个引用(指针),引用到栈上的空间(因为值类型变量的内存分配在栈上)

2、引用类型,类类型的数组,每个数组成员仍是一个引用(指针),引用到堆上的空间(因为类的实例的内存分配在堆上)

35、请写一段栈溢出、堆溢出的代码

递归调用可以导致栈溢出
不断创建对象可以导致堆溢出 

代码如下:

复制代码
复制代码
 

public class Test {  
 
   public void testHeap(){  
       for(;;){  
             ArrayList list = new ArrayList (2000);  
         }  
   }  
   int num=1;  
   public void testStack(){  
       num++;  
       this.testStack();  
    }  
     
   public static void main(String[] args){  
       Test  t  = new Test ();  
       t.testHeap();  
       t.testStack();     
   }  
}

 

36、java中常说的堆和栈,分别是什么数据结构;另外,为什么要分为堆和栈来存储数据

栈是一种具有后进先出性质的数据结构,也就是说后存放的先取,先存放的后取。

堆是一种经过排序的树形数据结构,每个结点都有一个值。通常我们所说的堆的数据结构,是指二叉堆。堆的特点是根结点的值最小(或最大),且根结点的两个子树也是一个堆。由于堆的这个特性,常用来实现优先队列,堆的存取是随意的。 

为什么要划分堆和栈

1、从软件设计的角度看,栈代表了处理逻辑,而堆代表了数据。这样分开,使得处理逻辑更为清晰。

2、堆与栈的分离,使得堆中的内容可以被多个栈共享。一方面这种共享提供了一种有效的数据交互方式(如:共享内存),另一方面,堆中的共享常量和缓存可以被所有栈访问,节省了空间。

3、栈因为运行时的需要,比如保存系统运行的上下文,需要进行地址段的划分。由于栈只能向上增长,因此就会限制住栈存储内容的能力。而堆不同,堆中的对象是可以根据需要动态增长的,因此栈和堆的拆分,使得动态增长成为可能,相应栈中只需记录堆中的一个地址即可。

4、体现了Java面向对象这一核心特点(也可以继续说一些自己的理解)

37、.Jvm垃圾收集器与内存分配策略:http://www.importnew.com/23035.html
38、.Jvm运行和类加载过程:https://www.cnblogs.com/dooor/p/5289994.html
39、.Jvm字节码执行:http://blog.csdn.net/u012077981/article/details/40156391
40、.java内存模型:http://blog.csdn.net/suifeng3051/article/details/52611310;
  http://www.hao124.net/article/49 

 

41、

Java8的内存分代改进

参考:http://blog.csdn.net/chlu113/article/details/51890469

42、

对Java内存模型的理解以及其在并发当中的作用?

参考:http://www.cnblogs.com/_popc/p/6096517.html

43、

Java中堆内存和栈内存区别?

参考:http://www.cnblogs.com/whgw/archive/2011/09/29/2194997.html

44、JVM的内存结构。

45、JVM方法栈的工作过程,方法栈和本地方法栈有什么区别。

46、JVM的栈中引用如何和堆中的对象产生关联。

47、可以了解一下逃逸分析技术。

48、GC的常见算法,CMS以及G1的垃圾回收过程,CMS的各个阶段哪两个是Stop the world的,CMS会不会产生碎片,G1的优势。

49、标记清除和标记整理算法的理解以及优缺点。

50、eden survivor区的比例,为什么是这个比例,eden survivor的工作过程。

51、JVM如何判断一个对象是否该被GC,可以视为root的都有哪几种类型。

52、强软弱虚引用的区别以及GC对他们执行怎样的操作。

53、Java是否可以GC直接内存。

54、Java类加载的过程。

55、双亲委派模型的过程以及优势。

56、常用的JVM调优参数。

57、dump文件的分析。

58、Java有没有主动触发GC的方式(没有)。

59、内存溢出和内存泄漏的区别#
内存溢出是指程序在申请内存时,没有足够的内存空间供其使用,出现out of
memory。
内存泄漏是指分配出去的内存不再使用,但是无法回收。

60、Java内存模型及各个区域的OOM,如何重现OOM#
这部分内容很重要,详细阅读《深入理解Java虚拟机》,也可以详细阅读这篇文章http://hllvm.group.iteye.com/group/wiki/2857-JVM

61、出现OOM如何解决#
一. 可通过命令定期抓取heap dump或者启动参数OOM时自动抓取heap dump文件。
二. 通过对比多个heap dump,以及heap dump的内容,分析代码找出内存占用最多的地方。
三. 分析占用的内存对象,是否是因为错误导致的内存未及时释放,或者数据过多导致的内存溢出。

62、用什么工具可以查出内存泄漏#
一. Memory
Analyzer-是一款开源的JAVA内存分析软件,查找内存泄漏,能容易找到大块内存并验证谁在一直占用它,它是基于Eclipse
RCP(Rich Client Platform),可以下载RCP的独立版本或者Eclipse的插件。
二. JProbe-分析Java的内存泄漏。
三.JProfiler-一个全功能的Java剖析工具,专用于分析J2SE和J2EE应用程序。它把CPU、执行绪和内存的剖析组合在一个强大的应用中,GUI可以找到效能瓶颈、抓出内存泄漏、并解决执行绪的问题。
四. JRockit-用来诊断Java内存泄漏并指出根本原因,专门针对Intel平台并得到优化,能在Intel硬件上获得最高的性能。
五. YourKit-.NET & Java Profiling业界领先的Java和.NET程序性能分析工具。
六.AutomatedQA -AutomatedQA的获奖产品performance profiling和memory debugging工具集的下一代替换产品,支持Microsoft,Borland, Intel, Compaq 和 GNU编译器。可以为.NET和Windows程序生成全面细致的报告,从而帮助您轻松隔离并排除代码中含有的性能问题和内存/资源泄露问题。支持.Net 1.0,1.1,2.0,3.0和Windows 32/64位应用程序。
七.Compuware DevPartner Java Edition-包含Java内存检测,代码覆盖率测试,代码性能测试,线程死锁,分布式应用等几大功能模块

63、Java内存管理及回收算法#
阅读这篇文章:http://www.cnblogs.com/hnrainll/archive/2013/11/06/3410042.html

64、Java类加载器及如何加载类(双亲委派)#
阅读文章:
https://www.ibm.com/developerworks/cn/java/j-lo-classloader/(推荐)
http://blog.csdn.net/zhoudaxia/article/details/35824249

 65、 JVM结构原理、GC工作机制详解

答:具体参照:JVM结构、GC工作机制详解     ,说到GC,记住两点:1、GC是负责回收所有无任何引用对象的内存空间。 注意:垃圾回收回收的是无任何引用的对象占据的内存空间而不是对象本身,2、GC回收机制的两种算法,a、引用计数法  b、可达性分析算法(  这里的可达性,大家可以看基础2 Java对象的什么周期),至于更详细的GC算法介绍,大家可以参考:Java GC机制算法

66、谈谈你对JVM的理解?

答: Java语言的一个非常重要的特点就是与平台的无关性。而使用Java虚拟机是实现这一特点的关键。Java编译器只要面向JVM,生成JVM能理解的代码或字节码文件。Java源文件经编译成字节码程序,通过JVM将每一条指令翻译成不同平台机器码,通过特定平台运行。

JVM执行程序的过程 :I.加载。class文件   ,II.管理并分配内存  ,III.执行垃圾收集

JRE(java运行时环境)由JVM构造的java程序的运行环境 

 

具体详情:JVM原理和调优

 

既然是 Java 开发面试,那么对 JVM 的考察当然也是必须的,面试官一般会问你对 JVM 有了解吗?

我通常都会把我所了解的都说一遍,包括:JVM 内存划分、JVM 垃圾回收的含义,有哪些 GC 算法,年轻代和老年代各自的特点统统阐述一遍。

67、JVM 内存划分:

  1. 方法区(线程共享):常量、静态变量、JIT(即时编译器) 编译后的代码也都在方法区;
  2. 堆内存(线程共享):垃圾回收的主要场所;
  3. 程序计数器: 当前线程执行的字节码的位置指示器;
  4. 虚拟机栈(栈内存):保存局部变量、基本数据类型变量以及堆内存中某个对象的引用变量;
  5. 本地方法栈 :为 JVM 提供使用 native 方法的服务。

68、类似-Xms、-Xmn 这些参数的含义:

答:

堆内存分配:

  1. JVM 初始分配的内存由-Xms 指定,默认是物理内存的 1/64;
  2. JVM 最大分配的内存由-Xmx 指定,默认是物理内存的 1/4;
  3. 默认空余堆内存小于 40% 时,JVM 就会增大堆直到-Xmx 的最大限制;空余堆内存大于 70% 时,JVM 会减少堆直到 -Xms 的最小限制;
  4. 因此服务器一般设置-Xms、-Xmx 相等以避免在每次 GC 后调整堆的大小。对象的堆内存由称为垃圾回收器的自动内存管理系统回收。

非堆内存分配:

  1. JVM 使用-XX:PermSize 设置非堆内存初始值,默认是物理内存的 1/64;
  2. 由 XX:MaxPermSize 设置最大非堆内存的大小,默认是物理内存的 1/4;
  3. -Xmn2G:设置年轻代大小为 2G;
  4. -XX:SurvivorRatio,设置年轻代中 Eden 区与 Survivor 区的比值。

69、垃圾回收算法有哪些?

答:

  1. 引用计数 :原理是此对象有一个引用,即增加一个计数,删除一个引用则减少一个计数。垃圾回收时,只用收集计数为 0 的对象。此算法最致命的是无法处理循环引用的问题;
  2. 标记-清除 :此算法执行分两阶段。第一阶段从引用根节点开始标记所有被引用的对象,第二阶段遍历整个堆,把未标记的对象清除;

此算法需要暂停整个应用,同时,会产生内存碎片;

  1. 复制算法 :此算法把内存空间划为两个相等的区域,每次只使用其中一个区域。垃圾回收时,遍历当前使用区域,把正在使用中的对象复制到另外一个区域中;

此算法每次只处理正在使用中的对象,因此复制成本比较小,同时复制过去以后还能进行相应的内存整理,不会出现 “碎片” 问题。当然,此算法的缺点也是很明显的,就是需要两倍内存空间;

  1. 标记-整理 :此算法结合了 “标记-清除” 和 “复制” 两个算法的优点。也是分两阶段,第一阶段从根节点开始标记所有被引用对象,第二阶段遍历整个堆,把清除未标记对象并且把存活对象 “压缩” 到堆的其中一块,按顺序排放。

此算法避免了 “标记-清除” 的碎片问题,同时也避免了 “复制” 算法的空间问题。

70、root 搜索算法中,哪些可以作为 root?

答:

  • 被启动类(bootstrap 加载器)加载的类和创建的对象;
  • JavaStack 中的引用的对象 (栈内存中引用的对象);
  • 方法区中静态引用指向的对象;
  • 方法区中常量引用指向的对象;
  • Native 方法中 JNI 引用的对象。

71、GC 什么时候开始?

答:GC 经常发生的区域是堆区,堆区还可以细分为新生代、老年代,新生代还分为一个 Eden 区和两个 Survivor 区。

  1. 对象优先在 Eden 中分配,当 Eden 中没有足够空间时,虚拟机将发生一次 Minor GC,因为 Java 大多数对象都是朝生夕灭,所以 Minor GC 非常频繁,而且速度也很快;
  2. Full GC,发生在老年代的 GC,当老年代没有足够的空间时即发生 Full GC,发生 Full GC 一般都会有一次 Minor GC。

大对象直接进入老年代,如很长的字符串数组,虚拟机提供一个;XX:PretenureSizeThreadhold 参数,令大于这个参数值的对象直接在老年代中分配,避免在 Eden 区和两个 Survivor 区发生大量的内存拷贝;

  1. 发生 Minor GC 时,虚拟机会检测之前每次晋升到老年代的平均大小是否大于老年代的剩余空间大小,如果大于,则进行一次 Full GC,如果小于,则查看 HandlePromotionFailure 设置是否允许担保失败,如果允许,那只会进行一次 Minor GC,如果不允许,则改为进行一次 Full GC。

72、内存泄漏和内存溢出

答:

概念:

  1. 内存溢出指的是内存不够用了;
  2. 内存泄漏是指对象可达,但是没用了。即本该被 GC 回收的对象并没有被回收;
  3. 内存泄露是导致内存溢出的原因之一;内存泄露积累起来将导致内存溢出。

内存泄漏的原因分析:

  1. 长生命周期的对象引用短生命周期的对象;
  2. 没有将无用对象置为 null。
小结:本小节涉及到 JVM 虚拟机,包括对内存的管理等知识,相对较深。除了以上问题,面试官会继续问你一些比较深的问题,可能也是为了看看你的极限在哪里吧。
比如:内存调优、内存管理,是否遇到过内存泄漏的实际案例、是否真正关心过内存等。由于本人实际项目经验不足,这些深层次问题并没有接触过,各位有需要可以上网查阅。

 

 

IO/NIO

1、bio,nio,aio的区别;

2、nio框架:dubbo的实现原理;

3、京东内部的jsf是使用的什么协议通讯:可参见dubbo的协议;

4、http://blog.csdn.net/zhaojw_420/article/details/70524353

5、http://blog.csdn.net/zhaojw_420/article/details/70526695

6、BIO、NIO和AIO的区别

Java BIO : 同步并阻塞,服务器实现模式为一个连接一个线程,即客户端有连接请求时服务器端就需要启动一个线程进行处理,如果这个连接不做任何事情会造成不必要的线程开销,当然可以通过线程池机制改善。

Java NIO : 同步非阻塞,服务器实现模式为一个请求一个线程,即客户端发送的连接请求都会注册到多路复用器上,多路复用器轮询到连接有I/O请求时才启动一个线程进行处理。

Java AIO: 异步非阻塞,服务器实现模式为一个有效请求一个线程,客户端的I/O请求都是由OS先完成了再通知服务器应用去启动线程进行处理。

NIO比BIO的改善之处是把一些无效的连接挡在了启动线程之前,减少了这部分资源的浪费(因为我们都知道每创建一个线程,就要为这个线程分配一定的内存空间)

AIO比NIO的进一步改善之处是将一些暂时可能无效的请求挡在了启动线程之前,比如在NIO的处理方式中,当一个请求来的话,开启线程进行处理,但这个请求所需要的资源还没有就绪,此时必须等待后端的应用资源,这时线程就被阻塞了。

适用场景分析:

 BIO方式适用于连接数目比较小且固定的架构,这种方式对服务器资源要求比较高,并发局限于应用中,JDK1.4以前的唯一选择,但程序直观简单易理解,如之前在Apache中使用。

 NIO方式适用于连接数目多且连接比较短(轻操作)的架构,比如聊天服务器,并发局限于应用中,编程比较复杂,JDK1.4开始支持,如在 Nginx,Netty中使用。

 AIO方式使用于连接数目多且连接比较长(重操作)的架构,比如相册服务器,充分调用OS参与并发操作,编程比较复杂,JDK7开始支持,在成长中,Netty曾经使用过,后来放弃。

 7、NIO、BIO与AIO:http://blog.51cto.com/stevex/1284437

8、

Java NIO和IO的区别?

参考:http://www.jb51.net/article/50621.htm

9、.Java中的NIO,BIO,AIO分别是什么#
BIO:同步并阻塞,服务器实现模式为一个连接一个线程,即客户端有连接请求时服务器端就需要启动一个线程进行处理,如果这个连接不做任何事情会造成不必要的线程开销,当然可以通过线程池机制改善。BIO方式适用于连接数目比较小且固定的架构,这种方式对服务器资源要求比较高,并发局限于应用中,JDK1.4以前的唯一选择,但程序直观简单易理解。
NIO:同步非阻塞,服务器实现模式为一个请求一个线程,即客户端发送的连接请求都会注册到多路复用器上,多路复用器轮询到连接有I/O请求时才启动一个线程进行处理。NIO方式适用于连接数目多且连接比较短(轻操作)的架构,比如聊天服务器,并发局限于应用中,编程比较复杂,JDK1.4开始支持。
AIO:异步非阻塞,服务器实现模式为一个有效请求一个线程,客户端的I/O请求都是由OS先完成了再通知服务器应用去启动线程进行处理.AIO方式使用于连接数目多且连接比较长(重操作)的架构,比如相册服务器,充分调用OS参与并发操作,编程比较复杂,JDK7开始支持。

10、IO和NIO区别#
一.IO是面向流的,NIO是面向缓冲区的。
二.IO的各种流是阻塞的,NIO是非阻塞模式。
三.Java NIO的选择器允许一个单独的线程来监视多个输入通道,你可以注册多个通道使用一个选择器,然后使用一个单独的线程来“选择”通道:这些通道里已经有可以处理的输入,或者选择已准备写入的通道。这种选择机制,使得一个单独的线程很容易来管理多个通道。

11、Java中的NIO,BIO,AIO分别是什么#
BIO:同步并阻塞,服务器实现模式为一个连接一个线程,即客户端有连接请求时服务器端就需要启动一个线程进行处理,如果这个连接不做任何事情会造成不必要的线程开销,当然可以通过线程池机制改善。BIO方式适用于连接数目比较小且固定的架构,这种方式对服务器资源要求比较高,并发局限于应用中,JDK1.4以前的唯一选择,但程序直观简单易理解。
NIO:同步非阻塞,服务器实现模式为一个请求一个线程,即客户端发送的连接请求都会注册到多路复用器上,多路复用器轮询到连接有I/O请求时才启动一个线程进行处理。NIO方式适用于连接数目多且连接比较短(轻操作)的架构,比如聊天服务器,并发局限于应用中,编程比较复杂,JDK1.4开始支持。
AIO:异步非阻塞,服务器实现模式为一个有效请求一个线程,客户端的I/O请求都是由OS先完成了再通知服务器应用去启动线程进行处理.AIO方式使用于连接数目多且连接比较长(重操作)的架构,比如相册服务器,充分调用OS参与并发操作,编程比较复杂,JDK7开始支持。

12、IO和NIO区别#
一.IO是面向流的,NIO是面向缓冲区的。
二.IO的各种流是阻塞的,NIO是非阻塞模式。
三.Java NIO的选择器允许一个单独的线程来监视多个输入通道,你可以注册多个通道使用一个选择器,然后使用一个单独的线程来“选择”通道:这些通道里已经有可以处理的输入,或者选择已准备写入的通道。这种选择机制,使得一个单独的线程很容易来管理多个通道。

13、Java?IO与NIO
NIO是为了弥补IO操作的不足而诞生的,NIO的一些新特性有:非阻塞I/O,选择器,缓冲以及管道。管道(Channel),缓冲(Buffer) ,选择器( Selector)是其主要特征。

概念解释

Channel——管道实际上就像传统IO中的流,到任何目的地(或来自任何地方)的所有数据都必须通过一个 Channel 对象。一个 Buffer 实质上是一个容器对象。

每一种基本 Java 类型都有一种缓冲区类型:

ByteBuffer——byte
CharBuffer——char
ShortBuffer——short
IntBuffer——int
LongBuffer——long
FloatBuffer——float
DoubleBuffer——double
Selector——选择器用于监听多个管道的事件,使用传统的阻塞IO时我们可以方便的知道什么时候可以进行读写,而使用非阻塞通道,我们需要一些方法来知道什么时候通道准备好了,选择器正是为这个需要而诞生的。

NIO和传统的IO有什么区别呢?

IO是面向流的,NIO是面向块(缓冲区)的。

IO面向流的操作一次一个字节地处理数据。一个输入流产生一个字节的数据,一个输出流消费一个字节的数据。,导致了数据的读取和写入效率不佳。

NIO面向块的操作在一步中产生或者消费一个数据块。按块处理数据比按(流式的)字节处理数据要快得多,同时数据读取到一个它稍后处理的缓冲区,需要时可在缓冲区中前后移动。这就增加了处理过程中的灵活性。通俗来说,NIO采取了“预读”的方式,当你读取某一部分数据时,他就会猜测你下一步可能会读取的数据而预先缓冲下来。

IO是阻塞的,NIO是非阻塞的

对于传统的IO,当一个线程调用read() 或 write()时,该线程被阻塞,直到有一些数据被读取,或数据完全写入。该线程在此期间不能再干任何事情了。

而对于NIO,使用一个线程发送读取数据请求,没有得到响应之前,线程是空闲的,此时线程可以去执行别的任务,而不是像IO中那样只能等待响应完成。

NIO和IO适用场景

NIO是为弥补传统IO的不足而诞生的,但是尺有所短寸有所长,NIO也有缺点,因为NIO是面向缓冲区的操作,每一次的数据处理都是对缓冲区进行的,那么就会有一个问题,在数据处理之前必须要判断缓冲区的数据是否完整或者已经读取完毕,如果没有,假设数据只读取了一部分,那么对不完整的数据处理没有任何意义。所以每次数据处理之前都要检测缓冲区数据。

那么NIO和IO各适用的场景是什么呢?

如果需要管理同时打开的成千上万个连接,这些连接每次只是发送少量的数据,例如聊天服务器,这时候用NIO处理数据可能是个很好的选择。

而如果只有少量的连接,而这些连接每次要发送大量的数据,这时候传统的IO更合适。使用哪种处理数据,需要在数据的响应等待时间和检查缓冲区数据的时间上作比较来权衡选择。

通俗解释,最后,对于NIO和传统IO

有一个网友讲的生动的例子:

以前的流总是堵塞的,一个线程只要对它进行操作,其它操作就会被堵塞,也就相当于水管没有阀门,你伸手接水的时候,不管水到了没有,你就都只能耗在接水(流)上。

nio的Channel的加入,相当于增加了水龙头(有阀门),虽然一个时刻也只能接一个水管的水,但依赖轮换策略,在水量不大的时候,各个水管里流出来的水,都可以得到妥

善接纳,这个关键之处就是增加了一个接水工,也就是Selector,他负责协调,也就是看哪根水管有水了的话,在当前水管的水接到一定程度的时候,就切换一下:临时关上当

前水龙头,试着打开另一个水龙头(看看有没有水)。

当其他人需要用水的时候,不是直接去接水,而是事前提了一个水桶给接水工,这个水桶就是Buffer。也就是,其他人虽然也可能要等,但不会在现场等,而是回家等,可以做

其它事去,水接满了,接水工会通知他们。

这其实也是非常接近当前社会分工细化的现实,也是统分利用现有资源达到并发效果的一种很经济的手段,而不是动不动就来个并行处理,虽然那样是最简单的,但也是最浪费资源的方式。

14、谈谈你对NIO的理解

答:IO是面向流,NIO是面向缓冲 ,这里不细讲了,具体参照:Java NIO和IO的区别

 

 

 

算法

 1、TreeMap如何插入数据:二叉树的左旋,右旋,双旋;

2、个排序之后的数组,插入数据,可以使用什么方法?答:二分法;问:时间复杂度是多少?

3、平衡二叉树的时间复杂度;

4、Hash算法和二叉树算法分别什么时候用;

5、图的广度优先算法和深度优先算法:详见jvm中垃圾回收实现;

6、链表,栈,队列,二叉树: 
http://blog.csdn.net/zhaojw_420/article/details/68485474 

7、八大排序算法: 
8、查找算法

9、.队列:http://blog.csdn.net/javazejian/article/details/53375004
10、.堆栈:http://blog.csdn.net/javazejian/article/details/53362993
11、.链表:http://blog.csdn.net/jianyuerensheng/article/details/51200274
12、.树:[二叉树]http://blog.csdn.net/javazejian/article/details/53727333
 [B树]http://blog.csdn.net/liuquan0071/article/details/50521032
 [哈夫曼树]http://blog.csdn.net/axi295309066/article/details/54019807
13、.(图)广度优先、深度优先:https://segmentfault.com/a/1190000002685939
14、.常见排序算法:https://www.cnblogs.com/qqzy168/archive/2013/08/03/3219201.html
15、.常见查找算法:http://blog.csdn.net/wqc_csdn/article/details/52691019
16、.hash原理:http://blog.csdn.net/tanggao1314/article/details/51457585
17、.hashmap实现:https://www.cnblogs.com/chengxiao/p/6059914.html

 18、B+树

19、快速排序,堆排序,插入排序(其实八大排序算法都应该了解

20、一致性Hash算法,一致性Hash算法的应用

21、.深度优先和广度优先算法#
推荐看书籍复习!可参考文章:
http://blog.163.com/zhoumhan_0351/blog/static/3995422720098342257387/
http://blog.163.com/zhoumhan_0351/blog/static/3995422720098711040303/
http://blog.csdn.net/andyelvis/article/details/1728378
http://driftcloudy.iteye.com/blog/782873

22、排序算法及对应的时间复杂度和空间复杂度#
推荐看书籍复习!可参考文章:
http://www.cnblogs.com/liuling/p/2013-7-24-01.html
http://blog.csdn.net/cyuyanenen/article/details/51514443
http://blog.csdn.net/whuslei/article/details/6442755

23、排序算法编码实现#
参考http://www.cnblogs.com/liuling/p/2013-7-24-01.html

24、.查找算法#
参考http://sanwen8.cn/p/142Wbu5.html

25、.B+树#
参考http://www.cnblogs.com/syxchina/archive/2011/03/02/2197251.html

26、.KMP算法#
推荐阅读数据复习!参考http://www.cnblogs.com/c-cloud/p/3224788.html

27、.hash算法及常用的hash算法#
参考http://www.360doc.com/content/13/0409/14/10384031_277138819.shtml

28、.如何判断一个单链表是否有环#
参考文章:
http://www.jianshu.com/p/0e28d31600dd
http://my.oschina.net/u/2391658/blog/693277?p={{totalPage}}

29、.队列、栈、链表、树、堆、图#
推荐阅读数据复习!

30、谈谈红黑树

答:算法和数据结构一直是我薄弱之处,这方面说自己补吧,成效不大,这里我就推荐一个:红黑树

31、举例说说几个排序,并说明其排序原理

答:这里我就不细说了,大家自己看看 Java实现几种常见的排序算法

 

 

其他

 1、

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

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

友情链接: HTTP与HTTPS的区别
友情链接: HTTPS 为什么更安全,先看这些 
友情链接: HTTP请求报文和HTTP响应报文
友情链接: HTTP 请求方式: GET和POST的比较

2、

Session与Cookie:Cookie可以让服务端跟踪每个客户端的访问,但是每次客户端的访问都必须传回这些Cookie,如果Cookie很多,则无形的增加了客户端与服务端的数据传输量,
而Session则很好地解决了这个问题,同一个客户端每次和服务端交互时,将数据存储通过Session到服务端,不需要每次都传回所有的Cookie值,而是传回一个ID,每个客户端第一次访问服务器生成的唯一的ID,客户端只要传回这个ID就行了,这个ID通常为NAME为JSESSIONID的一个Cookie。这样服务端就可以通过这个ID,来将存储到服务端的KV值取出了。
Session和Cookie的超时问题,Cookie的安全问题

3、

适配器模式:将一个接口适配到另一个接口,Java I/O中InputStreamReader将Reader类适配到InputStream,从而实现了字节流到字符流的准换。
装饰者模式:保持原来的接口,增强原来有的功能。
FileInputStream 实现了InputStream的所有接口,BufferedInputStreams继承自FileInputStream是具体的装饰器实现者,将InputStream读取的内容保存在内存中,而提高读取的性能。

4、

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

Filter有如下几个用处:
Filter可以进行对特定的url请求和相应做预处理和后处理。
在HttpServletRequest到达Servlet之前,拦截客户的HttpServletRequest。
根据需要检查HttpServletRequest,也可以修改HttpServletRequest头和数据。
在HttpServletResponse到达客户端之前,拦截HttpServletResponse。
根据需要检查HttpServletResponse,也可以修改HttpServletResponse头和数据。

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

Filter和Servlet的生命周期:
1.Filter在web服务器启动时初始化
2.如果某个Servlet配置了 1 ,该Servlet也是在Tomcat(Servlet容器)启动时初始化。
3.如果Servlet没有配置1 ,该Servlet不会在Tomcat启动时初始化,而是在请求到来时初始化。
4.每次请求, Request都会被初始化,响应请求后,请求被销毁。
5.Servlet初始化后,将不会随着请求的结束而注销。
6.关闭Tomcat时,Servlet、Filter依次被注销。

5、

Linux常用命令:cd,cp,mv,rm,ps(进程),tar,cat(查看内容),chmod,vim,find,ls

6、

进程间的通信方式

  1. 管道( pipe ):管道是一种半双工的通信方式,数据只能单向流动,而且只能在具有亲缘关系的进程间使用。进程的亲缘关系通常是指父子进程关系。
  2. 有名管道 (named pipe) : 有名管道也是半双工的通信方式,但是它允许无亲缘关系进程间的通信。
  3. 信号量( semophore ) : 信号量是一个计数器,可以用来控制多个进程对共享资源的访问。它常作为一种锁机制,防止某进程正在访问共享资源时,其他进程也访问该资源。因此,主要作为进程间以及同一进程内不同线程之间的同步手段。
  4. 消息队列( message queue ) : 消息队列是由消息的链表,存放在内核中并由消息队列标识符标识。消息队列克服了信号传递信息少、管道只能承载无格式字节流以及缓冲区大小受限等缺点。
  5. 信号 ( sinal ) : 信号是一种比较复杂的通信方式,用于通知接收进程某个事件已经发生。
  6. 共享内存( shared memory ) :共享内存就是映射一段能被其他进程所访问的内存,这段共享内存由一个进程创建,但多个进程都可以访问。共享内存是最快的 IPC 方式,它是针对其他进程间通信方式运行效率低而专门设计的。它往往与其他通信机制,如信号量,配合使用,来实现进程间的同步和通信。
  7. 套接字( socket ) : 套解口也是一种进程间通信机制,与其他通信机制不同的是,它可用于不同机器间的进程通信。

7、

进程与线程的区别和联系
操作系统的进程调度算法
计算机系统的层次存储结构详解

8、

进程和线程的区别:

进程:每个进程都有独立的代码和数据空间(进程上下文),进程间的切换会有较大的开销,一个进程包含1–n个线程。

线程:同一类线程共享代码和数据空间,每个线程有独立的运行栈和程序计数器(PC),线程切换开销小。

线程和进程一样分为五个阶段:创建、就绪、运行、阻塞、终止。

多进程是指操作系统能同时运行多个任务(程序)。

多线程是指在同一程序中有多个顺序流在执行。

在java中要想实现多线程,有三种手段,一种是继续Thread类,另外一种是实现Runable接口,还有就是实现Callable接口。

9、

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

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

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

10、

用过哪些设计模式,手写一个(除单例);

11、

java的多态表现在哪里;

12、接口有什么用;

13、说说http,https协议;

14、tcp/ip协议簇;

15、osi五层网络协议;

16、tcp,udp区别;

17、用过哪些加密算法:对称加密,非对称加密算法;

18、说说tcp三次握手,四次挥手;

19、cookie和session的区别,分布式环境怎么保存用户状态;

20、git,svn区别;

21、请写一段栈溢出、堆溢出的代码;

22、ThreadLocal可以用来共享数据吗;

23、进程通讯的方式:消息队列,共享内存,信号量,socket通讯等;

24、linux常用的命令有哪些;

25、如何获取java进程的pid;

26、如何获取某个进程的网络端口号;

27、如何实时打印日志;

28、如何统计某个字符串行数;

29、TCP的三次握手和四次挥手

30、单例模式,工厂模式,建造者模式,观察者模式,适配器模式,代理模式等等

31、 StringBuilder vs StringBuffer

A:前者是后者不加锁的版本,使用场景BlaBla……

现在还有人问这个问题,只有两种可能:1. 面试官或者候选人的水平比较初级;2. 面试官一下子想不到别的好问的。

32、Java8比Java7添加了什么新的特性

A:Lambda、streams、接口默认方法……

我要是背书背的好早学文科了。

33、 Java自带线程池判断线程池是否已经结束运行的方法叫什么

A:isShutdown和isTerminated。

34、BlockingQueueCountDownLatchSemeaphore的使用场景
35、. java.util.Datejava.sql.Date有什么区别

A:继承关系

不知道这个问题的意义在哪里。

36、. 如果要从LinkedBlockingQueue中取出头部对象,分别哪个方法会返回null、抛错、阻塞

A:take - 阻塞,poll - 返回null,remove - 抛错

37.HDFS的特点?

38.客户端从HDFS中读写数据过程?

39.HDFS的文件目录结构?

40.NameNode的内存结构?

41.NameNode的重启优化?

42.Git的使用?

43.Maven的使用

44. 说说http,https协议

HTTP:

是互联网上应用最为广泛的一种网络协议,是一个客户端和服务器端请求和应答的标准(TCP),用于从WWW服务器传输超文本到本地浏览器的传输协议,它可以使浏览器更加高效,使网络传输减少。

HTTPS:

是以安全为目标的HTTP通道,简单讲是HTTP的安全版,即HTTP下加入SSL层,HTTPS的安全基础是SSL,因此加密的详细内容就需要SSL。

区别:

1、https协议需要到ca申请证书,一般免费证书较少,因而需要一定费用。

2、http是超文本传输协议,信息是明文传输,https则是具有安全性的ssl加密传输协议。

3、http和https使用的是完全不同的连接方式,用的端口也不一样,前者是80,后者是443。

4、http的连接很简单,是无状态的;HTTPS协议是由SSL+HTTP协议构建的可进行加密传输、身份认证的网络协议,比http协议安全。

45. 说说tcp/ip协议族

TCP/IP协议族是一个四层协议系统,自底而上分别是数据链路层、网络层、传输层和应用层。每一层完成不同的功能,且通过若干协议来实现,上层协议使用下层协议提供的服务。

1、数据链路层负责帧数据的传递。

2、网络层责数据怎样传递过去。

3、传输层负责传输数据的控制(准确性、安全性)

4、应用层负责数据的展示和获取。

 

46、tcp五层网络协议

物理层:

为数据端设备提供传送数据的通路,数据通路可以是一个物理媒体,也可以是多个物理媒体连接而成。

 数据链路层:

为网络层提供数据传送服务。

 网络层:

路由选择和中继、激活,终止网络连接、在一条数据链路上复用多条网络连接,多采取分时复用技术 、差错检测与恢复、排序,流量控制、服务选择、网络管理 。

 传输层:

传输层是两台计算机经过网络进行数据通信时,第一个端到端的层次,具有缓冲作用。

 应用层:

应用层向应用程序提供服务

47、TCP与UDP的区别

1、基于连接与无连接

2、TCP要求系统资源较多,UDP较少; 

3、UDP程序结构较简单 

4、流模式(TCP)与数据报模式(UDP); 

5、TCP保证数据正确性,UDP可能丢包 

6、TCP保证数据顺序,UDP不保证 

 

48、cookie和session的区别,分布式环境怎么保存用户状态

1、cookie数据存放在客户的浏览器上,session数据放在服务器上。

2、cookie不是很安全,别人可以分析存放在本地的COOKIE并进行COOKIE欺骗,考虑到安全应当使用session。

3、session会在一定时间内保存在服务器上。当访问增多,会比较占用你服务器的性能,考虑到减轻服务器性能方面,应当使用COOKIE。

4、单个cookie保存的数据不能超过4K,很多浏览器都限制一个站点最多保存20个cookie。

分布式环境下的session(举例两种):

服务器session复制

原理:任何一个服务器上的session发生改变(增删改),该节点会把这个 session的所有内容序列化,然后广播给所有其它节点,不管其他服务器需不需要session,以此来保证Session同步。

优点:可容错,各个服务器间session能够实时响应。

缺点:会对网络负荷造成一定压力,如果session量大的话可能会造成网络堵塞,拖慢服务器性能。 

session共享机制

使用分布式缓存方案比如memcached、redis,但是要求Memcached或Redis必须是集群。

 

49、TCP长连接和短连接:https://www.cnblogs.com/onlysun/p/4520553.html
50、.TCP与UDP区别:http://blog.csdn.net/li_ning_/article/details/52117463
51、.TCP三次握手四次挥手过程:https://www.cnblogs.com/Andya/p/7272462.html
52、.http几个重要概念:http://blog.csdn.net/drixe/article/details/1893558
53、.http的报文结构:http://blog.csdn.net/zhangliang_571/article/details/23508953
54、.GET/POST以及幂等性:http://blog.csdn.net/dongzhiquan/article/details/6113966
55、.http request的几种类型:https://www.cnblogs.com/liangxiaofeng/p/5798607.html
56、.http几个版本之间的区别:http://blog.csdn.net/zocojoker/article/details/53868639 

57、Cookie和Session的区别?

参考:http://blog.csdn.net/axin66ok/article/details/6175522

58、

手写单例模式(线程安全)

参考:http://www.cnblogs.com/hupp/p/4487521.html

59、

Servlet 工作原理?

参考:http://www.ibm.com/developerworks/cn/java/j-lo-servlet/

60、java中四种修饰符的限制范围。

61、Object类中的方法。

62、接口和抽象类的区别,注意JDK8的接口可以有实现。

63、动态代理的两种方式,以及区别。

64、Java序列化的方式。

65、传值和传引用的区别,Java是怎么样的,有没有传值引用。

66、一个ArrayList在循环过程中删除,会不会出问题,为什么。

67、TCP,UDP区别。

68、三次握手,四次挥手,为什么要四次挥手。
69、长连接和短连接。
70、连接池适合长连接还是短连接。

 71、.OSI七层模型以及TCP/IP四层模型#

参考文章:
http://blog.csdn.net/sprintfwater/article/details/8751453
http://www.cnblogs.com/commanderzhu/p/4821555.html
http://blog.csdn.net/superjunjin/article/details/7841099

72、.HTTP和HTTPS区别#
参考:
http://blog.csdn.net/mingli198611/article/details/8055261
http://www.mahaixiang.cn/internet/1233.html

73、.HTTP报文内容#
参考文章:
https://yq.aliyun.com/articles/44675
http://www.cnblogs.com/klguang/p/4618526.html
http://my.oschina.net/orgsky/blog/387759

74、.get提交和post提交的区别#
参考文章:
http://www.cnblogs.com/hyddd/archive/2009/03/31/1426026.html
http://www.jellythink.com/archives/806

75、.get提交是否有字节限制,如果有是在哪限制的#
参考http://www.jellythink.com/archives/806

76、.TCP的三次握手和四次挥手#
阅读http://www.jianshu.com/p/f7d1010fa603

77、.TCP和UDP区别#
参考http://www.cnblogs.com/bizhu/archive/2012/05/12/2497493.html

78、.DDos攻击及预防#
79、.session和cookie的区别#
参考http://www.cnblogs.com/shiyangxt/archive/2008/10/07/1305506.html

80、.HTTP请求中Session实现原理#
参考http://blog.csdn.net/zhq426/article/details/2992488

81、.redirect与forward区别#
参考http://www.cnblogs.com/wxgblogs/p/5602849.html

82、try?catch?finally,try里有return,finally还执行么
肯定会执行。finally{}块的代码。 只有在try{}块中包含遇到System.exit(0)。 之类的导致Java虚拟机直接退出的语句才会不执行。

当程序执行try{}遇到return时,程序会先执行return语句,但并不会立即返回——也就是把return语句要做的一切事情都准备好,也就是在将要返回、但并未返回的时候,程序把执行流程转去执行finally块,当finally块执行完成后就直接返回刚才return语句已经准备好的结果。

83、Excption与Error包结构。OOM你遇到过哪些情况,SO F你遇到过哪些情况
Throwable是 Java 语言中所有错误或异常的超类。 Throwable包含两个子类: Error 和 Exception 。它们通常用于指示发生了异常情况。 Throwable包含了其线程创建时线程执行堆栈的快照,它提供了printStackTrace()等接口用于获取堆栈跟踪数据等信息。

Java将可抛出(Throwable)的结构分为三种类型:

被检查的异常(Checked Exception)。 运行时异常(RuntimeException)。 错误(Error)。

运行时异常RuntimeException

定义 : RuntimeException及其子类都被称为运行时异常。 特点 : Java编译器不会检查它 也就是说,当程序中可能出现这类异常时,倘若既"没有通过throws声明抛出它",也"没有用try-catch语句捕获它",还是会编译通过。

例如,除数为零时产生的ArithmeticException异常,数组越界时产生的IndexOutOfBoundsException异常,fail-fail机制产生的ConcurrentModificationException异常等,都属于运行时异常。

堆内存溢出 OutOfMemoryError(OOM)

除了程序计数器外,虚拟机内存的其他几个运行时区域都有发生OutOfMemoryError(OOM)异常的可能。

Java Heap 溢出。 一般的异常信息:java.lang.OutOfMemoryError:Java heap spacess。 java堆用于存储对象实例,我们只要不断的创建对象,并且保证GC Roots到对象之间有可达路径来避免垃圾回收机制清除这些对象,就会在对象数量达到最大堆容量限制后产生内存溢出异常。

堆栈溢出 StackOverflow (SOF)

StackOverflowError 的定义: 当应用程序递归太深而发生堆栈溢出时,抛出该错误。 因为栈一般默认为1-2m,一旦出现死循环或者是大量的递归调用,在不断的压栈过程中,造成栈容量超过1m而导致溢出。

栈溢出的原因:

递归调用。 大量循环或死循环。 全局变量是否过多。 数组、List、map数据过大。

84、Java(OOP)面向对象的三个特征与含义
封装(高内聚低耦合 -->解耦)

封装是指将某事物的属性和行为包装到对象中,这个对象只对外公布需要公开的属性和行为,而这个公布也是可以有选择性的公布给其它对象。在java中能使用private、protected、public三种修饰符或不用(即默认defalut)对外部对象访问该对象的属性和行为进行限制。

java的继承(重用父类的代码)

继承是子对象可以继承父对象的属性和行为,亦即父对象拥有的属性和行为,其子对象也就拥有了这些属性和行为。

java中的多态(父类引用指向子类对象)

多态是指父对象中的同一个行为能在其多个子对象中有不同的表现。

有两种多态的机制:编译时多态、运行时多态。

1、方法的重载:重载是指同一类中有多个同名的方法,但这些方法有着不同的参数。,因此在编译时就可以确定到底调用哪个方法,它是一种编译时多态。 2、方法的重写:子类可以覆盖父类的方法,因此同样的方法会在父类中与子类中有着不同的表现形式。

Override和Overload的含义去区别
重载 Overload方法名相同,参数列表不同(个数、顺序、类型不同)与返回类型无关。 重写 Override 覆盖。 将父类的方法覆盖。 重写方法重写:方法名相同,访问修饰符只能大于被重写的方法访问修饰符,方法签名个数,顺序个数类型相同。

Override(重写)

方法名、参数、返回值相同。
子类方法不能缩小父类方法的访问权限。
子类方法不能抛出比父类方法更多的异常(但子类方法可以不抛出异常)。
存在于父类和子类之间。
方法被定义为final不能被重写。
Overload(重载)

参数类型、个数、顺序至少有一个不相同。
不能重载只有返回值不同的方法名。
存在于父类和子类、同类中。
而重载的规则

1、必须具有不同的参数列表。 2、可以有不同的返回类型,只要参数列表不同就可以了。 3、可以有不同的访问修饰符。 4、可以抛出不同的异常。

重写方法的规则

1、参数列表必须完全与被重写的方法相同,否则不能称其为重写而是重载。 2、返回的类型必须一直与被重写的方法的返回类型相同,否则不能称其为重写而是重载。 3、访问修饰符的限制一定要大于被重写方法的访问修饰符(public>protected>default>private)。 4、重写方法一定不能抛出新的检查异常或者比被重写方法申明更加宽泛的检查型异常。

例如: 父类的一个方法申明了一个检查异常IOException,在重写这个方法是就不能抛出Exception,只能抛出IOException的子类异常,可以抛出非检查异常。

86、Interface与abstract类的区别
Interface 只能有成员常量,只能是方法的声明。 Abstract class可以有成员变量,可以声明普通方法和抽象方法。

interface是接口,所有的方法都是抽象方法,成员变量是默认的public static final 类型。接口不能实例化自己。

abstract class是抽象类,至少包含一个抽象方法的累叫抽象类,抽象类不能被自身实例化,并用abstract关键字来修饰。

87、Static?class?与non?static?class的区别
static class(内部静态类)

1、用static修饰的是内部类,此时这个内部类变为静态内部类;对测试有用。 2、内部静态类不需要有指向外部类的引用。 3、静态类只能访问外部类的静态成员,不能访问外部类的非静态成员。

non static class(非静态内部类)

1、非静态内部类需要持有对外部类的引用。 2、非静态内部类能够访问外部类的静态和非静态成员。 3、一个非静态内部类不能脱离外部类实体被创建。 4、一个非静态内部类可以访问外部类的数据和方法。

88、java多态的实现原理
www.cnblogs.com/startRuning…

89、foreach与正常for循环效率对比
用for循环arrayList 10万次花费时间:5毫秒。 用foreach循环arrayList 10万次花费时间:7毫秒。 用for循环linkList 10万次花费时间:4481毫秒。 用foreach循环linkList 10万次花费时间:5毫秒。

循环ArrayList时,普通for循环比foreach循环花费的时间要少一点。 循环LinkList时,普通for循环比foreach循环花费的时间要多很多。

当我将循环次数提升到一百万次的时候,循环ArrayList,普通for循环还是比foreach要快一点;但是普通for循环在循环LinkList时,程序直接卡死。

ArrayList:ArrayList是采用数组的形式保存对象的,这种方式将对象放在连续的内存块中,所以插入和删除时比较麻烦,查询比较方便。

LinkList:LinkList是将对象放在独立的空间中,而且每个空间中还保存下一个空间的索引,也就是数据结构中的链表结构,插入和删除比较方便,但是查找很麻烦,要从第一个开始遍历。

结论:

需要循环数组结构的数据时,建议使用普通for循环,因为for循环采用下标访问,对于数组结构的数据来说,采用下标访问比较好。

需要循环链表结构的数据时,一定不要使用普通for循环,这种做法很糟糕,数据量大的时候有可能会导致系统崩溃。

90、java反射的作用于原理
什么是Java的反射呢?

Java 反射是可以让我们在运行时,通过一个类的Class对象来获取它获取类的方法、属性、父类、接口等类的内部信息的机制。

这种动态获取信息以及动态调用对象的方法的功能称为JAVA的反射。

反射的作用?

反射就是:在任意一个方法里:

1.如果我知道一个类的名称/或者它的一个实例对象, 我就能把这个类的所有方法和变量的信息找出来(方法名,变量名,方法,修饰符,类型,方法参数等等所有信息)

2.如果我还明确知道这个类里某个变量的名称,我还能得到这个变量当前的值。

3.当然,如果我明确知道这个类里的某个方法名+参数个数类型,我还能通过传递参数来运行那个类里的那个方法。

反射机制主要提供了以下功能:

在运行时判断任意一个对象所属的类。
在运行时构造任意一个类的对象。
在运行时判断任意一个类所具有的成员变量和方法。
在运行时调用任意一个对象的方法。
生成动态代理。
91、反射的原理?

JAVA语言编译之后会生成一个.class文件,反射就是通过字节码文件找到某一个类、类中的方法以及属性等。

反射的实现API有哪些?

反射的实现主要借助以下四个类:

Class:类的对象
Constructor:类的构造方法
Field:类中的属性对象
Method:类中的方法对象
反射的实例

blog.csdn.net/xuefeng_yan…

www.cnblogs.com/zhaoyanjun/…

92、泛型常用特点
List<String>能否转为List<Object>
不可以强转类型的

这个问题涉及到了,范型向上转型 和 范型向下转型问题。 List向上转换至List(等价于List)会丢失String类的身份(String类型的特有接口)。 当需要由List向下转型时,你的程序必须明确的知道将对象转换成何种具体类型,不然这将是不安全的操作。

如果要强转类型,Json 序列化转型

List<String> str = new ArrayList<String>();
List<Object> obj= JSONObject.parseArray(JSONObject.toJSONString(str));
或者遍历,或者克隆,但是取出来就是(Object)了,需要强转,String 因为类型丢了。

93、解析XML的几种方式的原理与特点:DOM、SAX
Android中三种常用解析XML的方式(DOM、SAX、PULL)简介及区别。

http://blog.csdn.net/cangchen/article/details/44034799

xml解析的两种基本方式:DOM和SAX的区别是?

DOM: document object model。
SAX: simple api for xml 。
dom一次性把xml文件全部加载到内存中简历一个结构一摸一样的树, 效率低。 SAX解析器的优点是解析速度快,占用内存少,效率高。

DOM在内存中以树形结构存放,因此检索和更新效率会更高。但是对于特别大的文档,解析和加载整个文档将会很耗资源。

DOM,它是生成一个树,有了树以后你搜索、查找都可以做。 SAX,它是基于流的,就是解析器从头到尾解析一遍xml文件,解析完了以后你不过想再查找重新解析。 sax解析器核心是事件处理机制。例如解析器发现一个标记的开始标记时,将所发现的数据会封装为一个标记开始事件,并把这个报告给事件处理器。

平时工作中,xml解析你是使用什么?

JDOM
DOM4J
95、Java1.7与1.8,1.9,10 新特性
1.5

自动装箱与拆箱
枚举(常用来设计单例模式)
静态导入
可变参数
内省
1.6

Web服务元数据
脚本语言支持
JTable的排序和过滤
更简单,更强大的JAX-WS
轻量级Http Server
嵌入式数据库 Derby
1.7

switch中可以使用字串了
运用List tempList = new ArrayList<>(); 即泛型实例化类型自动推断
语法上支持集合,而不一定是数组
新增一些取环境信息的工具方法
Boolean类型反转,空指针安全,参与位运算
两个char间的equals
安全的加减乘除
map集合支持并发请求,且可以写成 Map map = {name:"xxx",age:18};
1.8

允许在接口中有默认方法实现
Lambda表达式
函数式接口
方法和构造函数引用
Lambda的范围
内置函数式接口
Streams
Parallel Streams
Map
时间日期API
Annotations
1.9

Jigsaw 项目;模块化源码
简化进程API
轻量级 JSON API
钱和货币的API
改善锁争用机制
代码分段缓存
智能Java编译, 第二阶段
HTTP 2.0客户端
Kulla计划: Java的REPL实现
10

本地变量类型推断
统一JDK仓库
垃圾回收器接口
G1的并行Full GC
应用程序类数据共享
ThreadLocal握手机制
设计模式:单例、工厂、适配器、责任链、观察者等等
【示例】设计模式——单例模式、工厂模式、代理模式、观察者模式、装饰器模式

blog.csdn.net/learrrrrrrr…

菜鸟教程-设计模式

www.runoob.com/design-patt…

96、什么是设计模式

设计模式是一种解决方案,用于解决在软件设计中普遍存在的问题,是前辈们对之前软件设计中反复出现的问题的一个总结。

我们学设计模式,是为了学习如何合理的组织我们的代码,如何解耦,如何真正的达到对修改封闭对扩展开放的效果,而不是去背诵那些类的继承模式,然后自己记不住,回过头来就骂设计模式把你的代码搞复杂了,要反设计模式。

设计模式的六大原则

开闭原则:实现热插拔,提高扩展性。
里氏代换原则:实现抽象的规范,实现子父类互相替换;
依赖倒转原则:针对接口编程,实现开闭原则的基础;
接口隔离原则:降低耦合度,接口单独设计,互相隔离;
迪米特法则,又称不知道原则:功能模块尽量独立;
合成复用原则:尽量使用聚合,组合,而不是继承;
1、开闭原则(Open Close Principle)

开闭原则的意思是:对扩展开放,对修改关闭。在程序需要进行拓展的时候,不能去修改原有的代码,实现一个热插拔的效果。简言之,是为了使程序的扩展性好,易于维护和升级。想要达到这样的效果,我们需要使用接口和抽象类,后面的具体设计中我们会提到这点。

2、里氏代换原则(Liskov Substitution Principle)

里氏代换原则是面向对象设计的基本原则之一。 里氏代换原则中说,任何基类可以出现的地方,子类一定可以出现。LSP 是继承复用的基石,只有当派生类可以替换掉基类,且软件单位的功能不受到影响时,基类才能真正被复用,而派生类也能够在基类的基础上增加新的行为。里氏代换原则是对开闭原则的补充。实现开闭原则的关键步骤就是抽象化,而基类与子类的继承关系就是抽象化的具体实现,所以里氏代换原则是对实现抽象化的具体步骤的规范。

3、依赖倒转原则(Dependence Inversion Principle)

这个原则是开闭原则的基础,具体内容:针对接口编程,依赖于抽象而不依赖于具体。

4、接口隔离原则(Interface Segregation Principle)

这个原则的意思是:使用多个隔离的接口,比使用单个接口要好。它还有另外一个意思是:降低类之间的耦合度。由此可见,其实设计模式就是从大型软件架构出发、便于升级和维护的软件设计思想,它强调降低依赖,降低耦合。

5、迪米特法则,又称最少知道原则(Demeter Principle)

最少知道原则是指:一个实体应当尽量少地与其他实体之间发生相互作用,使得系统功能模块相对独立。

6、合成复用原则(Composite Reuse Principle)

合成复用原则是指:尽量使用合成/聚合的方式,而不是使用继承。

97、JNI的使用
www.cnblogs.com/larryzeal/p…

JNI是 Java Native Interface 的缩写,它提供了若干的API实现了Java和其他语言的通信(主要是C&C++)。从Java1.1开始,JNI标准成为java平台的一部分,它允许Java代码和其他语言写的代码进行交互。JNI一开始是为了本地已编译语言,尤其是C和C++而设计的,但是它并不妨碍你使用其他编程语言,只要调用约定受支持就可以了。使用java与本地已编译的代码交互,通常会丧失平台可移植性。

JNI步骤

java类中编写带有native 声明的方法。
使用 javac 命令编译所编写的java类。
使用 javah 命令生成头文件。
使用C/C++实现本地方法。
生成动态连接库。
执行(java)。
JNI实例

public class HelloWorld {
public native void displayHelloWorld();//所有native关键词修饰的都是对本地的声明
static {
System.loadLibrary("hello");//载入本地库
}
public static void main(String[] args) {
new HelloWorld().displayHelloWorld();
}
}

 

98、数据库存储日期格式时,如何考虑时区转换问题?

答:使用TimeStamp ,  原因参照:Java编程中遇到的时区转换问题

99、HTTP协议,GET和POST 的区别

答:浅谈HTTP中GET和POST的区别

100、单例模式有几种? 如何优化?

解答:单例模式的7中用法

101、如何看待设计模式,并简单说说你对观察者模式的理解

答:1、设计模式有神马用     2、观察者模式类图及实现

102、随便说说几个单例模式,并选择一种线程安全的

答:单例的类别:懒汉、饿汉、枚举、静态内部类、双重校验锁 等等 , 选择线程安全我选最后一种,双重校验锁。  具体实现方式参照:Java:单例模式的七种写法

103、序列化的原理和作用

答:Serialization(序列化)是一种将对象以一连串的字节描述的过程;反序列化deserialization是一种将这些字节重建成一个对象的过程,主要用于HTTP或者WebService接口传输过程中对象参数的传播,具体可参看:Java序列化机制和原理

 

网络协议方面,考察最多的包括服务器和客户端在三次握手、四次挥手过程中的状态变化;还有网络拥塞控制,及其解决办法等。

104、三次握手、四次挥手示意图:

总共有四种状态:主动建立连接、主动断开连接、被动建立连和被动断开连接

两两组合还是 4 种组合:

  1. 主动建立连接、主动断开连接会经历的状态:
    SYNC_SENT——ESTABLISHED—-FIN_WAIT_1—-FIN_WAIT_2—-TIME_WAIT
  2. 主动建立连接、被动断开连接会经历的状态:
    SYNC_SENT——ESTABLISHED—-CLOSE_WAIT—-LAST_ACK
  3. 被动建立连接、主动断开连接会经历的状态:
    LISTEN—-SYN_RCVD—-ESTABLISHED—-FIN_WAIT_1—-FIN_WAIT_2—-TIME_WAIT
  4. 被动建立连接、被动断开连接会经历的状态:
    LISTEN—-SYN_RCVD—-ESTABLISHED—-CLOSE_WAIT—-LAST_ACK

105、滑动窗口机制

由发送方和接收方在三次握手阶段,互相将自己的最大可接收的数据量告诉对方。也就是自己的数据接收缓冲池的大小。这样对方可以根据已发送的数据量来计算是否可以接着发送。

在处理过程中,当接收缓冲池的大小发生变化时,要给对方发送更新窗口大小的通知。

106、拥塞避免机制

拥塞:对资源的需求超过了可用的资源。若网络中许多资源同时供应不足,网络的性能就要明显变坏,整个网络的吞吐量随之负荷的增大而下降。

拥塞控制:防止过多的数据注入到网络中,使得网络中的路由器或链路不致过载。

拥塞控制方法:

  • 慢开始 + 拥塞避免;
  • 快重传 + 快恢复。

107、浏览器中输入:“www.xxx.com” 之后都发生了什么?请详细阐述。

解析:经典的网络协议问题。

答:

  1. 由域名→IP 地址
    寻找 IP 地址的过程依次经过了浏览器缓存、系统缓存、hosts 文件、路由器缓存、 递归搜索根域名服务器。
  2. 建立 TCP/IP 连接(三次握手具体过程)
  3. 由浏览器发送一个 HTTP 请求
  4. 经过路由器的转发,通过服务器的防火墙,该 HTTP 请求到达了服务器
  5. 服务器处理该 HTTP 请求,返回一个 HTML 文件
  6. 浏览器解析该 HTML 文件,并且显示在浏览器端
  7. 这里需要注意:
  • HTTP 协议是一种基于 TCP/IP 的应用层协议,进行 HTTP 数据请求必须先建立 TCP/IP 连接
  • 可以这样理解:HTTP 是轿车,提供了封装或者显示数据的具体形式;Socket 是发动机,提供了网络通信的能力。
  • 两个计算机之间的交流无非是两个端口之间的数据通信 , 具体的数据会以什么样的形式展现是以不同的应用层协议来定义的。

108、常见 HTTP 状态码

  1. 1xx(临时响应)
  2. 2xx(成功)
  3. 3xx(重定向):表示要完成请求需要进一步操作
  4. 4xx(错误):表示请求可能出错,妨碍了服务器的处理
  5. 5xx(服务器错误):表示服务器在尝试处理请求时发生内部错误
  6. 常见状态码:
  • 200(成功)
  • 304(未修改):自从上次请求后,请求的网页未修改过。服务器返回此响应时,不会返回网页内容
  • 401(未授权):请求要求身份验证
  • 403(禁止):服务器拒绝请求
  • 404(未找到):服务器找不到请求的网页

109、TCP 和 UDP 的区别:

答:

  1. 回答发送数据前是否存在建立连接的过程;
  2. TCP过确认机制,丢包可以重发,保证数据的正确性;UDP不保证正确性,只是单纯的负责发送数据包;
  3. UDP 是面向报文的。发送方的 UDP 对应用程序交下来的报文,在添加首部后就向下交付给 IP 层。既不拆分,也不合并,而是保留这些报文的边界,因 此,应用程序需要选择合适的报文大小;
  4. UDP 的头部,只有 8 个字节,相对于 TCP 头部的 20 个字节信息包的额外开销很小。

限于篇幅,更多网络协议相关知识,请参阅我的博客:TCP/IP 协议面试常问知识点,倾心总结

小结:必须熟练掌握 TCP 和 UDP 的区别、三次握手和四次挥手的状态切换,必考。

  

 

 

  


 

 

核心篇

数据存储

1、MySQL 索引使用的注意事项

2、说说反模式设计

3、说说分库与分表设计

4、分库与分表带来的分布式困境与应对之策

5、说说 SQL 优化之道

6、MySQL 遇到的死锁问题

7、存储引擎的 InnoDB 与 MyISAM

8、数据库索引的原理

9、为什么要用 B-tree

10、聚集索引与非聚集索引的区别

11、limit 20000 加载很慢怎么解决

12、选择合适的分布式主键方案

13、选择合适的数据存储方案

14、ObjectId 规则

15、聊聊 MongoDB 使用场景

16、倒排索引

17、聊聊 ElasticSearch 使用场景

18、

索引:B+,B-,全文索引
Mysql的索引是一个数据结构,旨在使数据库高效的查找数据。
常用的数据结构是B+Tree,每个叶子节点不但存放了索引键的相关信息还增加了指向相邻叶子节点的指针,这样就形成了带有顺序访问指针的B+Tree,做这个优化的目的是提高不同区间访问的性能。
什么时候使用索引:

  1. 经常出现在group by,order by和distinc关键字后面的字段
  2. 经常与其他表进行连接的表,在连接字段上应该建立索引
  3. 经常出现在Where子句中的字段
  4. 经常出现用作查询选择的字段

友情链接:MySQL:InnoDB存储引擎的B+树索引算法
友情链接:MySQL索引背后的数据结构及算法原理

19、

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

友情链接:数据库事务的四大特性以及事务的隔离级别

20、

MySQL数据库优化总结
MYSQL 优化常用方法
MySQL存储引擎--MyISAM与InnoDB区别
关于SQL数据库中的范式

21、msyql优化经验:

22、mysql的语句优化,使用什么工具;

23、mysql的索引分类:B+,hash;什么情况用什么索引;

24、mysql的存储引擎有哪些,区别是什么;

25、说说事务的特性和隔离级别;

26、mysql面试题: 
http://blog.csdn.net/zhaojw_420/article/details/70530664 
27、sql优化: 
http://blog.csdn.net/zhaojw_420/article/details/70532017 

28、mysql分页有什么优化

29、悲观锁、乐观锁

30、组合索引,最左原则

31、mysql 的表锁、行锁

32、mysql 性能优化

33、mysql的索引分类:B+,hash;什么情况用什么索引

34、事务的特性和隔离级别

35. 如果有很多数据插⼊MYSQL 你会选择什么⽅式?

36. 如果查询很慢,你会想到的第⼀个⽅式是什么?索引是⼲嘛的?

37. 如果建了⼀个单列索引,查询的时候查出2列,会⽤到这个单列索引吗?

38. 如果建了⼀个包含多个列的索引,查询的时候只⽤了第⼀列,能不能⽤上 这个索引?查三列呢?

39. 接上题,如果where条件后⾯带有⼀个 i + 5 < 100 会使⽤到这个索引吗?

40. 怎么看是否⽤到了某个索引?

41. like %aaa%会使⽤索引吗? like aaa%呢?

42. drop、truncate、delete的区别?

43. 平时你们是怎么监控数据库的? 慢SQL是怎么排查的?

44. 你们数据库是否⽀持emoji表情,如果不⽀持,如何操作?

45. 你们的数据库单表数据量是多少?⼀般多⼤的时候开始出现查询性能急 剧下降?

46. 查询死掉了,想要找出执⾏的查询进程⽤什么命令?找出来之后⼀般你 会⼲嘛?

47. 读写分离是怎么做的?你认为中间件会怎么来操作?这样操作跟事务有 什么关系? 14. 分库分表有没有做过?线上的迁移过程是怎么样的?如何确定数据是正 确的?

48. MySQL常用命令

49. 数据库中事物的特征?

50. JDBC的使用?

51. InnodB与MyISAM的区别

52. MySQL为什么使用B+树作为索引?

53、msyql优化经验

1、对查询进行优化,应尽量避免全表扫描,首先应考虑在 where 及 order by 涉及的列上建立索引。 

2、应尽量避免在 where 子句中使用!=或<>操作符,否则引擎将放弃使用索引而进行全表扫描。 

3、尽量使用数字型字段,若只含数值信息的字段尽量不要设计为字符型,这会降低查询和连接的性能,并会增加存储开销。这是因为引擎在处理查询和连接时会逐个比较字符串中每一个字符,而对于数字型而言只需要比较一次就够了。

4、任何地方都不要使用 select * from t ,用具体的字段列表代替“*”,不要返回用不到的任何字段。

5、避免频繁创建和删除临时表,以减少系统表资源的消耗。诸如此类,等等等等......

54、.各个数据库引擎区别:http://www.jb51.net/article/38004.htm
55、.索引的使用注意事项:https://www.cnblogs.com/zlingh/p/3883716.html 

56、

如何预防Mysql注入?

参考:http://www.jb51.net/article/87948.htm

 57、常见的数据库优化手段

58、索引的优缺点,什么字段上建立索引
59、数据库连接池。
60、durid的常用配置。

61、.产生死锁的必要条件#
参考http://blog.sina.com.cn/s/blog_5e3604840100ddgq.html

62、.死锁预防#
参考http://blog.sina.com.cn/s/blog_5e3604840100ddgq.html

63、数据库范式#
参考http://www.360doc.com/content/12/0712/20/5287961_223855037.shtml

64、.数据库事务隔离级别#
参考http://blog.csdn.net/fg2006/article/details/6937413

65、.数据库连接池的原理#
参考http://blog.csdn.net/shuaihj/article/details/14223015

66、.乐观锁和悲观锁#
参考http://www.open-open.com/lib/view/open1452046967245.html

67、.如何实现不同数据库的数据查询分页#
参考http://blog.csdn.net/yztezhl/article/details/20489387

68、.SQL注入的原理,如何预防#
参考https://www.aliyun.com/zixun/content/3_15_245099.html

69、.数据库索引的实现(B+树介绍、和B树、R树区别)#
参考文章:
http://blog.csdn.net/kennyrose/article/details/7532032
http://www.xuebuyuan.com/2216918.html

70、.SQL性能优化#
参考文章:
http://database.51cto.com/art/200904/118526.htm
http://www.cnblogs.com/rootq/archive/2008/11/17/1334727.html

71、.数据库索引的优缺点以及什么时候数据库索引失效#
参考文章:
http://www.cnblogs.com/mxmbk/articles/5226344.html
http://www.cnblogs.com/simplefrog/archive/2012/07/15/2592527.html
http://www.open-open.com/lib/view/open1418476492792.html
http://blog.csdn.net/colin_liu2009/article/details/7301089
http://www.cnblogs.com/hongfei/archive/2012/10/20/2732589.html 

72、当数据表中A、B字段做了组合索引,那么单独使用A或单独使用B会有索引效果吗?(使用like查询如何有索引效果)

答:看A、B两字段做组合索引的时候,谁在前面,谁在后面,如果A在前,那么单独使用A会有索引效果,单独使用B则没有,反之亦然。同理,使用like模糊查询时,如果只是使用前面%,那么有索引效果,如果使用双%号匹配,那么则无索引效果

 73、mysql查询字段区不区分大小写?

解答:不区分,哪怕值也不区分(我当时还反问了,区不区分大小的应用含义有哪些,面试官没说得出来)

74、简单说说数据库集群和负载均衡、分布式(我不懂这块)

解答:数据库负载均衡和集群参考 ,参考2

75、存储过程的结构和优点

解答:大概结构  
存储过程的优缺点

76、触发器的原理和作用

解答:参考

77、一条sql执行过长的时间,你如何优化,从哪些方面?

答:

1、查看sql是否涉及多表的联表或者子查询,如果有,看是否能进行业务拆分,相关字段冗余或者合并成临时表(业务和算法的优化)

2、涉及链表的查询,是否能进行分表查询,单表查询之后的结果进行字段整合

3、如果以上两种都不能操作,非要链表查询,那么考虑对相对应的查询条件做索引。加快查询速度

4、针对数量大的表进行历史表分离(如交易流水表)

5、数据库主从分离,读写分离,降低读写针对同一表同时的压力,至于主从同步,mysql有自带的binlog实现 主从同步

6、explain分析sql语句,查看执行计划,分析索引是否用上,分析扫描行数等等

7、查看mysql执行日志,看看是否有其他方面的问题

个人理解:从根本上来说,查询慢是占用mysql内存比较多,那么可以从这方面去酌手考虑

78、Mysql的事物隔离级别?

答:Mysql的事物隔离级别 其实跟 Spring的事物隔离级别一样,都是1、Read Uncommitted(读取未提交内容), 2、Read Committed(读取提交内容),3、Repeatable Read(可重读),4、Serializable(可串行化)    具体参照:mysql事物隔离级别

79、Mysql索引的原理

答:索引的作用大家都知道,就是加快查询速度,但是原理,我说不上来,这里直接看吧:Mysql索引工作原理

1、假设商户表A(id , city )  ,交易流水表B (aid, amount , time)   这里的time代表交易时间,  请用sql写出查询每个城市每个月的销售业绩(答案可在评论里回复)

2、假设有一个数组 A ,int[] A = { 1 , 3 , -1 ,0 , 2 , 1 , -4 , 2 , 0 ,1 ...  N};   原来是需要查出大于0的数组,但是由于传参错误或者其他原因,导致查出0和负数了,现在要求在不使用新数组和新集合的情况下(即只使用这个A数组,因数组数据比较大,且只能用一次循环) 实现正数放到数组的前面,小于等于0的数放到数组的末尾(答案可在评论里回复)

 

80、MySQL 和 MongoDB 的区别有哪些?如何选择?

81、MongoDB 的优缺点有哪些?

(ps 本人对这一块不是很熟悉,就不附上参考答案了,请各位小伙伴自行学习哈~)

82、听说过事务吗?(必考)

答:作为单个逻辑工作单元执行的一系列操作,满足四大特性:

  1. 原子性(Atomicity):事务作为一个整体被执行 ,要么全部执行,要么全部不执行;
  2. 一致性(Consistency):保证数据库状态从一个一致状态转变为另一个一致状态;
  3. 隔离性(Isolation):多个事务并发执行时,一个事务的执行不应影响其他事务的执行;
  4. 持久性(Durability):一个事务一旦提交,对数据库的修改应该永久保存。

83、事务的并发问题有哪几种?

答:丢失更新、脏读、不可重复读以及幻读。

84、数据库中的锁有哪几种?
答:独占锁、排他锁以及更新锁。

85、事务的隔离级别有哪几种?

答:读未提交、读已提交、可重复读和序列化。

扩展问题:MySQL 事务默认隔离级别是哪个?

答:可重复读。

解析:关于问题(4)(5)(6)的详细解答,请参阅我的博客:数据库并发机制和事务的隔离级别详解

(ps,关于数据库事务方面的深层次考察还有分布式事务即两段提交和三段提交等,限于本人水平,请各位自行学习)

86、数据库的索引有什么作用?(必考) 底层数据结构是什么,为什么使用这种数据结构?

答:

  1. 索引 是对数据库表中一列或多列的值进行排序的一种结构,使用索引可快速访问数据库表中的特定信息;
  2. 底层数据结构是 B+ 树;
  3. 使用 B+ 树的原因:查找速度快、效率高,在查找的过程中,每次都能抛弃掉一部分节点,减少遍历个数。( 此时,你应该在白纸上画出什么是 B+ 树 )

扩展问题:聚簇索引和非聚簇索引的区别?

87、MyISAM 和 InnoDB 的区别有哪些?

答:

  • MyISAM 不支持事务,InnoDB 是事务类型的存储引擎;
  • MyISAM 只支持表级锁,BDB 支持页级锁和表级锁,默认为页级锁;而 InnoDB 支持行级锁和表级锁,默认为行级锁;
  • MyISAM 引擎不支持外键,InnoDB 支持外键;
  • MyISAM 引擎的表在大量高并发的读写下会经常出现表损坏的情况;
  • 对于 count( ) 查询来说 MyISAM 更有优势;
  • InnoDB 是为处理巨大数据量时的最大性能设计,它的 CPU 效率可能是任何其它基于磁盘的关系数据库引擎所不能匹敌的;
  • MyISAM 支持全文索引(FULLTEXT),InnoDB 不支持;
  • MyISAM 引擎的表的查询、更新、插入的效率要比 InnoDB 高。
最主要的区别是:MyISAM 表不支持事务、不支持行级锁、不支持外键。 InnoDB 表支持事务、支持行级锁、支持外键。(可直接回答这个)

88、数据库中 Where、group by、having 关键字:

答: 关键字作用:

  1. where 子句用来筛选 from 子句中指定的操作所产生的的行;
  2. group by 子句用来分组 where 子句的输出;
  3. having 子句用来从分组的结果中筛选行;

having 和 where 的区别:

  1. 语法类似,where 搜索条件在进行分组操作之前应用;having 搜索条件在进行分组操作之后应用;
  2. having 可以包含聚合函数 sum、avg、max 等;
  3. having 子句限制的是组,而不是行。

当同时含有 where 子句、group by 子句 、having 子句及聚集函数时,执行顺序如下:

  1. 执行 where 子句查找符合条件的数据;
  2. 使用 group by 子句对数据进行分组;对 group by 子句形成的组运行聚集函数计算每一组的值;最后用 having 子句去掉不符合条件的组。

89、还有一些问题,如 MySQL 和 SQL Server 用法上的区别、limit 关键字的使用等问题。

小结:数据库方面还是事务机制、隔离级别比较重要,当然了数据库索引是必考的问题。偶尔也会给你几个表,让你现场写 SQL 语句,主要考察 group by 和 having 等关键字。

 

 

 


 

缓存使用

1、Redis 有哪些类型

2、Redis 内部结构

3、聊聊 Redis 使用场景

4、Redis 持久化机制

5、Redis 如何实现持久化

6、Redis 集群方案与实现

7、Redis 为什么是单线程的

8、缓存奔溃

9、缓存降级

10、使用缓存的合理性问题

11、

Redis数据结构: String—字符串(key-value 类型)
Hash—字典(hashmap) Redis的哈希结构可以使你像在数据库中更新一个属性一样只修改某一项属性值
List—列表 实现消息队列
Set—集合 利用唯一性
Sorted Set—有序集合 可以进行排序 可以实现数据持久化
友情链接: Spring + Redis 实现数据的缓存

12、redis和memcache的区别;

13、用redis做过什么;

14、redis是如何持久化的:rdb和aof;

15、redis集群如何同步;

16、redis的数据添加过程是怎样的:哈希槽;

17、redis的淘汰策略有哪些;

19、redis有哪些数据结构;

20、Redis用过哪些数据数据,以及Redis底层怎么实现

21、Redis缓存穿透,缓存雪崩

22、如何使用Redis来实现分布式锁

23、Redis的并发竞争问题如何解决

24、Redis持久化的几种方式,优缺点是什么,怎么实现的

25、Redis的缓存失效策略

26、Redis集群,高可用,原理

27、Redis缓存分片

28、Redis的数据淘汰策略

29.Redis与Memorycache的区别?

30.Redis的五种数据结构?

31.渐进式rehash过程?

32.rehash源码?

33.持久化机制

34.reaof源码?

35.事务与事件

36.主从复制

37.启动过程

38.集群

39.Redis的6种数据淘汰策略

40.redis的并发竞争问题?

41、redis五大数据类型:http://www.runoob.com/redis/redis-data-types.html
42、redis的两个持久化策略:http://blog.csdn.net/u010785685/article/details/52366977
43、.redis如何事务支持:https://www.cnblogs.com/kyrin/p/5967620.html
44、.redis哨兵机制:http://blog.csdn.net/zbw18297786698/article/details/52891695
45、.redis集群方案:https://www.zhihu.com/question/21419897
46、.redis主从同步策略:http://blog.csdn.net/sk199048/article/details/50725369

44、redis和memcached的区别。
45、redis支持哪些数据结构。
46、redis是单线程的么,所有的工作都是单线程么。

47、redis如何存储一个String的。
48、redis的部署方式,主从,集群。
49、redis的哨兵模式,一个key值如何在redis集群中找到存储在哪里。
50、redis持久化策略。

51、项目中为何要用缓存?如何理解nginx + tomcat + redis 集群缓存?

答1:最直接的表现就是减轻数据库的压力。避免因为数据读取频繁或过大而影响数据库性能,降低程序宕机的可能性

答2:nginx常用做静态内容服务和代理服务器,直面外来请求转发给后面的应用服务。nginx本身也能做缓存,比如静态页面的缓存什么的。而tomcat是应用服务器,处理JAVA WEB程序功能等等 。你也可以这么理解,假设把用户的请求当做是一条河流,那么nginx就相当于一个水利工程,tomcat相当于一条条分流的支流,而redis 相当于支流旁边的一个个水库。 当你洪水来了,nginx根据你每条支流的承受力度分发不同的水流量,在确保程序正常运行的情况下,分发给每条支流(tomcat)不同的水流量。而redis相当于一个个支流的水库,存储水源,降低压力,让后面的水量平稳。

 

 

 

消息队列

1、消息队列的使用场景

2、消息的重发补偿解决思路

3、消息的幂等性解决思路

4、消息的堆积解决思路

5、自己如何实现消息队列

6、如何保证消息的有序性

7、mq的原理是什么:有点大。。都可以说;

8、mq如何保证实时性;

9、mq的持久化是怎么做的;

 

 

框架篇

Spring

1、BeanFactory 和 ApplicationContext 有什么区别

2、Spring Bean 的生命周期

3、Spring IOC 如何实现

4、说说 Spring AOP

5、Spring AOP 实现原理

6、动态代理(cglib 与 JDK)

7、Spring 事务实现方式

8、Spring 事务底层原理

9、如何自定义注解实现功能

10、Spring MVC 运行流程

11、Spring MVC 启动流程

12、Spring 的单例实现原理

13、Spring 框架中用到了哪些设计模式

14、Spring 其他产品(Srping Boot、Spring Cloud、Spring Secuirity、Spring Data、Spring AMQP 等)

15、

Spring IOC (控制反转,依赖注入)
Spring支持三种依赖注入方式,分别是属性(Setter方法)注入,构造注入和接口注入。
在Spring中,那些组成应用的主体及由Spring IOC容器所管理的对象被称之为Bean。
Spring的IOC容器通过反射的机制实例化Bean并建立Bean之间的依赖关系。
简单地讲,Bean就是由Spring IOC容器初始化、装配及被管理的对象。
获取Bean对象的过程,首先通过Resource加载配置文件并启动IOC容器,然后通过getBean方法获取bean对象,就可以调用他的方法。
Spring Bean的作用域:
Singleton:Spring IOC容器中只有一个共享的Bean实例,一般都是Singleton作用域。
Prototype:每一个请求,会产生一个新的Bean实例。
Request:每一次http请求会产生一个新的Bean实例。
友情链接: Spring框架IOC容器和AOP解析
友情链接:浅谈Spring框架注解的用法分析
友情链接:关于Spring的69个面试问答——终极列表

16、

代理的共有优点:业务类只需要关注业务逻辑本身,保证了业务类的重用性。
Java静态代理:
代理对象和目标对象实现了相同的接口,目标对象作为代理对象的一个属性,具体接口实现中,代理对象可以在调用目标对象相应方法前后加上其他业务处理逻辑。
缺点:一个代理类只能代理一个业务类。如果业务类增加方法时,相应的代理类也要增加方法。
Java动态代理:
Java动态代理是写一个类实现InvocationHandler接口,重写Invoke方法,在Invoke方法可以进行增强处理的逻辑的编写,这个公共代理类在运行的时候才能明确自己要代理的对象,同时可以实现该被代理类的方法的实现,然后在实现类方法的时候可以进行增强处理。
实际上:代理对象的方法 = 增强处理 + 被代理对象的方法

JDK和CGLIB生成动态代理类的区别:
JDK动态代理只能针对实现了接口的类生成代理(实例化一个类)。此时代理对象和目标对象实现了相同的接口,目标对象作为代理对象的一个属性,具体接口实现中,可以在调用目标对象相应方法前后加上其他业务处理逻辑
CGLIB是针对类实现代理,主要是对指定的类生成一个子类(没有实例化一个类),覆盖其中的方法 。
Spring AOP应用场景
性能检测,访问控制,日志管理,事务等。
默认的策略是如果目标类实现接口,则使用JDK动态代理技术,如果目标对象没有实现接口,则默认会采用CGLIB代理

17、

SpringMVC运行原理

  1. 客户端请求提交到DispatcherServlet
  2. 由DispatcherServlet控制器查询HandlerMapping,找到并分发到指定的Controller中。
  3. Controller调用业务逻辑处理后,返回ModelAndView
  4. DispatcherServlet查询一个或多个ViewResoler视图解析器,找到ModelAndView指定的视图
  5. 视图负责将结果显示到客户端

友情链接:Spring:基于注解的Spring MVC(上)
友情链接: Spring:基于注解的Spring MVC(下) 
友情链接:SpringMVC与Struts2区别与比较总结
友情链接:SpringMVC与Struts2的对比

18、

Spring事务配置方法:
1.切点信息,用于定位实施事物切面的业务类方法
2.控制事务行为的事务属性,这些属性包括事物隔离级别,事务传播行为,超时时间,回滚规则。

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

19、springmvc的核心是什么,请求的流程是怎么处理的,控制反转怎么实现的;

20、spring里面的aop的原理是什么;

21、BeanFactory 和 FactoryBean?

22、Spring IOC 的理解,其初始化过程?

23、BeanFactory 和 ApplicationContext?

24、Spring Bean 的生命周期,如何被管理的?

25、Spring Bean 的加载过程是怎样的?

26、如果要你实现Spring AOP,请问怎么实现?

27、如果要你实现Spring IOC,你会注意哪些问题?

28、Spring 是如何管理事务的,事务管理机制?

29、Spring 的不同事务传播行为有哪些,干什么用的?

30、Spring 中用到了那些设计模式?

31、Spring MVC 的工作原理?

32、Spring 循环注入的原理?

33、Spring AOP的理解,各个术语,他们是怎么相互工作的?

34、Spring 如何保证 Controller 并发的安全?

35. 你有没有⽤过Spring的AOP? 是⽤来⼲嘛的? ⼤概会怎么使⽤?

36. 如果⼀个接⼝有2个不同的实现, 那么怎么来Autowire⼀个指定的实现?

37. Spring的声明式事务 @Transaction注解⼀般写在什么位置? 抛出了异常 会⾃动回滚吗?有没有办法控制不触发回滚?

38. 如果想在某个Bean⽣成并装配完毕后执⾏⾃⼰的逻辑,可以什么⽅式实 现?

39. SpringBoot没有放到web容器⾥为什么能跑HTTP服务?

40. SpringBoot中如果你想使⽤⾃定义的配置⽂件⽽不仅仅是 application.properties,应该怎么弄?

41. SpringMVC中RequestMapping可以指定GET, POST⽅法么?怎么指定?

42. SpringMVC如果希望把输出的Object(例如XXResult或者XXResponse)这 种包装为JSON输出, 应该怎么处理?

43. 怎样拦截SpringMVC的异常,然后做⾃定义的处理,⽐如打⽇志或者包装 成JSON

44. 1.struts1和struts2的区别

45. .struts2和springMVC的区别

46. spring框架中需要引用哪些jar包,以及这些jar包的用途

47. springMVC的原理

48. springMVC注解的意思

49. spring中beanFactory和ApplicationContext的联系和区别

50. spring注入的几种方式

51. spring如何实现事物管理的

52. springIOC和AOP的原理

53. hibernate中的1级和2级缓存的使用方式以及区别原理

54. spring中循环注入的方式

55. springmvc的核心是什么,请求的流程是怎么处理的,控制反转怎么实现的

核心:

控制反转和面向切面

请求处理流程:

1、首先用户发送请求到前端控制器,前端控制器根据请求信息(如URL)来决定选择哪一个页面控制器进行处理并把请求委托给它,即以前的控制器的控制逻辑部分;

2、页面控制器接收到请求后,进行功能处理,首先需要收集和绑定请求参数到一个对象,并进行验证,然后将命令对象委托给业务对象进行处理;处理完毕后返回一个ModelAndView(模型数据和逻辑视图名);

3、前端控制器收回控制权,然后根据返回的逻辑视图名,选择相应的视图进行渲染,并把模型数据传入以便视图渲染;

4、前端控制器再次收回控制权,将响应返回给用户。

控制反转如何实现:

我们每次使用spring框架都要配置xml文件,这个xml配置了bean的id和class。

spring中默认的bean为单实例模式,通过bean的class引用反射机制可以创建这个实例。

因此,spring框架通过反射替我们创建好了实例并且替我们维护他们。

A需要引用B类,spring框架就会通过xml把B实例的引用传给了A的成员变量。

56、.spring的特点及好处:https://www.cnblogs.com/song1314/articles/4568379.html
57、.spring的69面试题:https://www.cnblogs.com/huajiezh/p/6415276.html
58、.spring简化java开发复杂性的策略:http://blog.csdn.net/running_nz/article/details/54583100
59、.spring循环依赖及解决办法:http://blog.csdn.net/caomiao2006/article/details/46511123
60、.springmvc工作流程和原理:http://blog.csdn.net/liangzi_lucky/article/details/52459378
61、.spring注解原理:http://blog.csdn.net/u010987379/article/details/52152795

 62、

Spring AOP 实现原理?

参考 :http://blog.csdn.net/moreevan/article/details/11977115/

63、@transactional注解在什么情况下会失效,为什么。

64、SpringMVC的Controller是如何将参数和前端传来的数据一一对应的。
65、Quartz是如何完成定时任务的。
66、自定义注解的实现。
67、Spring使用了哪些设计模式。
68、Spring的IOC有什么优势。
69、Spring如何维护它拥有的bean。

70、.Struts中请求处理过程#

参考文章http://www.cnblogs.com/liuling/p/2013-8-10-01.html

71、.MVC概念#
参考文章http://www.cnblogs.com/scwyh/articles/1436802.html

72、.Springmvc与Struts区别#
参考文章:
http://blog.csdn.net/tch918/article/details/38305395
http://blog.csdn.net/chenleixing/article/details/44570681

73、.Hibernate/Ibatis两者的区别#
参考文章http://blog.csdn.net/firejuly/article/details/8190229

74、.Hibernate一级和二级缓存#
参考文章http://blog.csdn.net/windrui/article/details/23165845

75、.简述Hibernate常见优化策略#
参考文章http://blog.csdn.net/shimiso/article/details/8819114

76、.Springbean的加载过程(推荐看Spring的源码)#
参考文章http://geeekr.com/read-spring-source-1-how-to-load-bean/

77、.Springbean的实例化(推荐看Spring的源码)#
参考文章http://geeekr.com/read-spring-source-two-beans-initialization/

78、.Spring如何实现AOP和IOC(推荐看Spring的源码)#
参考文章http://www.360doc.com/content/15/0116/21/12385684_441408260.shtml

79、.Springbean注入方式#
参考文章http://blessht.iteye.com/blog/1162131

80、.Spring的事务管理#
这个主题的参考文章没找到特别好的,http://blog.csdn.net/trigl/article/details/50968079这个还可以。

81、.Spring事务的传播特性#
参考文章http://blog.csdn.net/lfsf802/article/details/9417095

80、.springmvc原理
参考文章http://blog.sina.com.cn/s/blog_7ef0a3fb0101po57.html

81、.springmvc用过哪些注解#
参考文章http://aijuans.iteye.com/blog/2160141

 82、Spring 事务的隔离性,并说说每个隔离性的区别

解答:Spring事务详解

83、Spring事务的传播行为,并说说每个传播行为的区别

解答:Spring事务详解

84、hibernate跟Mybatis/ ibatis 的区别,为什么选择?

解答:Hibernate与Mybatis的比较

85、Struts跟Spring mvc的优缺点,让你选会如何选

解答:Spring MVC 与 Struts的区别

86、简单说说Spring 事务机制

解答:Spring事务机制

87、Spring 4.0新特性

解答:Spring4新特性

88、SpringMVC的原理以及返回数据如何渲染到jsp/html上?

答:Spring MVC的核心就是 DispatcherServlet , 一个请求经过 DispatcherServlet ,转发给HandlerMapping ,然后经反射,对应 Controller及其里面方法的@RequestMapping地址,最后经ModelAndView和ViewResoler返回给对应视图  。  具体可参考:Spring MVC的工作原理

89、Spring的原理

答:Spring的核心是IOC和AOP  ,IOC是依赖注入和控制反转, 其注入方式可分为set注入、构造器注入、接口注入等等。IOC就是一个容器,负责实例化、定位、配置应用程序中的对象及建立这些对象间的依赖。简单理解就是:JAVA每个业务逻辑处理至少需要两个或者以上的对象协作进行工作,但是每个对象在使用它的合作对象的时候,都需要频繁的new 对象来实现,你就会发现,对象间的耦合度高了。而IOC的思想是:Spring容器来管理这些,对象只需要处理本身业务关系就好了。至于什么是控制反转,就是获得依赖对象的方式反转了。
AOP呢,面向切面编程,最直接的体现就是Spring事物管理。至于Spring事物的相关资料,就不细说了,参考:Spring注解式事物管理

 

JavaWeb 开发经典的 3 层框架:Web 层、Service 层(业务逻辑层)和 Dao 层(数据访问层)

  • Web 层:包含 JSP 和 Servlet 等与 Web 相关的内容;
  • 业务层:只关心业务逻辑;
  • 数据层:封装了对数据库的访问细节。

Spring 知识点

90、Spring 的 IOC 和 AOP 有了解吗?

答:

  • IOC:控制反转,(解耦合)将对象间的依赖关系交给 Spring 容器,使用配置文件来创建所依赖的对象,由主动创建对象改为了被动方式;
  • AOP:面向切面编程,将功能代码从业务逻辑代码中分离出来。

91、AOP 的实现方式有哪几种?如何选择?(必考)

答:JDK 动态代理实现和 cglib 实现。

选择:

  1. 如果目标对象实现了接口,默认情况下会采用 JDK 的动态代理实现 AOP,也可以强制使用 cglib 实现 AOP;
  2. 如果目标对象没有实现接口,必须采用 cglib 库,Spring 会自动在 JDK 动态代理和 cglib 之间转换。

扩展:JDK 动态代理如何实现?(加分点)

答:JDK 动态代理,只能对实现了接口的类生成代理,而不是针对类,该目标类型实现的接口都将被代理。原理是通过在运行期间创建一个接口的实现类来完成对目标对象的代理。

  1. 定义一个实现接口 InvocationHandler 的类;
  2. 通过构造函数,注入被代理类;
  3. 实现 invoke( Object proxy, Method method, Object[] args)方法;
  4. 在主函数中获得被代理类的类加载器;
  5. 使用 Proxy.newProxyInstance( ) 产生一个代理对象;
  6. 通过代理对象调用各种方法。

解析:关于 IOC 和 AOP 的详细阐述,请各位参阅我的博客:Spring 核心 AOP(面向切面编程)总结,Spring 框架学习—控制反转(IOC)

92、Spring MVC 的核心控制器是什么?消息处理流程有哪些?

答:核心控制器为 DispatcherServlet。消息流程如下:

93、其他问题包括:重定向和转发的区别、动态代理和静态代理的区别等。

Mybatis 知识点

关于 MyBatis 主要考察占位符#和 $ 的区别,区别如下:

  1. 符号将传入的数据都当做一个字符串,会对自动传入的数据加一个双引号;
  2. $ 符号将传入的数据直接显示生成 SQL 中;
  3. 符号存在预编译的过程,,对问号赋值,防止 SQL 注入;
  4. $ 符号是直译的方式,一般用在 order by ${列名}语句中;
  5. 能用#号就不要用 $ 符号。
小结:限于作者水平,MVC 框架方面了解不是太多,实战能力欠缺。面试官偶尔问框架底层实现原理等都知之甚少,有能力的小伙伴可以多加学习。

 

Netty

1、为什么选择 Netty

2、说说业务中,Netty 的使用场景

3、原生的 NIO 在 JDK 1.7 版本存在 epoll bug

4、什么是TCP 粘包/拆包

5、TCP粘包/拆包的解决办法

6、Netty 线程模型

7、说说 Netty 的零拷贝

8、Netty 内部执行流程

9、Netty 重连实现

10、BIO、NIO和AIO

11、Netty 的各大组件

12、Netty的线程模型

13、TCP 粘包/拆包的原因及解决方法

14、了解哪几种序列化协议?包括使用场景和如何去选择

15、Netty的零拷贝实现

16、Netty的高性能表现在哪些方面

17.BIO、NIO和AIO的区别?

18.NIO的组成?

19.Netty的特点?

20.Netty的线程模型?

21.TCP 粘包/拆包的原因及解决方法?

22.了解哪几种序列化协议?

23.如何选择序列化协议?

24.Netty的零拷贝实现?

25.Netty的高性能表现在哪些方面?

26.NIOEventLoopGroup源码?

 

 

MyBatis

1、

Mybatis
每一个Mybatis的应用程序都以一个SqlSessionFactory对象的实例为核心。首先用字节流通过Resource将配置文件读入,然后通过SqlSessionFactoryBuilder().build方法创建SqlSessionFactory,然后再通过SqlSessionFactory.openSession()方法创建一个SqlSession为每一个数据库事务服务。
经历了Mybatis初始化 –>创建SqlSession –>运行SQL语句,返回结果三个过程

2、

mybatis如何处理结果集:反射,建议看看源码;

3、mybatis如何处理结果集

MyBatis的结果集是通过反射来实现的。并不是通过get/set方法。在实体类中无论是否定义get/set()方法,都是可以接收到的。 

如果面试只是考你这个点的话就恭喜了。如果继续深问流程,那就需要自己找一些源码来阅读了。

4、 mybatis常用api:https://www.cnblogs.com/haimishasha/p/5710474.html
5、.mybatis分页及分页插件原理:http://blog.csdn.net/jaryle/article/details/52315565
6、.mybatis插件原理:http://blog.csdn.net/hupanfeng/article/details/9247379
7、.mybatis动态sql原理:http://www.importnew.com/24160.html
8、.mybatis延迟加载:http://blog.csdn.net/eson_15/article/details/51668523

9、

Mybatis如何找到指定的Mapper的,如何完成查询的。

 

Dubbo

1.什么是rcp框架:https://www.cnblogs.com/ChrisMurphy/p/6550184.html
2.序列化方式方式及作用:http://blog.csdn.net/u012554102/article/details/51902697
3.dubbo底层协议实现:https://www.cnblogs.com/1201x/p/6482638.html
4.dubbo注册中心如何设置:http://blog.csdn.net/u011659172/article/details/51491518
5.dubbo负载均衡的理解:https://www.cnblogs.com/qingfengbuluo/p/5527930.html
6.dubbo容错机制:https://www.2cto.com/kf/201612/572681.html
7.服务调用超时的实现原理:https://www.cnblogs.com/ASPNET2008/p/7292472.html
8.服务注册与发现的流程:http://doc.okbase.net/661116/archive/241946.html

 

 

微服务篇

微服务

1、前后端分离是如何做的

2、微服务哪些框架

3、你怎么理解 RPC 框架

4、说说 RPC 的实现原理

5、说说 Dubbo 的实现原理

6、你怎么理解 RESTful

7、说说如何设计一个良好的 API

8、如何理解 RESTful API 的幂等性

9、如何保证接口的幂等性

10、说说 CAP 定理、 BASE 理论

11、怎么考虑数据一致性问题

12、说说最终一致性的实现方案

13、你怎么看待微服务

14、微服务与 SOA 的区别

15、如何拆分服务

16、微服务如何进行数据库管理

17、如何应对微服务的链式调用异常

18、对于快速追踪与定位问题

19、微服务的安全

 
 

分布式

1、谈谈业务中使用分布式的场景

2、Session 分布式方案

3、分布式锁的场景

4、分布是锁的实现方案

5、分布式事务

6、集群与负载均衡的算法与实现

7、说说分库与分表设计

8、分库与分表带来的分布式困境与应对之策

 
 
9、

一致性哈希:
Memcahed缓存:
数据结构:key,value对
使用方法:get,put等方法
友情链接:hashcode(),equal()方法深入解析

 10、

分布式Session框架

  1. 配置服务器,Zookeeper集群管理服务器可以统一管理所有服务器的配置文件
  2. 共享这些Session存储在一个分布式缓存中,可以随时写入和读取,而且性能要很好,如Memcache,Tair。
  3. 封装一个类继承自HttpSession,将Session存入到这个类中然后再存入分布式缓存中
  4. 由于Cookie不能跨域访问,要实现Session同步,要同步SessionID写到不同域名下。

11、zookeeper是什么;

12、zookeeper哪里用到;

13、zookeeper的选主过程;

14、zookeeper集群之间如何通讯;

15、你们的zookeeper的节点加密是用的什么方式;

16、分布式锁的实现过程;

17、Dubbo的底层实现原理和机制

18、描述一个服务从发布到被消费的详细过程

19、分布式系统怎么做服务治理

20、接口的幂等性的概念

21、消息中间件如何解决消息丢失问题

22、Dubbo的服务请求失败怎么处理

23、重连机制会不会造成错误

24、对分布式事务的理解

25、如何实现负载均衡,有哪些算法可以实现?

26、Zookeeper的用途,选举的原理是什么?

27、数据的垂直拆分水平拆分。

28、zookeeper原理和适用场景

29、zookeeper watch机制

30、redis/zk节点宕机如何处理

31、分布式集群下如何做到唯一序列号

32、如何做一个分布式锁

33、用过哪些MQ,怎么用的,和其他mq比较有什么优缺点,MQ的连接是线程安全的吗

34、MQ系统的数据如何保证不丢失

35、列举出你能想到的数据库分库分表策略;分库分表后,如何解决全表查询的问题

36、zookeeper的选举策略

37、全局ID

38、分布式事务的控制。
39、分布式锁如何设计。
40、分布式session如何设计。
41、dubbo的组件有哪些,各有什么作用。
42、zookeeper的负载均衡算法有哪些。
43、dubbo是如何利用接口就可以通信的。

44、集群环境中,session如何实现共享

答:

1、Java集群之session共享    

2、session多服务器共享方案,还有一种方案就是使用一个固定的服务器专门保持session,其他服务器共享

45、分布式、集群环境中,缓存如何刷新,如何保持同步?

答:

A、缓存如何刷新? 1、定时刷新  2、主动刷新覆盖   ,每个缓存框架都有自带的刷新机制,或者说缓存失效机制,就拿Redis和 Ehcache举例, 他们都有自带的过期机制,另外主动刷新覆盖时,只需获取对应的key进行数据的覆盖即可

B、缓存如何保持同步?  这个redis有自带的集群同步机制,即复制功能,具体参考:基于Redis分布式缓存实现      ,Ehcache也有分布式缓存同步的配置,只需要配置不同服务器地址即可,参照:Ehcache分布式缓存同步

46、消息队列的原理和实现

解答:1、消息队列原理     2、深入浅出 消息队列 ActiveMQ

47、Redis实现消息队列

答:Redis实现消息队列     、参考2

48、谈谈你对分布式的理解

答:个人理解:分布式就是把一个系统/业务 拆分成多个子系统/子业务 去协同处理,这个过程就叫分布式,具体的演变方式参考:Java分布式应用技术架构介绍

 
 

安全&性能

安全问题

1、安全要素与 STRIDE 威胁

2、防范常见的 Web 攻击

3、服务端通信安全攻防

4、HTTPS 原理剖析

5、HTTPS 降级攻击

6、授权与认证

7、基于角色的访问控制

8、基于数据的访问控制

性能优化

1、性能指标有哪些

2、如何发现性能瓶颈

3、性能调优的常见手段

4、说说你在项目中如何进行性能调优

 
 

5、web如何项目优化

解答:这个我整理过一次,web项目性能优化(整理)

6、日常项目中,如果你接手,你准备从哪些方面调优?

答:这个呢首先是了解哪些需要优化,需要优化肯定是项目性能遭遇瓶颈或者猜测即将遭遇了,我们才会去考虑优化。那么怎么优化?

a、扩容 ,扩容的理解,就是扩充服务器并行处理的能力,简单来说就是加服务器,增加处理请求的能力,例如增加nginx 、tomcat等应用服务器的个数,或者物理服务器的个数,还有加大服务器带宽等等,这里考虑的是硬件方面

b、调优 ,调优,包括系统调优和代码调优 。 系统调优就是说加快处理速度,比如我们所提到的CDN、ehcache、redis等缓存技术,消息队列等等,加快服务间的响应速度,增加系统吞吐量,避免并发,至于代码调优,这些就需要多积累了,比如重构、工厂等, 数据库调优的话这个我不是很懂,只知道索引和存储过程,具体参考:Mysql数据库调优21个最佳实践  ,其他数据库调优方面就各位自己找找吧

7、分享一个调优工具和方案:如何利用 JConsole观察分析Java程序的运行,进行排错调优

 

工程篇

需求分析

1、你如何对需求原型进行理解和拆分

2、说说你对功能性需求的理解

3、说说你对非功能性需求的理解

4、你针对产品提出哪些交互和改进意见

5、你如何理解用户痛点

设计能力

1、说说你在项目中使用过的 UML 图

2、你如何考虑组件化

3、你如何考虑服务化

4、你如何进行领域建模

5、你如何划分领域边界

6、说说你项目中的领域建模

7、说说概要设计

设计模式

1、你项目中有使用哪些设计模式

2、说说常用开源框架中设计模式使用分析

3、说说你对设计原则的理解

4、23种设计模式的设计理念

5、设计模式之间的异同,例如策略模式与状态模式的区别

6、设计模式之间的结合,例如策略模式+简单工厂模式的实践

7、设计模式的性能,例如单例模式哪种性能更好。

业务工程

1、你系统中的前后端分离是如何做的

2、说说你的开发流程

3、你和团队是如何沟通的

4、你如何进行代码评审

5、说说你对技术与业务的理解

6、说说你在项目中经常遇到的 Exception

7、说说你在项目中遇到感觉最难Bug,怎么解决的

8、说说你在项目中遇到印象最深困难,怎么解决的

9、你觉得你们项目还有哪些不足的地方

10、你是否遇到过 CPU 100% ,如何排查与解决

11、你是否遇到过 内存 OOM ,如何排查与解决

12、说说你对敏捷开发的实践

13、说说你对开发运维的实践

14、介绍下工作中的一个对自己最有价值的项目,以及在这个过程中的角色

 

 

15、重构过代码没有?说说经验;

16、一千万的用户实时排名如何实现;

17、五万人并发抢票怎么实现;

18、大型网站应用之海量数据解决方案 
http://blog.csdn.net/zhaojw_420/article/details/70881230

19、大型网站应用之高并发情况下的解决方案 
http://blog.csdn.net/zhaojw_420/article/details/70881266

20、在一个千万级的数据库查寻中,如何提高查询效率? 
http://blog.csdn.net/zhaojw_420/article/details/69367682

21、 用 wait-notify 写一段代码来解决生产者-消费者问题,更进一步,在分布式的环境下怎么解决

A:哈哈哈,我们来写段代码吧……

wait()notify()都是线程间通信的方法,可以直接对线程的行为进行操作。他们的本质其实是传递生产者-消费者各自的消息,理解了这一点,那么在分布式环境下就很简单了,只要找到一个第三方的可以用来传递消息的媒介(Zookeeper、Redis、Kafka等)就可以了。

22.、设计一个线程池

A:可以参考Java线程池的理论与实践

如果对JDK的线程池java.util.concurrent.ThreadPoolExecutor比较了解,可以把一些简单的特性放上去。如果不了解,可以直接设计一个线程数组,然后加一些业务逻辑。所谓线程池,基本也就如此。

23、 设计一个IOC容器

A:用反射,注解,还有IOC的理论

24. 谈谈你对C10K问题的理解

A:NIO对BIO在吞吐量上的优势,可以参考从I/O模型到Netty(一)

25、

手机扫二维码登录是怎么实现的?

参考:http://www.jianshu.com/p/7f072ac61763

26、

如何保证RESTful API安全性 ?

参考: http://blog.csdn.net/ywk253100/article/details/25654101

27、项目并发如何处理?(我们是web项目)

解答:高并发量网站解决方案,另外,还有数据库乐观锁,数据库读写分离、使用消息队列、多用存储过程等等

28、简单说说功能权限存在的水平权限漏洞和垂直权限漏洞的场景和解决办法(因为我们目前权限级别就是功能权限)

解答:
A、水平权限漏洞,如下图

假设机构有 用户A和用户B 两个用户,其中A有1、2和3权限 ,  用户B有 2 和3 的权限,这时候假设用户B 知道1,并给自己添加1的权限,这时候就是水平权限漏洞。
目前解决办法:1、限制入口,让用户B无法编辑自己的权限   2、对用户B无法进行向上扩展。最根本的解决办法是深入到数据权限
解答:水平权限漏洞和解决办法

B、垂直权限漏洞
解答:垂直权限漏洞案例和解决方案

29、平台上的图片如何防盗链

解答:http下载防盗链原理:http协议的字段referer记录来实现

30、如何区分上传的图片是不是木马?

解答:1、看上传的图片后缀  2、如何后缀是篡改的,那么每个文件有个魔术数字  文件上传-魔术数字

面试还会问到一些关于设计方案相关的问题,比如

31、你的接口服务数据被人截包了,你如何防止数据恶意提交?

答:我们可以在接口传输参数里面设置一个业务编号,这个编号用来区分是否重复提交。这样即使数据被抓包了,对方也无法区分每个字段你的含义,这时,这个业务编号的作用就来了

32、假设服务器经常宕机,你从哪些方面去排查问题?

答:这个就留个各位看官补充了,可评论回复

 

 

 

软实力

1、说说你的亮点

2、说说你最近在看什么书

3、说说你觉得最有意义的技术书籍

4、工作之余做什么事情

5、说说个人发展方向方面的思考

6、说说你认为的服务端开发工程师应该具备哪些能力

7、说说你认为的架构师是什么样的,架构师主要做什么

8、说说你所理解的技术专家

posted on 2018-05-31 18:42  Vindia  阅读(490)  评论(0)    收藏  举报

导航