java 基础面试题

共包含 208 道面试题,主要用于学习

Java 基础

1. JDK 和 JRE 有什么区别?

JRE是Java Runtime Environment的缩写,顾名思义是java运行时环境,包含了java虚拟机,java基础类库。

Jdk是Java Development Kit的缩写,顾名思义是java开发工具包,是程序员使用java语言编写java程序所需的开发工具包,是提供给程序员使用的

2. == 和 equals 的区别是什么?

== : 它的作用是判断两个对象的地址是不是相等。即,判断两个对象是不是同一个对象。对于基本类型和引用类型 == 的作用效果是不同的:

基本数据类型==比较的是 值,

引用数据类型==比较的是内存地址

equals() : 它的作用也是判断两个对象是否相等。但它一般有两种使用情况:

情况1:类没有覆盖 equals() 方法。则通过 equals() 比较该类的两个对象时,等价于通过“==”比较这两个对象。

情况2:类覆盖了 equals() 方法。一般,我们都覆盖 equals() 方法来两个对象的内容相等;若它们的内容相 等,则返回 true (即,认为这两个对象相等)

3. 两个对象的 hashCode() 相同,则 equals() 也一定为 true,对吗?

false

4.final 在 Java 中有什么作用?

final修饰类:表示该类不能被继承

使用final修饰类的目的简单明确: 表明这个类不能被继承。

当程序中有永远不会被继承的类时, 可以使用final关键字修饰。

被final修饰的类所有成员方法都将被隐式修饰为final方法。

final作为Java中的关键字可以用于三个地方。用于修饰类、类属性和类方法。

特征:凡是引用final关键字的地方皆不可修改!(1)修饰类:表示该类不能被继承;(2)修饰方法:表示方法不能被重写;(3)修饰变量:表示变量不能被修改

5. Java 中的 Math. round(-1. 5) 等于多少? -1

6. String 属于基础的数据类型吗?不属于String 类型却是最常用到的引用类型

7. Java 中操作字符串都有哪些类?它们之间有什么区别?

String  StringBuffer  StringBuilde  

这三个类都是以char[]的形式保存的字符串,但是String类型的字符串是不可变的,

String类型的字符床做修改操作都是相当于重新创建对象.而对StringBuffer和StringBuilder进行增删操作都是对同一个对象做操作.

StringBuffer中的方法大部分都使用synchronized关键字修饰,所以StringBuffer是线程安全的,StringBuilder中的方法则没有,线程不安全,

StringBuilder因为没有使用使用synchronized关键字修饰,所以性能更高,在单线程环境下我会选择使用StringBuilder,多线程环境下使用StringBuffer.如果生命的这个字符串几乎不做修改操作,那么我就直接使用String,因为不调用new关键字声明String类型的变量的话它不会在堆内存中创建对象,直接指向String的常量池,并且可以复用.效率更高.到这时候还不过瘾的话你就接着说这三个类创建的时候都是什么状态,扩容的时候又怎么扩容的等等

8. String str="i"与 String str=new String("i")一样吗?

不一样,因为内存的分配方式不一样。String str=”i”的方式,java 虚拟机会将其分配到常量池中;而 String str=new String(“i”) 则会被分到堆内存中。

9.如何将字符串反转?

1. 利用 StringBuffer 或 StringBuilder 的 reverse 成员方法:// StringBuffer

  public static String reverse1(String str) {

    return new StringBuilder(str).reverse().toString();

  }

2利用 String 的 toCharArray 方法先将字符串转化为 char 类型数组,然后将各个字符进行重新拼接:

 public static String reverse2(String str) {

char[] chars = str.toCharArray();

    String reverse = "";

    for (int i = chars.length - 1; i >= 0; i--) {

      reverse += chars[i];}

return reverse;

  }

3. 利用 String 的 CharAt 方法取出字符串中的各个字符:

  public static String reverse3(String str) {

    String reverse = "";

int length = str.length();

    for (int i = 0; i < length; i++) {

      reverse = str.charAt(i) + reverse;

    }

return reverse;

10.String 类的常用方法都有那些?

·indexOf():返回指定字符的索引。

·charAt():返回指定索引处的字符。

·replace():字符串替换。

·trim():去除字符串两端空白。

·split():分割字符串,返回一个分割后的字符串数组。

·getBytes():返回字符串的 byte 类型数组。

·length():返回字符串长度。

·toLowerCase():将字符串转成小写字母。

·toUpperCase():将字符串转成大写字符。

·substring():截取字符串。

·equals():字符串比较。

11.抽象类必须要有抽象方法吗?

不必须

1.如果一个类使用了abstract关键字修饰,那么这个类就是一个抽象类。

2.抽象类可以没有抽象方法

3.一个类如果包含抽象方法,那么这个类必须是抽象类,否则编译就会报错。

4.最关键的一点就是如果一个类是抽象类,那么这个类是不能被实例化的。

12.普通类和抽象类有哪些区别?

·抽象类不能被实例化

·抽象类可以有抽象方法,抽象方法只需申明,无需实现

·含有抽象方法的类必须申明为抽象类

·抽象的子类必须实现抽象类中所有抽象方法,否则这个子类也是抽象类

·抽象方法不能被声明为静态

·抽象方法不能用private修饰

·抽象方法不能用final修饰

13.抽象类能使用 final 修饰吗?

   不能,抽象类是被用于继承的,final修饰代表不可修改、不可继承的。

14.接口和抽象类有什么区别?

1、抽象类和接口都不能直接实例化,如果要实例化,抽象类变量必须指向实现所有抽象方法的子类对象,接口变量必须指向实现所有接口方法的类对象。

2、抽象类要被子类继承,接口要被类实现。

3、接口只能做方法申明,抽象类中可以做方法申明,也可以做方法实现

4、接口里定义的变量只能是公共的静态的常量,抽象类中的变量是普通变量。

5、抽象类里的抽象方法必须全部被子类所实现,如果子类不能全部实现父类抽象方法,那么该子类只能是抽象类。同样,一个实现接口的时候,如不能全部实现接口方法,那么该类也只能为抽象类。

6、抽象方法只能申明,不能实现,接口是设计的结果 ,抽象类是重构的结果

7、抽象类里可以没有抽象方法

8、如果一个类里有抽象方法,那么这个类只能是抽象类

9、抽象方法要被实现,所以不能是静态的,也不能是私有的。

10、接口可继承接口,并可多继承接口,但类只能单根继承

15.Java 中 IO 流分为几种?

按照流的流向分,可以分为输入流和输出流;

·按照操作单元划分,可以划分为字节流和字符流;

·按照流的角色划分为节点流和处理流。

16.BIO、NIO、AIO 有什么区别?

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

Java对BIO、NIO、AIO的支持:

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

BIO、NIO、AIO适用场景分析:

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

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

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

17. Files的常用方法都有哪些?

Files.exists():检测文件路径是否存在。

Files.createFile():创建文件。

Files.createDirectory():创建文件夹。

Files.delete():删除一个文件或目录。

Files.copy():复制文件。

Files.move():移动文件。

Files.size():查看文件个数。

Files.read():读取文件。

Files.write():写入文件。

18.Java 容器都有哪些?

Collection: 存放独立元素的序列。

Map:存放key-value型的元素对。(这对于需要利用key查找value的程序十分的重要!)

Collection下分为List、Set和Queue;

List下分为ArrayList和LinkedList;

Set下分为HashSet、LinkedHashSet和TreeSet;

Queue下有PriorityQueue。

Map下分为HashMap、LinkedHashMap、TreeMap、WeakHashMap;

Collection代表的是单个元素对象的序列;Map代表的是“键值对”对象的集合。

19. Collection 和 Collections 有什么区别?

1.Collection 是一个集合接口。它提供了对集合对象进行基本操作的通用接口方法。Collection接口在Java 类库中有很多具体的实现。Collection接口的意义是为各种具体的集合提供了最大化的...

2.Collections 是一个包装类。它包含有各种有关集合操作的静态多态方法。此类不能实例化,就像一个工具类,服务于Java的Collection框架。

20.List、Set、Map 之间的区别是什么?

list(列表)、set(集)、map(映射)

List接口和Set接口属于Collection接口,Map接口和Collection接口并列存在(同级)

 List(元素可重复性,有序性)

 Set(具有唯一性,无序性)

21.HashMap 和 Hashtable 有什么区别?

hashmap:底层结构是数组+链表,无序,线程不安全,效率高,允许有null(key和value都允许),父类是AbstractMap

treemap:底层结构是红黑树,有序,将数据按照key排序,默认是升序排序。

hashtable:底层结构是哈希表,无序,线程安全,效率低,不允许有null值,父类是Dictionary

22. 如何决定使用 HashMap 还是 TreeMap?

如果你需要得到一个有序的结果时就应该使用TreeMap(因为HashMap中元素的排列顺序是不固定的)。除此之外,由于HashMap有更好的性能,所以大多不需要排序的时候我们会使用HashMap。

22.说一下 HashMap 的实现原理?

·HashMap 基于 Hash 算法实现,通过 put(key,value) 存储,get(key) 来获取 value

·当传入 key 时,HashMap 会根据 key,调用 hash(Object key) 方法,计算出 hash 值,根据 hash 值将 value 保存在 Node 对象里,Node 对象保存在数组里

·当计算出的 hash 值相同时,称之为 hash 冲突,HashMap 的做法是用链表和红黑树存储相同 hash 值的 value

·当 hash 冲突的个数:小于等于 8 使用链表;大于 8 时,使用红黑树解决链表查询慢的问题

ps:

·上述是 JDK 1.8 HashMap 的实现原理,并不是每个版本都相同,比如 JDK 1.7 的 HashMap 是基于数组 + 链表实现,所以 hash 冲突时链表的查询效率低

23.说一下 HashSet 的实现原理?

HashSet实际上是一个HashMap实例,都是一个存放链表的数组。它不保证存储元素的迭代顺序;此类允许使用null元素。HashSet中不允许有重复元素,这是因为HashSet是基于HashMap实现的,HashSet中的元素都存放在HashMap的key上面,而value中的值都是统一的一个固定对象private static final Object PRESENT = new Object();

HashSet中add方法调用的是底层HashMap中的put()方法,而如果是在HashMap中调用put,首先会判断key是否存在,如果key存在则修改value值,如果key不存在这插入这个key-value。而在set中,因为value值没有用,也就不存在修改value值的说法,因此往HashSet中添加元素,首先判断元素(也就是key)是否存在,如果不存在这插入,如果存在着不插入,这样HashSet中就不存在重复值。

 所以判断key是否存在就要重写元素的类的equals()和hashCode()方法,当向Set中添加对象时,首先调用此对象所在类的hashCode()方法,计算次对象的哈希值,此哈希值决定了此对象在Set中存放的位置;若此位置没有被存储对象则直接存储,若已有对象则通过对象所在类的equals()比较两个对象是否相同,相同则不能被添加。

24.ArrayList 和 LinkedList 的区别是什么?

·   ArrayList基于动态数组实现的非线程安全的集合;LinkedList基于链表实现的非线程安全的集合。

·对于随机index访问的get和set方法,一般ArrayList的速度要优于LinkedList。因为ArrayList直接通过数组下标直接找到元素;LinkedList要移动指针遍历每个元素直到找到为止。

·新增和删除元素,一般LinkedList的速度要优于ArrayList。因为ArrayList在新增和删除元素时,可能扩容和复制数组;LinkedList实例化对象需要时间外,只需要修改指针即可。

·LinkedList集合不支持 高效的随机随机访问(RandomAccess)

·ArrayList的空间浪费主要体现在在list列表的结尾预留一定的容量空间,而LinkedList的空间花费则体现在它的每一个元素都需要消耗相当的空间

25.如何实现数组和 List 之间的转换?

数组转 List ,使用 JDK 中 java.util.Arrays 工具类的 asList 方法

26.ArrayList 和 Vector 的区别是什么?

Vector与ArrayList一样,也是通过数组实现的,不同的是它支持线程的同步,即某一时刻只有一个线程能够写Vector,避免多线程同时写而引起的不一致性,但实现同步需要很高的花费,因此,访问它比访问ArrayList慢

如果集合中的元素的数目大于目前集合数组的长度时,vector增长率为目前数组长度的100%,而arraylist增长率为目前数组长度

的50%.如过在集合中使用数据量比较大的数据,用vector有一定的优势。

1)  Vector的方法都是同步的(Synchronized),是线程安全的(thread-safe),而ArrayList的方法不是,由于线程的同步必然要影响性能,因此,ArrayList的性能比Vector好。  

2) 当Vector或ArrayList中的元素超过它的初始大小时,Vector会将它的容量翻倍,而ArrayList只增加50%的大小,这样,ArrayList就有利于节约内存空间。

27.Array 和 ArrayList 有何区别?

1 Array类型的变量在声明的同bai时必须进行实例化(至少得初始化数组的大小),而ArrayList可以只是先声明

2 Array只能存储同构的对象,而ArrayList可以存储异构的对象。

3 在CLR托管对中的存放方式

Array是始终是连续存放的,而ArrayList的存放不一定连续

Array可以包含基本类型和对象类型,ArrayList只能包含对象类型。

Array大小是固定的,ArrayList的大小是动态变化的。

ArrayList提供了更多的方法和特性,比如:addAll(),removeAll(),iterator()等等。

对于基本类型数据,ArrayList 使用自动装箱来减少编码工作量;而当处理固定大小的基本数据类型的时候,这种方式相对比较慢,这时候应该使用Array。

28.在 Queue 中 poll()和 remove()有什么区别?

poll()和remove()都将移除并且返回对头,但是在poll()在队列为空时返回null,而remove()会抛出NoSuchElementException异常

29.哪些集合类是线程安全的?

Java中线程安全的集合类有Stack、Vector、Properties、Hashtable等。

vector:就比arraylist多了个同步化机制(线程安全),因为效率较低,现在已经不太建议使用。在web应用中,特别是前台页面,往往效率(页面响应速度)是优先考虑的。statck:堆栈类,先进后出。hashtable:就比hashmap多了个线程安全。enumeration:枚举,相当于迭代器。

30.迭代器 Iterator 是什么?

   Iterator接口提供了很多对集合元素进行迭代的方法。每一个集合类都包括了可以返回迭代器实例的迭代方法。迭代器可以在迭代过程中删除底层集合的元素,但是不可以直接调用集合的remove(Object obj)删除,可以通过迭代器的remove()方法删除

31.Iterator 怎么使用?有什么特点?

·java.lang.Iterable 接口被 java.util.Collection 接口继承,java.util.Collection 接口的 iterator() 方法返回一个 Iterator 对象

·next() 方法获得集合中的下一个元素

·hasNext() 检查集合中是否还有元素

·remove() 方法将迭代器新返回的元素删除

·forEachRemaining(Consumer<? super E> action) 方法,遍历所有元素

32.Iterator 和 ListIterator 有什么区别?

1. ListIterator有add()方法,可以向List中添加对象,而Iterator不能

2. ListIterator和Iterator都有hasNext()和next()方法,可以实现顺序向后遍历,但是ListIterator有hasPrevious()和previous()方法,可以实现逆向(顺序向前)遍历。Iterator就不可以。

3. ListIterator可以定位当前的索引位置,nextIndex()和previousIndex()可以实现。Iterator没有此功能。

4. 都可实现删除对象,但是ListIterator可以实现对象的修改,set()方法可以实现。Iierator仅能遍历,不能修改。

34. 怎么确保一个集合不能被修改?

Collections. unmodifiableCollection(Collection c) 方法创建的集合,和使用Arrays.asList创建的集合

list = Collections.unmodifiableList(list);

35.并行和并发有什么区别?

  并发的关键是你有处理多个任务的能力,但不是同时。

并行的关键是你在同时处理多个任务。

36.线程和进程的区别?

(1)进程

进程是程序的一次执行过程,是一个动态概念,是程序在执行过程中分配和管理资源的基本单位,每一个进程都有一个自己的地址空间,至少有 5 种基本状态,它们是:初始态,执行态,等待状态,就绪状态,终止状态。

(2)线程

线程是CPU调度和分派的基本单位,它可与同属一个进程的其他的线程共享进程所拥有的全部资源。

(3)联系

线程是进程的一部分,一个线程只能属于一个进程,而一个进程可以有多个线程,但至少有一个线程。

(4)区别:理解它们的差别,我从资源使用的角度出发。(所谓的资源就是计算机里的中央处理器,内存,文件,网络等等)

根本区别:进程是操作系统资源分配的基本单位,而线程是任务调度和执行的基本单位

在开销方面:每个进程都有独立的代码和数据空间(程序上下文),程序之间的切换会有较大的开销;线程可以看做轻量级的进程,同一类线程共享代码和数据空间,每个线程都有自己独立的运行栈和程序计数器(PC),线程之间切换的开销小。

所处环境:在操作系统中能同时运行多个进程(程序);而在同一个进程(程序)中有多个线程同时执行(通过CPU调度,在每个时间片中只有一个线程执行)

内存分配方面:系统在运行的时候会为每个进程分配不同的内存空间;而对线程而言,除了CPU外,系统不会为线程分配内存(线程所使用的资源来自其所属进程的资源),线程组之间只能共享资源。

包含关系:没有线程的进程可以看做是单线程的,如果一个进程内有多个线程,则执行过程不是一条线的,而是多条线(线程)共同完成的;线程是进程的一部分,所以线程也被称为轻权进程或者轻量级进程。

37.守护线程是什么?

 守护线程又被称为“服务进程”“精灵线程”“后台线程”,是指在程序运行是在后台提供一种通用的线程,这种线程并不属于程序不可或缺的部分。 通俗点讲,任何一个守护线程都是整个JVM中所有非守护线程的“保姆”

守护线程(即daemon thread),是个服务线程,准确地来说就是服务其他的线程,这是它的作用——而其他的线程只有一种,那就是用户线程。所以java里线程分2种,

1、守护线程,比如垃圾回收线程,就是最典型的守护线程。

2、用户线程,就是应用程序里的自定义线程。

38.创建线程有哪几种方式?

(Java中创建线程主要有三种方式:

一、继承Thread类创建线程类

(1)定义Thread类的子类,并重写该类的run方法,该run方法的方法体就代表了线程要完成的任务。因此把run()方法称为执行体。

(2)创建Thread子类的实例,即创建了线程对象。

(3)调用线程对象的start()方法来启动该线程。

二、通过Runnable接口创建线程类

 (1)定义runnable接口的实现类,并重写该接口的run()方法,该run()方法的方法体同样是该线程的线程执行体。

 (2)创建 Runnable实现类的实例,并依此实例作为Thread的target来创建Thread对象,该Thread对象才是真正的线程对象。

 (3)调用线程对象的start()方法来启动该线程。

三、通过Callable和Future创建线程

 (1)创建Callable接口的实现类,并实现call()方法,该call()方法将作为线程执行体,并且有返回值。

(2)创建Callable实现类的实例,使用FutureTask类来包装Callable对象,该FutureTask对象封装了该Callable对象的call()方法的返回值。

(3)使用FutureTask对象作为Thread对象的target创建并启动新线程。

(4)调用FutureTask对象的get()方法来获得子线程执行结束后的返回值

39.说一下 runnable 和 callable 有什么区别?

Runnable和Callable的区别是,

(1)Callable规定的方法是call(),Runnable规定的方法是run().

(2)Callable的任务执行后可返回bai值,而Runnable的任务是不能返回值得

(3)call方法可以抛出异常,run方法不可以

(4)运行Callable任务可以拿到一个Future对象,Future 表示异步计算的结果。

40.线程有哪些状态?

1、新建状态(New):新创建了一个线程对象。

2、就绪状态(Runnable):线程对象创建后,其他线程调用了该对象的start()方法。该状态的线程位于“可运行线程池”中,变得可运行,只等待获取CPU的使用权,

   即在就绪状态的进程除CPU之外,其它的运行所需资源都已全部获得。

3、运行状态(Running):就绪状态的线程获取了CPU,执行程序代码。

4、阻塞状态(Blocked):阻塞状态是线程因为某种原因放弃CPU使用权,暂时停止运行。直到线程进入就绪状态,才有机会转到运行状态。

   阻塞的情况分三种:

①.等待阻塞:运行的线程执行wait()方法,该线程会释放占用的所有资源,JVM会把该线程放入“等待池”中。进入这个状态后,是不能自动唤醒的,

   必须依靠其他线程调用notify()或notifyAll()方法才能被唤醒,

②.同步阻塞:运行的线程在获取对象的同步锁时,若该同步锁被别的线程占用,则JVM会把该线程放入“锁池”中。

③.其他阻塞:运行的线程执行sleep()或join()方法,或者发出了I/O请求时,JVM会把该线程置为阻塞状态。当sleep()状态超时、join()等待线程终止或者超时,

   或者I/O处理完毕时,线程重新转入就绪状态。

5、死亡状态(Dead):线程执行完了或者因异常退出了run()方法,该线程结束生命周期。

41.sleep() 和 wait() 有什么区别?

1、这两个方法来自不同的类分别是Thread和Object,sleep方法属于Thread类中的静态方法,wait属于Object的成员方法。

2、sleep()是线程类(Thread)的方法,不涉及线程通信,调用时会暂停此线程指定的时间,但监控依然保持,不会释放对象锁,到时间自动恢复;wait()是Object的方法,用于线程间的通信,调用时会放弃对象锁,进入等待队列,待调用notify()/notifyAll()唤醒指定的线程或者所有线程,才进入对象锁定池准备获得对象锁进入运行状态。

3、wait,notify和notifyAll只能在同步控制方法或者同步控制块里面使用,而sleep可以在任何地方使用(使用范围)。

4、sleep()方法必须捕获异常InterruptedException,而wait()\notify()以及notifyAll()不需要捕获异常。

注意:

    sleep方法只让出了CPU,而并不会释放同步资源锁。

  线程执行sleep()方法后会转入阻塞状态。

sleep()方法指定的时间为线程不会运行的最短时间。因此,sleep()方法不能保证该线程睡眠到期后就开始执行。

notify的作用相当于叫醒睡着的人,而并不会给他分配任务,就是说notify只是让之前调用wait的线程有权利重新参与线程的调度。

42.notify()和 notifyAll()有什么区别?

 notify() 方法随机唤醒对象的等待池中的一个线程,进入锁池;notifyAll() 唤醒对象的等待池中的所有线程,进入锁池。

43.线程的 run() 和 start() 有什么区别?

·启动一个线程需要调用 Thread 对象的 start() 方法

·调用线程的 start() 方法后,线程处于可运行状态,此时它可以由 JVM 调度并执行,这并不意味着线程就会立即运行

·run() 方法是线程运行时由 JVM 回调的方法,无需手动写代码调用

·直接调用线程的 run() 方法,相当于在调用线程里继续调用方法,并未启动一个新的线程

44.创建线程池有哪几种方式?

通过Executors工厂方法创建

通过new ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue)自定义创建

45.线程池都有哪些状态?

1.Running: 接受新task, 处理等待的task;

2.ShutDown: 不接受新task,但处理等待的task;

3.Stop: 不接受新task, 不处理等待的task, 尝试打断正在执行的task;

4.Tidying:但所有task都被终止, worCount == 0的时候(workCount是指有效的线程数);

5.Terminated: 执行完terminated()方法;

46.线程池中 submit() 和 execute() 方法有什么区别?

·execute():只能执行 Runnable 类型的任务。

·submit():可以执行 Runnable 和 Callable 类型的任务。

·submit()能获取返回值(异步)以及处理Exception。execute()方法不行。

47. 在 Java 程序中怎么保证多线程的运行安全?

方法一:使用安全类,比如 Java. util. concurrent 下的类。方法二:使用自动锁 synchronized。方法三:使用手动锁 Lock

47.多线程中 synchronized 锁升级的原理是什么?

什么是锁升级(锁膨胀)?

JVM优化synchronized的运行机制,当JVM检测到不同的竞争状态时,就会根据需要自动切换到合适的锁,这种切换就是锁的升级。升级是不可逆的,也就是说只能从低到高,也就是偏向-->轻量级-->重量级,不能够降级

锁级别:无锁->偏向锁->轻量级锁->重量级锁

在锁对象的对象头里面有一个 threadid 字段,在第一次访问的时候 threadid 为空,jvm 让其持有偏向锁,并将 threadid 设置为其线程 id,再次进入的时候会先判断 threadid 是否与其线程 id 一致,如果一致则可以直接使用此对象,如果不一致,则升级偏向锁为轻量级锁,通过自旋循环一定次数来获取锁,执行一定次数之后,如果还没有正常获取到要使用的对象,此时就会把锁从轻量级升级为重量级锁,此过程就构成了 synchronized 锁的升级。

锁的升级的目的:锁升级是为了减低了锁带来的性能消耗。在 Java 6 之后优化 synchronized 的实现方式,使用了偏向锁升级为轻量级锁再升级到重量级锁的方式,从而减低了锁带来的性能消耗。

48.什么是死锁?

是指多个进程在运行过程中因争夺资源而造成的一种僵局,当进程处于这种僵持状态时,若无外力作用,它们都将无法再向前推进

49.怎么防止死锁?

死锁的四个必要条件:

·互斥条件:线程要求对所分配的资源(如打印机)进行排他性控制,即在一段时间内某资源仅为一个线程所占有。此时若有其他线程请求该资源,则请求线程只能等待。

·不剥夺条件:线程所获得的资源在未使用完毕之前,不能被其他线程强行夺走,即只能由获得该资源的线程自己主动释放。

·请求和保持条件:线程已经保持了至少一个资源,但又提出了新的资源请求,而该资源已被其他线程占有,此时请求线程被阻塞,但对自己已获得的资源保持不放。

·循环等待条件:存在一种线程资源的循环等待链,链中每一个线程已获得的资源同时被链中下一个线程所请求。即存在一个处于等待状态的线程集合{Pl, P2, ..., pn},其中Pi等待的资源被P(i+1)占有(i=0, 1, ..., n-1),Pn等待的资源被P0占有

避免死锁的方式:

·加锁顺序(线程按照一定的顺序加锁)

·加锁时限(线程尝试获取锁的时候加上一定的时限,超过时限则放弃对该锁的请求,并释放自己占有的锁)

·死锁检测

51. ThreadLocal 是什么?有哪些使用场景?

ThreadLocal 是线程本地存储,在每个线程中都创建了一个 ThreadLocalMap 对象,每个线程可以访问自己内部 ThreadLocalMap 对象内的 value。

场景 JDBC

52. 说一下 synchronized 底层实现原理?

synchronized是JVM实现的一种互斥同步访问方式,底层是基于每个对象的监视器(monitor)来实现的。被synchronized修饰的代码,在被编译器编译后在被修饰的代码前后加上了一组字节指令。

在代码开始加入了monitorenter,在代码后面加入了monitorexit,这两个字节码指令配合完成了synchronized关键字修饰代码的互斥访问。

在虚拟机执行到monitorenter指令的时候,会请求获取对象的monitor锁,基于monitor锁又衍生出一个锁计数器的概念。

当执行monitorenter时,若对象未被锁定时,或者当前线程已经拥有了此对象的monitor锁,则锁计数器+1,该线程获取该对象锁。

当执行monitorexit时,锁计数器-1,当计数器为0时,此对象锁就被释放了。那么其他阻塞的线程则可以请求获取该monitor锁。

53.synchronized 和 volatile 的区别是什么?

作用:

·synchronized 表示只有一个线程可以获取作用对象的锁,执行代码,阻塞其他线程。

·volatile 表示变量在 CPU 的寄存器中是不确定的,必须从主存中读取。保证多线程环境下变量的可见性;禁止指令重排序。 

区别:

·synchronized 可以作用于变量、方法、对象;volatile 只能作用于变量。

·synchronized 可以保证线程间的有序性(猜测是无法保证线程内的有序性,即线程内的代码可能被 CPU 指令重排序)、原子性和可见性;volatile 只保证了可见性和有序性,无法保证原子性。

·synchronized 线程阻塞,volatile 线程不阻塞。

54.synchronized 和 Lock 有什么区别?

类别 synchronized Lock

存在的层次 Java关键字 在JVM层面上 是一个类

锁的释放 1以获取锁的线程执行完同步代码,释放锁

2线程执行发生产异常,jvm会让线程释放锁 在finally中必须释放锁,不然容易造存线程死锁发生异常

锁的获取 假设A线程获取锁,B线程等待。如果A线程阻塞,B线程会一直等待 可以尝试获得锁,线程可以不用一直等待

锁状态 无法判断 可以判断

锁类型 可以重入不可中断非公平 可重入可判断 可公平 (两者皆可)

锁的性能 少量同步 大量同步

55.synchronized 和 ReentrantLock 区别是什么?

1.ReentrantLock 显示的获得、释放锁,synchronized 隐式获得释放锁

2.ReentrantLock 可响应中断、可轮回,synchronized ...

3.ReentrantLock 是 API 级别的,synchronized 是 JVM ...

4.ReentrantLock 可以实现公平锁

5.ReentrantLock 通过 Condition 可以绑定多个条件

56. 说一下 atomic 的原理?

JDK Atomic开头的类,是通过 CAS 原理解决并发情况下原子性问题。

CAS 包含 3 个参数,CAS(V, E, N)。V 表示需要更新的变量,E 表示变量当前期望值,N 表示更新为的值。只有当变量 V 的值等于 E 时,变量 V 的值才会被更新为 N。如果变量 V 的值不等于 E ,说明变量 V 的值已经被更新过,当前线程什么也不做,返回更新失败。

当多个线程同时使用 CAS 更新一个变量时,只有一个线程可以更新成功,其他都失败。失败的线程不会被挂起,可以继续重试 CAS,也可以放弃操作。

CAS 操作的原子性是通过 CPU 单条指令完成而保障的。JDK 中是通过 Unsafe 类中的 API 完成的。

在并发量很高的情况,会有大量 CAS 更新失败,所以需要慎用。

56.什么是反射?

 JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法,对于任意一个对象,都能够调用它的任意一个方法和属性,这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。

57.什么是 Java 序列化?什么情况下需要序列化?

序列化:将 Java 对象转换成字节流的过程。

反序列化:将字节流转换成 Java 对象的过程。当 Java 对象需要在网络上传输 或者 持久化存储到文件中时,就需要对 Java 对象进行序列化处理

58.动态代理是什么?有哪些应用?

动态代理:在运行时,创建目标类,可以调用和扩展目标类的方法。

应用场景如:

统计每个 api 的请求耗时

统一的日志输出

校验被调用的 api 是否已经登录和权限鉴定

Spring的 AOP 功能模块就是采用动态代理的机制来实现切面编程

60. 怎么实现动态代理?

一种是利用JDK反射机制生成代理,另外一种是使用CGLIB代理

61. 为什么要使用克隆?

克隆的对象可能包含一些已经修改过的属性,而new出来的对象的属性都还是初始化时候的值,所以当需要一个新的对象来保存当前对象的“状态”就靠clone方法了

62. 如何实现对象克隆?

1). 实现Cloneable接口并重写Object类中的clone()方法;

2). 实现Serializable接口,通过对象的序列化和反序列化实现克隆,可以实现真正的深度克隆,

63.深拷贝和浅拷贝区别是什么?

浅拷贝可以使用列表自带的copy()函数(如list.copy()),或者使用copy模块的copy()函数。深拷贝只能使用copy模块的deepcopy()

Java Web

64.JSP 和 servlet 有什么区别?

Servlet

·一种服务器端的Java应用程序

·由 Web 容器加载和管理

·用于生成动态 Web 内容

·负责处理客户端请求     

Jsp

·是 Servlet 的扩展,本质上还是 Servlet

·每个 Jsp 页面就是一个 Servlet 实例

·Jsp 页面会被 Web 容器编译成 Servlet,Servlet 再负责响应用户请求

区别

·Servlet 适合动态输出 Web 数据和业务逻辑处理,对于 html 页面内容的修改非常不方便;Jsp 是在 Html 代码中嵌入 Java 代码,适合页面的显示

·内置对象不同,获取内置对象的方式不同

65.JSP 有哪些内置对象?作用分别是什么?

1.HttpServletRequet类的Request对象:代表请求对象,主要用于接受客户端通过HTTP协议连接传输服务器端的数据。

2.HttpSevletResponse类的Response对象:代表响应对象,主要用于向客户端发送数据。

3.JspWriter类的out对象:主要用于向客户端输出数据,out的基类是jspWriter

4.HttpSession类的session对象:主要用来分别保存每个月的信息与请求关联的会话;会话状态的维持是web应用开发者必须面对的问题。

5.ServletContext类的application对象:主要用于保存用户信息,代码片段的运行环境;它是一个共享的内置对象,即一个容器中的多个用户共享一个application

,故其保存的信息被所有用户所共享。

6.PageContext类的PageContext对象:管理网页属性,为jsp页面包装页面的上下文,管理对属于jsp的特殊可见部分中已经命名对象的访问,它的创建和初始化都是由容器来完成的。

7.ServletConfig类的Config对象:代码片段配置对象,标识Servlet的配置。

8.Object类的Page对象,处理jsp页面,是object类的一个实例,指的是jsp实现类的实例

9.Exception对象:处理jsp文件执行时发生的错误和异常,只有在错误页面里才使用,前提是在页面指令里要有isErrorPage=true。

66.说一下 JSP 的 4 种作用域?

作用域 名称 描述

page 当前页面作用域 相当于 Java 关键字中 this。在这个作用域中存放的属性值,只能在当前页面中取出。

request 请求作用域     范围是从请求创建到请求消亡这段时间,一个请求可以涉及的多个页面。

<jsp:forward>和<jsp:include>跳转到其他页面,也在作用域范围。

session 会话作用域     范围是一段客户端和服务端持续连接的时间,用户在会话有效期内多次请求所涉及的页面。

seesion会话器,服务端为第一次建立连接的客户端分配一段有效期内的属性内存空间。

application 全局作用域     范围是服务端Web应用启动到停止,整个Web应用中所有请求所涉及的页面。

当服务器开启时,会创建一个公共内存区域,任何客户端都可以在这个公共内存区域存取值。

67.session 和 cookie 有什么区别?

区别 Cookie session

存储位置 存端浏览器 存放在服务器

存储容量 单个4kb,最多存20个 没有上限

存储方式 只能保管ASCII字符串 存储任何类型

隐私策略不同 可见 存储在服务器上,对客户端是透明

有效期上 通过设置 只需关闭窗口会失效

服务器压力 不占用服务器资源 占用

浏览器支持 需要客户端浏览器支持 本窗口以及子窗口内

跨域支持上 支持 不支持

68.说一下 session 的工作原理?

1.用户第一次请求服务器时,服务器端会生成一个sessionid

2.服务器端将生成的sessionid返回给客户端,通过set-cookie

3.客户端收到sessionid会将它保存在cookie中,当客户端再次访问服务端时会带上这个sessionid

4.当服务端再次接收到来自客户端的请求时,会先去检查是否存在sessionid,不存在就新建一个sessionid重复1,2的流程,如果存在就去遍历服务端的session文件,找到与这个sessionid相对应的文件,文件中的键值便是sessionid,值为当前用户的一些信息

5.此后的请求都会交换这个 Session ID,进行有状态的会话。

69. 如果客户端禁止 cookie 能实现 session 还能用吗?

当然--------不能用了

因为服务端是根据session的id来确定当前对话所对应的的服务器,而session id 是通过cookie来传递的,禁用cookie相当于失去了sessionID,也就得不到session了。

69.spring mvc 和 struts 的区别是什么?

1.Struts是类级别的拦截,SpringMVC是方法级别的拦截

2.SpringMVC更适合更容易实现REST风格

3.SpringMVC的方法之间基本上独立的,独享request和response数据,请求数据通过参数获取,处理结果通过ModelMap交回给框架,方法之间不共享变量。

而Struts2虽然方法之间也是独立的,但其所有Action变量是共享的,这不会影响程序运行,却给我们编码读程序时带来麻烦。

70.如何避免 SQL 注入?

1.永远不要信任用户的输入。对用户的输入进行校验,可以通过正则表达式,或限制长度;对单引号和双"-"进行转换等。 

2.永远不要使用动态拼装sql,可以使用参数化的sql或者直接使用存储过程进行数据查询存取。 

3.永远不要使用管理员权限的数据库连接,为每个应用使用单独的权限有限的数据库连接。 

4.不要把机密信息直接存放,加密或者hash掉密码和敏感的信息。 

5.应用的异常信息应该给出尽可能少的提示,最好使用自定义的错误信息对原始错误信息进行包装。 

·严格限制 Web 应用的数据库的操作权限,给连接数据库的用户提供满足需要的最低权限,最大限度的减少注入攻击对数据库的危害

·校验参数的数据格式是否合法(可以使用正则或特殊字符的判断)

·对进入数据库的特殊字符进行转义处理,或编码转换

·预编译 SQL(Java 中使用 PreparedStatement),参数化查询方式,避免 SQL 拼接

·发布前,利用工具进行 SQL 注入检测

·报错信息不要包含 SQL 信息输出到 Web 页面

71.什么是 XSS 攻击,如何避免?

XSS 攻击,即跨站脚本攻击(Cross Site Scripting),它是 web 程序中常见的漏洞。

对输入(和URL参数)进行过滤,对输出进行编码;白名单和黑名单结合

73. 什么是 CSRF 攻击,如何避免?

跨站请求伪造是一种挟制用户在当前已登录的Web应用程序上执行非本意的操作的攻击方法。跟跨网站脚本(XSS)相比,XSS 利用的是用户对指定网站的信任,CSRF 利用的是网站对用户网页浏览器的信任

防御措施

检查Referer字段

添加校验token

异常

74.throw 和 throws 的区别?

区别一:throw 是语句抛出一个异常;throws 是方法抛出一个异常;

区别二:throws可以单独使用,但throw不能;

区别三:throw要么和try-catch-finally语句配套使用,要么与throws配套使用。但throws可以单独使用,然后再由处理异常的方法捕获。

75.final、finally、finalize 有什么区别?

·final 表示最终的、不可改变的。用于修饰类、方法和变量。

·finally 异常处理的一部分,它只能用在try/catch语句中,表示希望finally语句块中的代码最后一定被执行(但是不一定会被执行)

·finalize()是在java.lang.Object里定义的,Object的finalize方法什么都不做,对象被回收时finalized方法会被调用。

    特殊情况下,可重写finalize方法,当对象被回收的时候释放一些资源。但注意,要调用super.finalize()。

finalize是在Object类中定义的,因此,所有的类都继承了它。子类可以覆盖finalize()方法,来整理系统资源或者执行其他清理工作。

76. try-catch-finally 中哪个部分可以省略?

三种情况都是可以的:

try-catch

try-finally

try-catch-finally

可以省略catch或者finally。catch和finally不可以同时省略。

76.try-catch-finally 中,如果 catch 中 return 了,finally 还会执行吗?

1)finally的作用就是,无论出现什么状况,finally里的代码一定会被执行。

(2)如果在catch中return了,也会在return之前,先执行finally代码块。

(3)而且如果finally代码块中含有return语句,会覆盖其他地方的return。

(4)对于基本数据类型的数据,在finally块中改变return的值对返回值没有影响,而对引用数据类型的数据会有影响。

注:

finally也不是一定会被执行,如果在try代码块中,System.exit()强制退出程序,或者在执行try代码块中报错抛出异常(例如5/0),finally代码块就不会执行了。

77.常见的异常类有哪些?

算术异常类:ArithmeticExecption

空指针异常类:NullPointerException

类型强制转换异常:ClassCastException

数组负下标异常:NegativeArrayException

数组下标越界异常:ArrayIndexOutOfBoundsException

违背安全原则异常:SecturityException

文件已结束异常:EOFException

文件未找到异常:FileNotFoundException

字符串转换为数字异常:NumberFormatException

操作数据库异常:SQLException

输入输出异常:IOException

方法未找到异常:NoSuchMethodException

java.lang.AbstractMethodError

抽象方法错误。当应用试图调用抽象方法时抛出。

java.lang.AssertionError

网络

79. http 响应码 301 和 302 代表的是什么?有什么区别?

·301 表示被请求 url 永久转移到新的 url;302 表示被请求 url 临时转移到新的 url。

·301 搜索引擎会索引新 url 和新 url 页面的内容;302 搜索引擎可能会索引旧 url 和 新 url 的页面内容。

80. forward 和 redirect 的区别?

forward又叫转发,redirect叫做重定向

1、请求方不同

redirect:客户端发起的请求

forward:服务端发起的请求

2、浏览器bai地址表现不同

redirect:浏览器地址显示被请求的

urlforward:浏览器地址不显示被请求的url

81. 简述 tcp 和 udp的区别?

TCP与UDP的区别:

1.基于连接与无连接;

2.对系统资源的要求(TCP较多,UDP少);

3.UDP程序结构较简单;

4.流模式与数据报模式 ;

5.TCP保证数据正确性,UDP可能丢包,TCP保证数据顺序,UDP不保证。

tcp协议和udp协议的差别

           TCP           UDP

是否连接     面向连接     面向非连接

传输可靠性   可靠        不可靠

应用场合    少量数据    传输大量数据

速度       慢         快

82.tcp 为什么要三次握手,两次不行吗?为什么?

两次握手只能保证单向连接是畅通的

只有经过第三次握手,才能确保双向都可以接收到对方的发送的 数据

SYN - 创建一个连接FIN - 终结一个连接

ACK - 确认接收到的数据

83.说一下 tcp 粘包是怎么产生的?

发送端粘包:发送端需要等缓冲区满才发送出去,造成粘包; 接收方粘包:接收方不及时接收缓冲区的包,造成多个包接收。

1、什么是 tcp 粘包?

发送方发送的多个数据包,到接收方缓冲区首尾相连,粘成一包,被接收。

2、原因

TCP 协议默认使用 Nagle 算法可能会把多个数据包一次发送到接收方。

应用程读取缓存中的数据包的速度小于接收数据包的速度,缓存中的多个数据包会被应用程序当成一个包一次读取。

3、处理方法

发送方使用 TCP_NODELAY 选项来关闭 Nagle 算法

数据包增加开始符和结束,应用程序读取、区分数据包。

在数据包的头部定义整个数据包的长度,应用程序先读取数据包的长度,然后读取整个长度的包字节数据,保证读取的是单个包且完整。

84.OSI 的七层模型都有哪些?

1、应用层协议:

HTTP、FTP、TFTP、SMTP、SNMP、DNS、TELNET、HTTPS、POP3、DHCP等;

2、表示层不需要协议;

3、会话层不需要协议;

4、传输层协议:

TCP、UDP、DCCP、SCTP、RTP、RSVP、PPTP等; 

5、网络层协议:

ICMP、IGMP、IP(IPV4 IPV6)、ARP、RARP等;

6、数据链路层协议:

802.11、802.16、Wi-Fi、WiMAX、ATM、DTM、GPRS、EVDO、HSPA等;

7、物理层协议:

FTP、Telnet、SMTP、SNTP、REXEC、TFTP、LPD、SNMP、NFS、INETD等 。

85.get 和 post 请求有哪些区别?

1.get是从服务器上获取数据,post是向服务器传送数据。

2.get是把参数数据队列加到提交表单的ACTION属性所指的URL中,值和表单内各个字段一一对应,在URL中可以看到。post是通过HTTPpost机制

,将表单内各个字段与其内容放置在HTML HEADER内一起传送到ACTION属性所指的URL地址。用户看不到这个过程。

3.对于get方式,服务器端用Request.QueryString获取变量的值,对于post方式,服务器端用Request.Form获取提交的数据。

4.get传送的数据量较小,不能大于2KB。post传送的数据量较大,一般被默认为不受限制。但理论上,IIS4中最大量为80KB,IIS5中为100KB。

5.get安全性非常低,post安全性较高。

86.如何实现跨域?

跨域:是指浏览器不能执行其他网站的脚本。它是由浏览器的同源策略造成的,是浏览器对JavaScript实施的安全限制。

1 通过jsonp跨域(缺点:只能实现get 一种请求)

2document.domain+iframe 跨域

3location.hash+iframe

4windows.name+iframe跨域

5postMessage 跨域

6跨域资源共享CORS

7nginx代理跨域

8nodejs 中间件代理跨域

9webSocket协议跨域

87.说一下 JSONP 实现原理?

1 首先是利用script 标签的src属性来实现跨域

2通过将前端方法作为参数据传递到服务器端,然后由服务器端注入参数之后再返回,实现服务器端向客户端通信

3由于使用script 标签的src 属性,因此只支持get方法

设计模式

88. 说一下你熟悉的设计模式?

三大工厂模式的代码实现(简单工厂模式、工厂方法模式、抽象工厂模式)

89. 简单工厂和抽象工厂有什么区别?

·简单工厂模式

是由一个工厂对象创建产品实例,简单工厂模式的工厂类一般是使用静态方法,通过不同的参数的创建不同的对象实例

可以生产结构中的任意产品,不能增加新的产品

·抽象工厂模式

提供一个创建一系列相关或相互依赖对象的接口,而无需制定他们具体的类,生产多个系列产品

生产不同产品族的全部产品,不能新增产品,可以新增产品族

Spring/Spring MVC

90.为什么要使用 spring?

spring 是一个开源的轻量级 JavaBean 容器框架。使用 JavaBean 代替 EJB ,并提供了丰富的企业应用功能,降低应用开发的复杂性。

·轻量:非入侵性的、所依赖的东西少、资源占用少、部署简单,不同功能选择不同的 jar 组合

·容器:工厂模式实现对 JavaBean 进行管理,通过控制反转(IOC)将应用程序的配置和依赖性与应用代码分开

·松耦合:通过 xml 配置或注解即可完成 bean 的依赖注入

·AOP:通过 xml 配置 或注解即可加入面向切面编程的能力,完成切面功能,如:日志,事务...的统一处理

·方便集成:通过配置和简单的对象注入即可集成其他框架,如 Mybatis、Hibernate、Shiro...

·丰富的功能:JDBC 层抽象、事务管理、MVC、Java Mail、任务调度、JMX、JMS、JNDI、EJB、动态语言、远程访问、Web Service... 

91. 解释一下什么是 aop?

面向切面编程 为软件横向扩展功能 。AOP解决了OOP中遇到的一些问题,是OOP的延续和扩展。

AOP就是在某一个类或方法执行前后打个标记,声明在执行到这里之前要先执行什么,执行完这里之后要接着执行什么。插入了新的执行方法。

核心原理:

使用动态代理的方式在执行方法前后或者出现异常的时候做加入相关的逻辑

事务处理:执行方法前,开启事务,执行完成后关闭事务,出现异常后回滚事务

2.权限判断:在执行方法前,判断是否具有权限

3.日志:在执行前进行日志处理

aop 是面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。 简单来说就是统一处理某一“切面”(类)的问题的编程思想,比如统一处理日志、异常等。

AOP的设计理念可以说是代理模式的一种体现,在不修改源代码的前提下,可以进行一定的功能扩展。

AOP在具体的实践中,主要应用于非需求功能性的扩展,例如日志、性能统计、安全控制、事务处理、异常处理等方面的功能扩展。在需求功能的扩展上来说,AOP的作用是有限的。因为需求功能的扩展,往往要修改大量的业务逻辑。

AOP在Spring中可以说是被用到了极致。除了我们提到的前置、后置切面插入。还可以在抛出异常时,进行切面插入,也可以在返回语句执行前,进行切面插入。

Spring的AOP实际上就是拦截器。从使用角度上来说,AOP的确与拦截器很相似,抛开Spring说AOP是拦截器,这没什么太大的问题,但如果在Spring的环境下说AOP是拦截器,并不十分准确,主要原因是拦截器和AOP拦截的细粒度是不同的,例如还有拦截颗粒度更大的过滤器,它们在行为上都有相似之处

AOP:AOP比拦截器的细粒度更小,它可以到达语句级别,例如可以在异常、返回语句切面处进行处理。Spring的AOP实践中,也围绕这事物、性能、异常、日志、数据库事务等非需求功能展开设计。实际上,这也是AOP所局限的地方,毕竟业务的扩展是无法预估的。

91.解释一下什么是 ioc?

IOC:控制反转,把对象创建交给Spring进行配置。

依赖注入不能单独存在,需要在lOC基础之上完成操作

93. spring 有哪些主要模块?

1. Spring Core

框架的最基础部分,提供 IoC 容器,对 bean 进行管理。

2.Spring Context

基于 bean,提供上下文信息,扩展出JNDI、EJB、电子邮件、国际化、校验和调度等功能。

3.Spring DAO

提供了JDBC的抽象层,它可消除冗长的JDBC编码和解析数据库厂商特有的错误代码,还提供了声明性事务管理方法。

4.Spring ORM

提供了常用的“对象/关系”映射APIs的集成层。 其中包括JPA、JDO、Hibernate、MyBatis 等。

5.Spring AOP

提供了符合AOP Alliance规范的面向方面的编程实现。

6.Spring Web

提供了基础的 Web 开发的上下文信息,可与其他 web 进行集成。

7.Spring Web MVC

提供了 Web 应用的 Model-View-Controller 全功能实现。

94.spring 常用的注入方式有哪些?

1.setter 属性注入

2.构造方法注入

3.注解方式注入

95. spring 中的 bean 是线程安全的吗?

通常来说是不安全的!

bean的scope属性可以配置bean是单例还是每次请求都new一个bean,如果每次请求都返回新的bean的话就是安全的,但是通常情况下,绝大多数bean都是单例bean。

但是单例bean也不表示就一定线程不安全,这要看bean中有没有多线程共享变量。如果都是线程私有数据,那也是线程安全的,反之就是不安全的!

95.spring 支持几种 bean 的作用域?

(1)singleton:默认,每个容器中只有一个bean的实例,单例的模式由BeanFactory自身来维护。

(2)prototype:为每一个bean请求提供一个实例。

(3)request:为每一个网络请求创建一个实例,在请求完成以后,bean会失效并被垃圾回收器回收。

(4)session:与request范围类似,确保每个session中有一个bean的实例,在session过期后,bean会随之失效。

(5)global-session:全局作用域,global-session和Portlet应用相关。当你的应用部署在Portlet容器中工作时,它包含很多portlet。如果你想要声明让所有的portlet共用全局的存储变量的话,那么这全局变量需要存储在global-session中。全局作用域与Servlet中的session作用域效果相同。

96.spring 自动装配 bean 有哪些方式?

no:默认值,表示没有自动装配,应使用显式 bean 引用进行装配。

byName:它根据 bean 的名称注入对象依赖项。

byType:它根据类型注入对象依赖项。 构造函数:通过构造函数来注入依赖项,需要设置大量的参数。

autodetect:容器首先通过构造函数使用 autowire 装配,如果不能,则通过 byType 自动装配。

97.spring 事务实现方式有哪些?

1.aspectJ AOP实现事务

2.事务代理工厂Bean实现事务

3.注解方式实现事务

99. 说一下 spring 的事务隔离?

spring 有五大隔离级别,默认值为 ISOLATION_DEFAULT(使用数据库的设置),其他四个隔离级别和数据库的隔离级别一致 (越往下隔离级别越高,花费越大):

read uncommited 未提交读:是最低的事务隔离级别。事务未提交前,数据就可被其他事务读取 --> 会造成:脏读、不可重复读、幻读

read commited 提交读:一个事务提交后才能被其他事务读取到,SQL server 的默认级别 --> 会造成:不可重复读、幻读

repeatable read 可重复读:保证多次读取同一个数据时,其值都和事务开始时候的内容是一致,禁止读取到别的事务未提交的数据,MySQL 的默认级别 --> 会造成: 幻读。

serializable 序列化:这是花费最高代价但最可靠的事务隔离级别。事务被处理为顺序执行。该隔离级别能防止脏读、不可重复读、幻读。

100. 说一下 spring mvc 运行流程?

核心控制器捕获请求、查找Handler、执行Handler、选择ViewResolver,通过ViewResolver渲染视图并返回

101. spring mvc 有哪些组件?

·前端控制器(DispatcherServlet) 

·处理器映射器(HandlerMapping) 

·处理器适配器(HandlerAdapter) 

·拦截器(HandlerInterceptor)

·语言环境处理器(LocaleResolver)

·主题解析器(ThemeResolver)

·视图解析器(ViewResolver) 

·文件上传处理器(MultipartResolver)

·异常处理器(HandlerExceptionResolver) 

·数据转换(DataBinder)

·消息转换器(HttpMessageConverter)

·请求转视图翻译器(RequestToViewNameTranslator)

·页面跳转参数管理器(FlashMapManager)

·处理程序执行链(HandlerExecutionChain) 

102. @RequestMapping 的作用是什么?

@RequestMapping 是一个注解,用来标识 http 请求地址与 Controller 类的方法之间的映射。

103.@Autowired 的作用是什么?

@Autowired 是一个注释,它可以对类成员变量、方法及构造函数进行标注,让 spring 完成 bean 自动装配的工作

Spring Boot/Spring Cloud

104.什么是 spring boot?

从本质上来说,Spring Boot就是Spring,它做了那些没有它你也会去做的Spring Bean配置。

Spring Boot作为一个微框架,离微服务的实现还是有距离的

Spring Boot可以帮助我们以最少的工作量,更加健壮地使用现有的Spring功能

105. 为什么要用 spring boot?

(1) Spring Boot使编码变简单

(2) Spring Boot使配置变简单

(3) Spring Boot使部署变简单

(4) Spring Boot使监控变简单

(5) 弥补了Spring的不足

SpringBoot的缺点

·SpringBoot仅适用于全新Spring项目。

·集成度较高,使用过程中不太容易了解底层。

106. spring boot 核心配置文件是什么?

Spring Boot 有两种类型的配置文件,application 和 bootstrap 文件

Spring Boot会自动加载classpath目前下的这两个文件,文件格式为 properties 或 yml 格式

107. spring boot 配置文件有哪几种类型?它们有什么区别?

  .properties 和 .yml,它们的区别主要是书写格式不同。

    1).properties

    app.user.name = javastack

    2).yml

    app:

      user:

    name: javastack

    另外,.yml 格式不支持 @PropertySource 注解导入配置。

108. spring boot 有哪些方式可以实现热部署?

·Spring Loaded

·spring-boot-devtools

·JRebel插件 

109. jpa 和 hibernate 有什么区别?

JPA和Hibernate之间的主要区别在于JPA是一个规范。 Hibernate是Red Hat对JPA规范的实现。

110.什么是 spring cloud?

Spring Cloud是一个微服务框架,相比Dubbo等RPC框架,Spring Cloud提供的全套的分布式系统解决方案

  Spring Cloud对微服务基础框架Netflix的多个开源组件进行了封装,同时又实现了和云端平台以及和Spring Boot开发框架的集成。 

      Spring Cloud为微服务架构开发涉及的配置管理,服务治理,熔断机制,智能路由,微代理,控制总线,一次性token,全局一致性锁,leader选举,分布式session,集群状态管理等操作提供了一种简单的开发方式。

      Spring Cloud 为开发者提供了快速构建分布式系统的工具,开发者可以快速的启动服务或构建应用、同时能够快速和云平台资源进行对接。   

111. spring cloud 断路器的作用是什么?

在分布式架构中,断路器模式的作用也是类似的,当某个服务单元发生故障(类似用电器发生短路)之后,通过断路器的故障监控(类似熔断保险丝),向调用方返回一个错误响应,而不是长时间的等待。这样就不会使得线程因调用故障服务被长时间占用不释放,避免了故障在分布式系统中的蔓延。

112. spring cloud 的核心组件有哪些?

Eureka:服务注册于发现。

Feign:基于动态代理机制,根据注解和选择的机器,拼接请求 url 地址,发起请求。

Ribbon:实现负载均衡,从一个服务的多台机器中选择一台。

Hystrix:提供线程池,不同的服务走不同的线程池,实现了不同服务调用的隔离,避免了服务雪崩的问题。

Zuul:网关管理,由 Zuul 网关转发请求给对应的服务。

Hibernate

113.为什么要使用 hibernate?

Hibernate是一个开放源代码的对象关系映射(ORM)框架,它对JDBC进行了非常轻量级的对象封装,使得Java程序员可以随心所欲的使用对象编程思维来操纵数据库。

114. 什么是 ORM 框架?

对象关系映射

即通过类与数据库表的映射关系,将对象持久化到数据库中,

115. hibernate 中如何在控制台查看打印的 SQL 语句?

使用Hibernate提供的内置属性true只能输出类似于下面的SQL语句 p6spy

116. hibernate 有几种查询方式?

1 HQL(Hibernate Query Language)

与所熟悉的SQL的语法差不太多,不同的就是把表名换成了类或者对象

2 SQL

3QBC

117. hibernate 实体类可以被定义为 final 吗?

是的,你可以将Hibernate的实体类定义为final类,但这种做法并不好

118. 在 hibernate 中使用 Integer 和 int 做映射有什么区别?

1、返回数据库字段值是null的话,int类型会报错。int是基本数据类型,其声明的是变量,而null则是对象。所以hibernate实体建议用integer;

2、通过jdbc将实体存储到数据库的操作通过sql语句,基本数据类型可以直接存储,对象需要序列化存储。

119. hibernate 是如何工作的?

1.读取并解析配置

2.读取并解析映射信息,创建Session Factory

3.打开Session

4.创建事务Transation

5.持久化操作

6.提交事务

7.关闭Session

8.关闭SesstionFactory

120.get()和 load()的区别?

load()没有使用对象的其他属性的时候,没有SQL  延迟加载

get() :没有使用对象的其他属性的时候,也生成了SQL  立即加载

121. 说一下 hibernate 的缓存机制?

Hibernate中的缓存分一级缓存和二级缓存。

一级缓存就是  Session 级别的缓存,在事务范围内有效是,内置的不能被卸载。

二级缓存是 SesionFactory级别的缓存,从应用启动到应用结束有效。是可选的,默认没有二级缓存,需要手动开启。保存数据库后,缓存在内存中保存一份,如果更新了数据库就要同步更新。

什么样的数据适合存放到第二级缓存中?

1)很少被修改的数据   帖子的最后回复时间

2)经常被查询的数据   电商的地点

2)  不是很重要的数据,允许出现偶尔并发的数据

3)  不会被并发访问的数据

4)  常量数据

扩展:hibernate的二级缓存默认是不支持分布式缓存的。使用  memcahe,redis等中央缓存来代替二级缓存

122. hibernate 对象有哪些状态?

hibernate里对象有三种状态:

1,Transient 瞬时 :对象刚new出来,还没设id,设了其他值。

2,Persistent 持久:调用了save()、saveOrUpdate(),就变成Persistent,有id

3,Detached  脱管 : 当session  close()完之后,变成Detached

123. 在 hibernate 中 getCurrentSession 和 openSession 的区别是什么?

1. openSession 从字面上可以看得出来,是打开一个新的session对象,而且每次使用都是打开一个新的session,假如连续使用多次,则获得的session不是同一个对象,并且使用完需要调用close方法关闭session。

2. getCurrentSession ,从字面上可以看得出来,是获取当前上下文一个session对象,当第一次使用此方法时,会自动产生一个session对象,并且连续使用多次时,得到的session都是同一个对象,这就是与openSession的区别之一,简单而言,getCurrentSession 就是:如果有已经使用的,用旧的,如果没有,建新的。

124. hibernate 实体类必须要有无参构造函数吗?为什么?

 每个Hibernate实体类必须包含一个无参数的构造器, 这是因为 Hibernate框架要使用Reflection API,通过调用Class.newInstance()来创建这些实体类的实例。如果在实体类中找不到无参数的构造器,这个方法就会抛出一个InstantiationException异常。

MyBatis

125. MyBatis 中 #{}和 ${}的区别是什么?

#{}是预编译处理,${}是字符串替换;

Mybatis在处理#{}时,会将sql中的#{}替换为?号,调用PreparedStatement的set方法来赋值;

Mybatis在处理${}时,就是把sql中的${}替换成变量的值;

使用#{}可以有效的防止SQL注入,提高系统安全性。

126.MyBatis 有几种分页方式?

1  数组分页

2  sql分页

3  拦截器分页

4  RowBounds分页

127.RowBounds 是一次性查询全部结果吗?为什么?

RowBounds 表面是在“所有”数据中检索数据,其实并非是一次性查询出所有数据,因为 MyBatis 是对 jdbc 的封装,在 jdbc 驱动中有一个 Fetch Size 的配置,它规定了每次最多从数据库查询多少条数据,假如你要查询更多数据,它会在你执行 next()的时候,去查询更多的数据

128. MyBatis 逻辑分页和物理分页的区别是什么?

 1:逻辑分页 内存开销比较大,在数据量比较小的情况下效率比物理分页高;在数据量很大的情况下,内存开销过大,容易内存溢出,不建议使用

    2:物理分页 内存开销比较小,在数据量比较小的情况下效率比逻辑分页还是低,在数据量很大的情况下,建议使用物理分页

物理分页速度上并不一定快于逻辑分页,

逻辑分页速度上也并不一定快于物理分页。

物理分页总是优于逻辑分页:没有必要将属于数据库端的压力加诸到应用端来,

就算速度上存在优势,然而其它性能上的优点足以弥补这个缺点。

129. MyBatis 是否支持延迟加载?延迟加载的原理是什么?

mybatis支持延迟加载

适用场景

一对一,多对一   立即加载

一对多,多对多   延迟加载

130. 说一下 MyBatis 的一级缓存和二级缓存?

一级缓存

    一级缓存也叫sqlSession级别的缓存 ,也就是在同一个sqlSession内执行两次多次相同结果的查询语句,

    只会在第一次时发出sql查询数据库的数据,然后之后每次从一级缓存中查询数据返回。

二级缓存

是mapper级别的缓存,也就是多个sqlSession之间可以实现数据的共享。

二级缓存默认是不开启,所以在使用二级缓存时需要在做以下配置

131. MyBatis 和 hibernate 的区别有哪些?

1 mybatis 和 hibernate不同,它不完全是一个ORM框架,因为myBatis 需要程序员自己编写SQL语句

2Mybatis直接编写原生态sql 可以严格控制sql执行性能,灵活度高

3hibernate对象/关系映射能力强,数据库无关性能。

132. MyBatis 有哪些执行器(Executor)?

SimpleExecutor:每执行一次update或select,就开启一个Statement对象,用完立刻关闭Statement对象。

ReuseExecutor:执行update或select,以sql作为key查找Statement对象,存在就使用,不存在就创建,用完后,不关闭Statement对象,而是放置于Map内,供下一次使用。简言之,就是重复使用Statement对象。

BatchExecutor:执行update(没有select,JDBC批处理不支持select),将所有sql都添加到批处理中(addBatch()),等待统一执行(executeBatch()),它缓存了多个Statement对象,每个Statement对象都是addBatch()完毕后,等待逐一执行executeBatch()批处理。与JDBC批处理相同。

作用范围:Executor的这些特点,都严格限制在SqlSession生命周期范围内。

133. MyBatis 分页插件的实现原理是什么?

分页插件的基本原理是使用MyBatis 提供的插件接口,实现自定义插件,在插件的拦截方法内拦截待执行的sql,然后重写sql ,添加对应的物理分页语句和物理分页参数

134.MyBatis 如何编写一个自定义插件?

MyBatis 自定义插件针对 MyBatis 四大对象(Executor,StatementHandler,ParamentHandler,ResultSetHandler)进行拦截。

Executor  :拦截内部执行器,它负责调用StatementHandler 操作数据库,并把结果集通过 ResultSetHandler 进行自动映射,另外它还处理了二级缓存的操作。

StatementHandler  :拦截 SQL 语法构建的处理,它是MyBatis 直接和数据库执行 SQL脚本的对象,另外它也实现了 MyBatis一级缓存

ParamenterHandler  :拦截参数的处理。

ResultSetHandler  :拦截结果集的处理。

RabbitMQ

135.RabbitMQ 的使用场景有哪些?

(1)服务间异步通信

(2)顺序消费

(3)定时任务

(4)请求削峰

场景1:单发送单接收

使用场景:简单的发送与接收,没有特别的处理

场景2:单发送多接收

使用场景:一个发送端,多个接收端,如分布式的任务派发。为了保证消息发送的可靠性,不丢失消息,使消息持久化了。同时为了防止接收端在处理消息时down掉,只有在消息处理完成后才发送ack消息。

场景3:Publish/Subscribe

使用场景:发布、订阅模式,发送端发送广播消息,多个接收端接收。

场景4:Routing (按路线发送接收)

使用场景:发送端按routing key发送消息,不同的接收端按不同的routing key接收消息。

场景5:Topics (按topic发送接收)

使用场景:发送端不只按固定的routing key发送消息,而是按字符串“匹配”发送,接收端同样如此。

136. RabbitMQ 有哪些重要的角色?

生产者:消息的创建者,负责创建和推送数据到消息服务器

消费者:消息的接收方,用于处理数据和确认消息

代理:就是RabbitMQ本身,用于扮演快递的角色,本身并不生产消息

137. RabbitMQ 有哪些重要的组件?

ConnectionFactory(连接管理器):应用程序与RabbitMQ之间建立连接的管理器

Channel(信道):消息推送使用的通道

Exchange(交换器):用于接受、分配消息

Queue(队列):用于存储生产者的消息

RoutingKey(路由键):用于把生产者的数据分配到交换器上

BindKey(绑定键):用于把交换器的消息绑定到队列上

138.RabbitMQ 中 vhost 的作用是什么?

Vhost 可以理解为虚拟broker 即mini-RabbitMQ server。其内部均含有独立的queue,exchange和binding 其拥有独立的权限系统,可以做到vhost范围的用户控制

RabbitMQ中创建一个用户时,用户通常会被指派给至少一个vhost,并且只能访问被指派vhost内的队列、交换器和绑定,vhost之间是绝对隔离的

139. RabbitMQ 的消息是怎么发送的?

首先客户端必须连接到 RabbitMQ 服务器才能发布和消费消息,客户端和 rabbit server 之间会创建一个 tcp 连接,一旦 tcp 打开并通过了认证(认证就是你发送给 rabbit 服务器的用户名和密码),你的客户端和 RabbitMQ 就创建了一条 amqp 信道(channel),信道是创建在“真实” tcp 上的虚拟连接,amqp 命令都是通过信道发送出去的,每个信道都会有一个唯一的 id,不论是发布消息,订阅队列都是通过这个信道完成的。

140. RabbitMQ 怎么保证消息的稳定性?

提供了事务的功能。

通过将 channel 设置为 confirm(确认)模式

141. RabbitMQ 怎么避免消息丢失?

消息持久化

ACK确认机制

设置集群镜像模式

消息补偿机制

142. 要保证消息持久化成功的条件有哪些?

声明队列必须设置持久化 durable 设置为 true.

消息推送投递模式必须设置持久化,deliveryMode 设置为 2(持久)。

消息已经到达持久化交换器。

消息已经到达持久化队列。

以上四个条件都满足才能保证消息持久化成功

143. RabbitMQ 持久化有什么缺点?

持久化的缺地就是降低了服务器的吞吐量,

因为使用的是磁盘而非内存存储,

从而降低了吞吐量。可尽量使用 ssd 硬盘来缓解吞吐量的问题。

144. RabbitMQ 有几种广播类型?

三种广播模式:

1 fanout: 所有bind到此exchange的queue都可以接收消息

         (纯广播,绑定到RabbitMQ的接受者都能收到消息);

2 direct: 通过routingKey和exchange决定的那个唯一的queue可以接收消息;

3 topic:  所有符合routingKey(此时可以是一个表达式)的routingKey所bind的queue可以接收消息;

145. RabbitMQ 怎么实现延迟消息队列?

通过消息过期后进入死信交换器,

再由交换器转发到延迟消费队列,实现延迟功能;

使用 RabbitMQ-delayed-message-exchange 插件实现延迟功能

146. RabbitMQ 集群有什么用?

高可用:某个服务器出现问题,整个 RabbitMQ 还可以继续使用;

高容量:集群可以承载更多的消息量。

147. RabbitMQ 节点的类型有哪些?

磁盘节点:消息会存储到磁盘。

内存节点:消息都存储在内存中,重启服务器消息丢失,性能高于磁盘类型

148. RabbitMQ 集群搭建需要注意哪些问题?

各节点之间使用“--link”连接,此属性不能忽略。

各节点使用的 erlang cookie 值必须相同,此值相当于“秘钥”的功能,用于各节点的认证。

整个集群中必须包含一个磁盘节点

149. RabbitMQ 每个节点是其他节点的完整拷贝吗?为什么?

不是,原因有以下两个:

存储空间的考虑:如果每个节点都拥有所有队列的完全拷贝,

这样新增节点不但没有新增存储空间,反而增加了更多的冗余数据;

性能的考虑:如果每条消息都需要完整拷贝到每一个集群节点,

那新增节点并没有提升处理消息的能力,最多是保持和单节点相同的性能甚至是更糟。

150. RabbitMQ 集群中唯一一个磁盘节点崩溃了会发生什么情况?

如果唯一磁盘的磁盘节点崩溃了,不能进行以下操作:

不能创建队列

不能创建交换器

不能创建绑定

不能添加用户

不能更改权限

不能添加和删除集群节点

唯一磁盘节点崩溃了,集群是可以保持运行的,但你不能更改任何东西

151. RabbitMQ 对集群节点停止顺序有要求吗?

RabbitMQ 对集群的停止的顺序是有要求的,

应该先关闭内存节点,最后再关闭磁盘节点。如果顺序恰好相反的话,可能会造成消息的丢失

Kafka

152. kafka 可以脱离 zookeeper 单独使用吗?为什么?

kafka 不能脱离 zookeeper 单独使用,

因为 kafka 使用 zookeeper 管理和协调 kafka 的节点服务器

153. kafka 有几种数据保留的策略?

kafka 有两种数据保存策略:

按照过期时间保留

按照存储的消息大小保留。

154. kafka 同时设置了 7 天和 10G 清除数据,到第五天的时候消息达到了 10G,这个时候 kafka 将如何处理?

这个时候 kafka 会执行数据清除工作,时间和大小不论那个满足条件,都会清空数据。

155. 什么情况会导致 kafka 运行变慢?

cpu 性能瓶颈

磁盘读写瓶颈

网络瓶颈

156. 使用 kafka 集群需要注意什么?

集群的数量不是越多越好,最好不要超过 7 个,因为节点越多,消息复制需要的时间就越长,整个群组的吞吐量就越低。 集群数量最好是单数,因为超过一半故障集群就不能用了,设置为单数容错率更高。

Zookeeper

157. zookeeper 是什么?

是一个分布式的,开放源码的分布式应用程序协调服务

它是一个为分布应用提供一致性服务的软件 功能包括:配置维护,域名服务,分布式同步行

158. zookeeper 都有哪些功能?

集群管理 主节点选举,分布式锁,命名服务

159. zookeeper 有几种部署模式?

单机,集群,伪集群

160. zookeeper 怎么保证主从节点的状态同步?

Zookeeper的核心是原子广播,这个机制保证了各个Server之间的同步。实现这个机制的协议叫做Zab协议。

Zab协议有两种模式,它们分别是恢复模式(选主)和广播模式(同步)。恢复模式:当服务启动或者在领导者崩溃后,Zab就进入了恢复模式,当领导者被选举出来,且大多数Server完成了和leader的状态同步以后,恢复模式就结束了

状态同步保证了leader和server具有相同的系统状态

161. 集群中为什么要有主节点?

在分布式环境中,有些业务逻辑只需要集群中的某一台机器进行执行,

其他的机器可以共享这个结果,这样可以大大减少重复计算,提高性能,所以就需要主节点

162. 集群中有 3 台服务器,其中一个节点宕机,这个时候 zookeeper 还可以使用吗?

可以继续使用,单数服务器只要没超过一半的服务器宕机就可以继续使用

163. 说一下 zookeeper 的通知机制?

客户端端会对某个 znode 建立一个 watcher 事件,

当该 znode 发生变化时,这些客户端会收到 zookeeper 的通知,

然后客户端可以根据 znode 变化来做出业务上的改变。

MySQL

164. 数据库的三范式是什么?

第一范式:原子性每列不可再拆分

第二范式:不产生局部依赖,每列都完全依赖于主键,一张表只描述一件事情

第三范式 不生产传递依赖,所有的列都直接依赖于主键,使用外键关联,外键都来源与其他表的主键

反三范式

反3NF:为了提高数据的性能,增加冗余字段,以便提高查询性能。

166. 如何获取当前数据库版本?

1 mysql -V; 2 mysql --version

167. 说一下 ACID 是什么?

Atomicity(原子性):一个事务(transaction)中的所有操作,或者全部完成,或者全部不完成,

不会结束在中间某个环节。事务在执行过程中发生错误,会被恢复(Rollback)到事务开始前的状态,

就像这个事务从来没有执行过一样。即,事务不可分割、不可约简。

Consistency(一致性):在事务开始之前和事务结束以后,数据库的完整性没有被破坏。

这表示写入的资料必须完全符合所有的预设约束、触发器、级联回滚等。

Isolation(隔离性):数据库允许多个并发事务同时对其数据进行读写和修改的能力,

隔离性可以防止多个事务并发执行时由于交叉执行而导致数据的不一致。事务隔离分为不同级别,

包括读未提交(Read uncommitted)、读提交(read committed)、

可重复读(repeatable read)和串行化(Serializable)。

Durability(持久性):事务处理结束后,对数据的修改就是永久的,即便系统故障也不会丢失

168. char 和 varchar 的区别是什么?

char(n) :固定长度类型

char 优点:效率高;缺点:占用空间;

适用场景:存储密码的 md5 值,固定长度的,使用 char 非常合适。

varchar(n) :可变长度,

169. float 和 double 的区别是什么?

float 最多可以存储 8 位的十进制数,并在内存中占 4 字节。

double 最可可以存储 16 位的十进制数,并在内存中占 8 字节。

170. MySQL 的内连接、左连接、右连接有什么区别?

内连接关键字:inner join;

左连接:left join;

右连接:right join。

内连接是把匹配的关联数据显示出来;

左连接是左边的表全部显示出来,右边的表显示出符合条件的数据;右连接正好相反

171. MySQL 索引是怎么实现的?

索引是满足某种特定查找算法的数据结构,而这些数据结构会以某种方式指向数据,从而实现高效查找数据

MySQL 中的索引,不同数据引擎实现有所不同,但目前主流的数据库引擎的索引都是B+树实同,B+树搜索效率,可以到达二分法的性能,

172. 怎么验证 MySQL 的索引是否满足需求?

使用 explain 查看SQL是如何执查询语句

EXPLAIN SELECT * FROM XXX WHERE ID=4

173.说一下数据库的事务隔离?

Read Uncommitted(读未提交) 事务可以看到和读取到其他未提交事务的执行结果,这样一个事务读取到另一个事务还有没提交的记录,就很可能造成脏读。

Read Committed(读已提交) 事务只能看见已经提交的事务所做的改变,但是这种隔离级别可能会导致不可重复读,因为同一事务的其他实例在该实例处理其间可能会有新的 commit,所以同一个查询操作执行两次或者多次的结果可能不一致。

Repeatable Read(可重复读) 事务的多个实例在并发读取数据时读到同样的数据行,这种隔离级别可能会导致出现幻读,比如当用户读取某一个范围的数据行时,这时候另一个事务在这个数据行范围内插入了新行,当用户再读取该范围的数据行时,会发现有新的 “幻影” 数据

Serializable(串行化) 通过在每个读的数据行上加共享锁,这时候事务就会有顺序的执行,这样事务之间就不会出现冲突了,幻读问题也就解决了,不过由于加了锁,就会出现锁竞争和等待获取锁的情况

174. 说一下 MySQL 常用的引擎?

InnoDB 引擎:InnoDB引擎提供了对数据库acid事件的支持,并且还提供了行级锁

InnoDB会在内存中建立缓冲池,用于缓冲数据和索引,该索引不支技全文搜索,它是不会保存表的行数据,所以当进行

select count(*) from table 指令的时候,需要进行扫描全表,由于锁的粒度小,写操作是不会锁定全表,所以在并发度较高的场景下使用会提升 效率

MyIASM 引擎:Mysql的默认引擎,但不提供事务的支持,也不支持行级锁和外键,因些当执行插入和更新语句时,既执行定操作的时候需要锁定个表,所以会导致效率会降低,不过和InnoDB不同的是,MyIASM引擎是保存了表的行数,于是当进行select count(*) from tables语句时,可以直接的读取已保存的值而不需要进行扫描全表,所以,如查表的读操作运运多于写操作,并且不需要事务的支持时,可以将MyIASM作为数据库引擎的首选。

175. 说一下 MySQL 的行锁和表锁?

MyISAM 只支持表锁,InnoDB 支持表锁和行锁,默认为行锁。

表级锁:开销小,加锁快,不会出现死锁。锁定粒度大,发生锁冲突的概率最高,并发量最低。

行级锁:开销大,加锁慢,会出现死锁。锁力度小,发生锁冲突的概率小,并发度最高。

176. 说一下乐观锁和悲观锁?

乐观锁:每次去拿数据的时候都认为别人不会修改,所以不会上锁,

       但是在提交更新的时候会判断一下在此期间别人有没有去更新这个数据。

悲观锁:每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁,

       这样别人想拿这个数据就会阻止,直到这个锁被释放。

数据库的乐观锁需要自己实现,在表里面添加一个 version 字段,每次修改成功值加 1,

这样每次修改的时候先对比一下,自己拥有的 version 和数据库现在的 version 是否一致,

如果不一致就不修改,这样就实现了乐观锁

177. MySQL 问题排查都有哪些手段?

使用 show processlist 命令查看当前所有连接信息。

使用 explain 命令查询 SQL 语句执行计划。

开启慢查询日志,查看慢查询的 SQL

178. 如何做 MySQL 的性能优化?

为搜索字段创建索引。

避免使用 select *,列出需要查询的字段。

垂直分割分表。

选择正确的存储引擎

Redis

179. Redis 是什么?都有哪些使用场景?

Redis是一个开源的使用ANSI C语言编写、支持网络、

可基于内存亦可持久化的日志型、Key-Value数据库,并提供多种语言的API。

Redis 使用场景:

数据高并发的读写

海量数据的读写

对扩展性要求高的数据

180.Redis 有哪些功能?

数据缓存功能

分布式锁的功能

支持数据持久化

支持事务

支持消息队列

181. Redis 和 memcache 有什么区别?

1、Redis和Memcache都是将数据存放在内存中,都是内存数据库。不过memcache还可用于缓存其他东西,例如图片、视频等等。

2、Redis不仅仅支持简单的k/v类型的数据,同时还提供list,set,hash等数据结构的存储。

3、虚拟内存--Redis当物理内存用完时,可以将一些很久没用到的value 交换到磁盘

4、过期策略--memcache在set时就指定,例如set key1 0 0 8,即永不过期。Redis可以通过例如expire 设定,例如expire name 10

5、分布式--设定memcache集群,利用magent做一主多从;redis可以做一主多从。都可以一主一从

6、存储数据安全--memcache挂掉后,数据没了;redis可以定期保存到磁盘(持久化)

7、灾难恢复--memcache挂掉后,数据不可恢复; redis数据丢失后可以通过aof恢复

8、Redis支持数据的备份,即master-slave模式的数据备份。

182. Redis 为什么是单线程的?

因为Redis是基于内存的操作,CPU不是Redis的瓶颈,Redis的瓶颈最有可能是机器内存的大小或者网络带宽。既然单线程容易实现,而且CPU不会成为瓶颈,那就顺理成章地采用单线程的方案了。

183. 什么是缓存穿透?怎么解决?

一般的缓存系统,都是按照 key 去缓存查询,如果不存在对应的 value,就应该去后端系统查找(比如

DB)。一些恶意的请求会故意查询不存在的 key,请求量很大,就会对后端系统造成很大的压力。这就叫

做缓存穿透。

如何避免?

1:对查询结果为空的情况也进行缓存,缓存时间设置短一点,或者该 key 对应的数据 insert 了之后清理

缓存。

2:对一定不存在的 key 进行过滤。可以把所有的可能存在的 key 放到一个大的 Bitmap 中,查询时通过

该 bitmap 过滤。

缓存雪崩

当缓存服务器重启或者大量缓存集中在某一个时间段失效,这样在失效的时候,会给后端系统带来很大压

力。导致系统崩溃。

184. Redis 支持的数据类型有哪些?

1、string(字符串)2、hash(哈希)3、list(列表)4、set(集合)5、zset(有序集合)

185. Redis 支持的 Java 客户端都有哪些?

Redisson、Jedis、lettuce 等等,官方推荐使用 Redisson

jedis 和 Redisson 有哪些区别?jedis:提供了比较全面的 Redis 命令的支持。

Redisson:实现了分布式和可扩展的 Java 数据结构,与 jedis 相比 Redisson 的功能相对简单,不支持排序、事务、管道、分区等 Redis 特性。

187. 怎么保证缓存和数据库数据的一致性?

1 先更新数据库,再删除缓存,通过松耦合的情况,大部分场景能满足(先删除缓存再更新数据库,存在缓存击穿问题)

2 异步更新缓存(基于订阅binlog的同步机制)

3串行化,我们利用MQ将所有“读数据库” + “写缓存”的步骤串行化

4 MQ+时间差+标记锁(检查要读的数据是否被锁定)

188. Redis 持久化有几种方式?

redis 持久化的两种方式

RDB:RDB 持久化机制,是对 redis 中的数据执行周期性的持久化。

AOF:AOF 机制对每条写入命令作为日志,以 append-only 的模式写入一个日志文件中,在 redis 重启的时候,可以通过回放 AOF 日志中的写入指令来重新构建整个数据集。

RDB 优缺点

RDB 对 redis 对外提供的读写服务,影响非常小,可以让 redis 保持高性能

RDB 会生成多个数据文件,每个数据文件都代表了某一个时刻中 redis 的数据,这种多个数据文件的方式,非常适合做冷备, RDB 数据文件来重启和恢复 redis 进程,更加快速。

如果想要在 redis 故障时,尽可能少的丢失数据,那么 RDB 没有 AOF 好那么会丢失最近 5 分钟的数据。

AOF 优缺点

AOF 可以更好的保护数据不丢失,redis 性能会大大降低

189. Redis 怎么实现分布式锁?

先拿setnx来争抢锁,抢到之后,再用expire给锁加一个过期时间防止锁忘记了释放。

如果在setnx之后执行expire之前进程意外crash或者要重启维护了,那会怎么样?

set指令有非常复杂的参数,这个应该是可以同时把setnx和expire合成一条指令来用的!

190. Redis 分布式锁有什么缺陷?

Redis 分布式锁不能解决超时的问题,分布式锁有一个超时时间,程序的执行如果超出了锁的超时时间就会出现问题。

191. Redis 如何做内存优化?

 redisObject对象 二. 缩减键值对象 三. 共享对象池 四. 字符串优化 五. 编码优化 六. 控制key的数量

192. Redis 淘汰策略有哪些?

1,volatile-lru:从已设置过期时间的哈希表(server.db[i].expires)中随机挑选多个key,然后在选到的key中用lru算法淘汰最近最少使用的数据

2,allkey-lru:从所有key的哈希表(server.db[i].dict)中随机挑选多个key,然后再选到的key中利用lru算法淘汰最近最少使用的数据

3,volatile-ttl:从已设置过期时间的哈希表(server.db[i].expires)中随机挑选多个key,然后在选到的key中选择过期时间最小的数据淘汰掉。

4,volatile-random:从已设置过期时间的哈希表(server.db[i].expires)中随机挑选key淘汰掉。

5,allkey-random:从所有的key的哈希表(server.db[i].dict)中随机挑数据淘汰

6,no-eviction(驱逐):内存达到上限,不淘汰数据。

策略选择:

如果分为热数据与冷数据, 推荐使用 allkeys-lru 策略。 也就是, 其中一部分key经常被读写. 如果不确定具体的业务特征, 那么 allkeys-lru 是一个很好的选择。

如果需要循环读写所有的key, 或者各个key的访问频率差不多, 可以使用 allkeys-random 策略, 即读写所有元素的概率差不多。

假如要让 Redis 根据 TTL 来筛选需要删除的key, 请使用 volatile-ttl 策略。

193. Redis 常见的性能问题有哪些?该如何解决?

·Master写内存快照,save命令调度rdbSave函数,会阻塞主线程的工作,当快照比较大时对性能影响是非常大的,会间断性暂停服务,所以Master最好不要写内存快照。

·Master AOF持久化,如果不重写AOF文件,这个持久化方式对性能的影响是最小的,但是AOF文件会不断增大,AOF文件过大会影响Master重启的恢复速度。Master最好不要做任何持久化工作,包括内存快照和AOF日志文件,特别是不要启用内存快照做持久化,如果数据比较关键,某个Slave开启AOF备份数据,策略为每秒同步一次。

·Master调用BGREWRITEAOF重写AOF文件,AOF在重写的时候会占大量的CPU和内存资源,导致服务load过高,出现短暂服务暂停现象。

·Redis主从复制的性能问题,为了主从复制的速度和连接的稳定性,Slave和Master最好在同一个局域网内

JVM

194. 说一下 JVM 的主要组成部分?及其作用?

类加载器(ClassLoader) 把文件加载到内存中 

运行时数据区(Runtime Data Area) ,而字节码文件是jvm的一套指令集规范,并不能直接交个底层操作系统去执行,因此需要特定的命令解析器

 执行引擎(Execution Engine) 将字节码翻译成底层系统指令再交由CPU去执行,而这个过程中需要调用其他语言的接口 

本地库接口(Native Interface)来实现整个程序的功能,这就是这4个主要组成部分的职责与功能

195. 说一下 JVM 运行时数据区?

1,Java虚拟机栈

存储局部变量,操作数栈,方法出口等,为每个被执行的方法创建一个栈帧,是线程私有的,这一点跟堆是不同的

2,java堆

java虚拟机中内存最大的一块,所有new的对象,都在这里分配内存,被所有线程共享。

3,程序计数器

保存当前线程执行的字节码行号指示器,通过改变该值,来实现执行下一条字节码指令。

分支,循环,线程恢复等操作,都需要依赖这个计数器来实现。

4,方法区

存储类信息,常量,静态变量,即时编译的代码等数据

5,本地方法栈

与java虚拟机栈类似,只不过java虚拟机栈是服务java方法的,本地方法区栈服务虚拟机调用Native方法的。

196.说一下堆栈的区别?

1、栈区(stack)—由编译器自动分配释放,存放函数的参数值,局部变量的值等。其操作方式类似于数据结构中的栈。

2、堆区(heap)—一般由程序员分配释放,若程序员不释放,程序结束时可能由OS回收。注意它与数据结构中的堆是两回事,分配方式倒是类似于链表,呵呵。

堆:

1.提供所有类实例和数组对象存储区域

2.jvm只有一个堆区(heap)被所有线程共享,堆中不存放基本类型和对象引用,只存放对象本身

3.Java的堆是一个运行时数据区,类的对象从堆中分配空间。这些对象通过new等指令建立,通过垃圾回收器来销毁。

4.堆的优势是可以动态地分配内存空间,需要多少内存空间不必事先告诉编译器,因为它是在运行时动态分配的。

    但缺点是,由于需要在运行时动态分配内存,所以存取速度较慢。

1.栈内存存储的是局部变量而堆内存存储的是实体;

2.栈内存的更新速度要快于堆内存,因为局部变量的生命周期很短;

3.栈内存存放的变量生命周期一旦结束就会被释放,而堆内存存放的实体会被垃圾回收机制不定时的回收。

197. 队列和栈是什么?有什么区别?

(1)操作的名称不同。队列的插入称为入队,队列的删除称为出队。栈的插入称为进栈,栈的删除称为出栈。

(2)可操作的方式不同。队列是在队尾入队,队头出队,即两边都可操作。而栈的进栈和出栈都是在栈顶进行的,无法对栈底直接进行操作。

(3)操作的方法不同。队列是先进先出(FIFO),即队列的修改是依先进先出的原则进行的。新来的成员总是加入队尾(不能从中间插入),每次离开的成员总是队列头上(不允许中途离队)。而栈为后进先出(LIFO),即每次删除(出栈)的总是当前栈中最新的元素,即最后插入(进栈)的元素,而最先插入的被放在栈的底部,要到最后才能删除。

198. 什么是双亲委派模型?

如果一个类加载器需要加载类,那么首先它会把这个类请求委派给父类加载器去完成,每一层都是如此。一直递归到顶层,当父加载器无法完成这个请求时,子类才会尝试去加载。

199. 说一下类装载的执行过程?

1.加载:根据查找路径找到相应的 class 文件然后导入;

2.检查:检查加载的 class 文件的正确性;

3.准备:给类中的静态变量分配内存空间;

4.解析:虚拟机将常量池中的符号引用替换成直接引用的过程。符号引用就理解为一个标示,而在直接引用直接指向内存中的地址;

5.初始化:对静态变量和静态代码块执行初始化工作。

200. 怎么判断对象是否可以被回收?

引用计数器:为每个对象创建一个引用计数,有对象引用时计数器 +1,引用被释放时计数 -1,当计数器为 0 时就可以被回收。它有一个缺点不能解决循环引用的问题;可达性分析:从 GC Roots 开始向下搜索,搜索所走过的路径称为引用链。当一个对象到 GC Roots 没有任何引用链相连时,则证明此对象是可以被回收的。

201.Java 中都有哪些引用类型?

强引用:发生 gc 的时候不会被回收。

软引用:有用但不是必须的对象,在发生内存溢出之前会被回收。

弱引用:有用但不是必须的对象,在下一次GC时会被回收。

虚引用(幽灵引用/幻影引用):无法通过虚引用获得对象,用 PhantomReference 现虚引用,虚引用的用途是在 gc 时返回一个通知。

202. 说一下 JVM 有哪些垃圾回收算法?

常用的垃圾回收算法有如下四种:标记-清除、复制、标记-整理和分代收集。

标记-清除算法

从算法的名称上可以看出,这个算法分为两部分,标记和清除。首先标记出所有需要被回收的对象,然后在标记完成后统一回收掉所有被标记的对象。

这个算法简单,但是有两个缺点:一是标记和清除的效率不是很高;二是标记和清除后会产生很多的内存碎片,导致可用的内存空间不连续,当分配大对象的时候,没有足够的空间时不得不提前触发一次垃圾回收。

复制算法

这个算法将可用的内存空间分为大小相等的两块,每次只是用其中的一块,当这一块被用完的时候,就将还存活的对象复制到另一块中,然后把原已使用过的那一块内存空间一次回收掉。这个算法常用于新生代的垃圾回收。

复制算法解决了标记-清除算法的效率问题,以空间换时间,但是当存活对象非常多的时候,复制操作效率将会变低,而且每次只能使用一半的内存空间,利用率不高。

标记-整理算法

这个算法分为三部分:一是标记出所有需要被回收的对象;二是把所有存活的对象都向一端移动;三是把所有存活对象边界以外的内存空间都回收掉。

标记-整理算法解决了复制算法多复制效率低、空间利用率低的问题,同时也解决了内存碎片的问题。

分代收集算法

根据对象生存周期的不同将内存空间划分为不同的块,然后对不同的块使用不同的回收算法。一般把Java堆分为新生代和老年代,新生代中对象的存活周期短,只有少量存活的对象,所以可以使用复制算法,而老年代中对象存活时间长,而且对象比较多,所以可以采用标记-清除和标记-整理算法。

202.说一下 JVM 有哪些垃圾回收器?

Serial:最早的单线程串行垃圾回收器。

Serial Old:Serial 垃圾回收器的老年版本,同样也是单线程的,可以作为 CMS 垃圾回收器的备选预案。

ParNew:是 Serial 的多线程版本。 Parallel 和 ParNew 收集器类似是多线程的,但 Parallel 是吞吐量优先的收集器,可以牺牲等待时间换取系统的吞吐量。

Parallel Old 是 Parallel 老生代版本,Parallel 使用的是复制的内存回收算法,Parallel Old 使用的是标记-整理的内存回收算法。

CMS:一种以获得最短停顿时间为目标的收集器,非常适用 B/S 系统。

G1:一种兼顾吞吐量和停顿时间的 GC 实现,是 JDK 9 以后的默认 GC 选项。

204. 详细介绍一下 CMS 垃圾回收器?

是以牺牲吞吐量为代价来获得最短回收停顿时间的垃圾回收器。对于要求服务器响应速度的应用上,这种垃圾回收器非常适合。在启动 JVM 的参数加上“-XX:+UseConcMarkSweepGC”来指定使用 CMS 垃圾回收器。 CMS 使用的是标记-清除的算法实现的,所以在 gc 的时候回产生大量的内存碎片,当剩余内存不能满足程序运行要求时,系统将会出现 Concurrent Mode Failure,临时 CMS 会采用 Serial Old 回收器进行垃圾清除,此时的性能将会被降低。

205. 新生代垃圾回收器和老生代垃圾回收器都有哪些?有什么区别?

新生代回收器:Serial、ParNew、Parallel Scavenge

老年代回收器:Serial Old、Parallel Old、CMS

整堆回收器:G1

新生代垃圾回收器一般采用的是复制算法,复制算法的优点是效率高,缺点是内存利用率低;老年代回收器一般采用的是标记-整理的算法进行垃圾回收。

206. 简述分代垃圾回收器是怎么工作的?

分代回收器有两个分区:老生代和新生代,新生代默认的空间占比总空间的 1/3,老生代的默认占比是 2/3。 新生代使用的是复制算法,新生代里有 3 个分区:Eden、To Survivor、From Survivor,它们的默认占比是 8:1:1,

它的执行流程如下:

把 Eden + From Survivor 存活的对象放入 To Survivor 区;

清空 Eden 和 From Survivor 分区; From Survivor 和 To Survivor 分区交换,From Survivor 变 To Survivor,To Survivor 变 From Survivor。

每次在 From Survivor 到 To Survivor 移动时都存活的对象,年龄就 +1,当年龄到达 15(默认配置是 15)时,升级为老生代。大对象也会直接进入老生代。

老生代当空间占用到达某个值之后就会触发全局垃圾收回,一般使用标记整理的执行算法。

以上这些循环往复就构成了整个分代垃圾回收的整体执行流程。

207. 说一下 JVM 调优的工具?

JDK 自带了很多监控工具,都位于 JDK 的 bin 目录下,其中最常用的是 jconsole 和 jvisualvm 这两款视图监控工具。

jconsole:用于对 JVM 中的内存、线程和类等进行监控;

jvisualvm:JDK 自带的全能分析工具,可以分析:内存快照、线程快照、程序死锁、监控内存的变化、gc 变化等。 208.

208. 常用的 JVM 调优的参数都有哪些?

Xms2g:初始化推大小为 2g;

-Xmx2g:堆最大内存为 2g;

-XX:NewRatio=4:设置年轻的和老年代的内存比例为 1:4;

-XX:SurvivorRatio=8:设置新生代 Eden 和 Survivor 比例为 8:2; –XX:+UseParNewGC:指定使用 ParNew + Serial Old 垃圾回收器组合;

-XX:+UseParallelOldGC:指定使用 ParNew + ParNew Old 垃圾回收器组合;

-XX:+UseConcMarkSweepGC:指定使用 CMS + Serial Old 垃圾回收器组合;

-XX:+PrintGC:开启打印 gc 信息;

-XX:+PrintGCDetails:打印 gc 详细信息。

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值