JAVA常见面试题解()

news/2024/10/19 3:35:20/

一、java基础

1.JDK 和 JRE 有什么区别?

面向人群不同:

JDK是面向开发人员使用的SDK。

JRE是Java Runtime Enviroment是指Java的运行环境,是面向Java程序的使用者。

重要程度不同:

编写的Java程序必须要JRE才能运行。

2.== 和 equals 的区别?

 基本数据类型比较:

==和equals都是比较栈内存中的地址是否相等 。相等为true 否则为false

引用对象比较:

==和equals都比较两个值是否相等。相等为true 否则为false

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

不一定;

两个对象的 equals()相等 则 hashCode()相等;

两个对象的 equals()不相等 则 hashCode()也可能相等。

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

final 可修饰类、方法、变量(包括成员变量和局部变量);被final修饰的类不能被继承、被final修饰的方法不能被重写、被final修饰的变量赋值后不可再更改(常量)。

5.java中的Math.round(-1.5)等于多少?

等于 -1 ;Math.round()的作用是向上取整;

但是也有三种特殊情况:

1.如果参数为 NaN(无穷与非数值),那么结果为 0。
2.如果参数为负无穷大或任何小于等于 Long.MIN_VALUE 的值,那么结果等于Long.MIN_VALUE 的值。
3.如果参数为正无穷大或任何大于等于 Long.MAX_VALUE 的值,那么结果等于Long.MAX_VALUE 的值。

6.String属于基础类型吗?

Sring属于引用类型;

常用的基本类型为: byte / short / int / long / char / float / double /boolean

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

java中操作字符串的类有 String / StringBuffer / StringBuilder

其中StringBuffer / StringBuilder 均继承自 String ; 三者都是以char[ ] 的方式保存字符串; 其中String类型的字符串是不可更改的,做增删时会重新创建对象,而后两者做增删时都是对同一对象进行操作;StringBuffer中的方法被synchronized修饰,所以是线程安全的,而StringBuilder则是线程不安全的.

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

不一样 String str="i" 是在常量池中,而String str = new String("i")是创建了一个对象,分配在堆内存中

9.如何将字符串反转?

1.使用字符串数组,实现从尾部开始逐个逆序放入字符串

public static String reverse1(String s) {char[] array = s.toCharArray();String re = "";for(int i = array.length - 1; i >= 0; i--){re += array[i];
}return re;}

2.调用StringBuffer中的reverse方法

public static String reverse2(String s) {return new StringBuffer(s).reverse().toString();}

暂时只会用这两种....

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

1.contains()         判断是否包含

2.endwith()        判断是否以指定后缀结束

3.equals()        判断是否相等

4.hashCode()        获取哈希码值

5.indexOf()        获取指定字符第一次出现的索引6.

6.lastIndexOf()        获取指定字符最后一次出现的索引

7.isEmpty()        判断是否为空

8.length()        获取指定字符串的长度

9.matches()        判断字符串是否匹配给定的正则表达式

10.replace()        替换指定字符串并返回一个新的字符串

11.startWith()        判断是否以指定字符串开始

12.substring()        截取并返回新的字符串(注意截取时如指定范围则截取内容含头不含尾)

13.toLowerCase()        转小写

14.toUpperCase()        转大写

15.trim()        去除收尾的空格并返回新的字符串

16.split()        根据指定的正则表达式匹配并拆分字符

17.toCharArray()        将字符串转为一个新数组

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

抽象类可以没有抽象方法,可以由子类去实现;但是包含一个抽象方法的类一定是抽象类。

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

普通类中没有抽象方法,可以被实例化(也就是new)

抽象类中可以有抽象方法,不能被实例化;抽象类的子类必须实现该抽象类的抽象方法(重写抽象方法)(除非子类也是抽象类)

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

不能,因为抽象类是需要被子类继承的,而被final修饰的类不能被继承

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

抽象类中可以有构造方法,变量,常量,普通方法,抽象方法

接口中没有构造方法,只有常量,都是抽象方法;接口和接口之间可以多继承,接口和类之间可以多实现

15. java 中 IO 流分为几种?

1.按照流的流向分,可分为输入流和输出流

2.按照操作单元分,可分为字节流和字符流

3.按照流的角色分,可分为节点流和处理流

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

BIO (同步阻塞)是传统的java.io包,它是基于流的模式实现的;交互的方式是同步,阻塞方式,也就是说在读入输入流或输出流的同时,在读写动作完成之前,线程会一直阻塞在那里,它们之间的调用时可靠的线性顺序;它的优点就是代码比较简单、直观;缺点就是 IO 的效率和扩展性很低,容易成为应用性能瓶颈。

NIO (同步非阻塞)是java1.4引入的java.nio包,它的优点就是代码比较简单、直观;缺点就是 IO 的效率和扩展性很低,容易成为应用性能瓶颈。

AIO (异步非阻塞)是java1.7之后引入的包(Asynchronous IO),是NIO的升级版本,提供了异步非阻塞的IO操作方式;异步 IO是基于事件和回调机制实现的,也就是应用操作之后会直接返回,不会堵塞在那里,当后台处理完成,操作系统会通知相应的线程进行后续的操作。

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

1.length()        获取文件的字节量大小

2.isFile()        判断是否为文件

3.isDirectory()        判断是否为文件夹

4.getName()        获取文件,文件夹名

5.getParent()        获取父文件夹的路径

6.getAbsolutePath()        获取文件的完整路径

7.createNewFile()        新建文件

8.mkdir()        新建单层不存在的文件夹

9.mkdirs()        新建多层不存在的文件夹

10.delete()        删除文件,空文件夹

11.list()        列出文件夹里的资源名

12.listFile()        列出文件夹里的所有文件的完整路径并把每个资源封装成File数组

18. java 容器都有哪些?

JAVA中容器主要分为两大类:Map类跟Collection类; 它们都有一个共同的父接口Iterator

Map是一队成队的键值对象,可以用键来查找值,包含HashMap类和TreeMap类

Collection 是一个独立的元素序列,有三个常用子接口:List / Set / Queue ;其中List必须按照插入的顺序保存元素、Set不能有重复的元素、Queue按照排队规则来确定对象的产生顺序

19. Collection 和 Collections 有什么区别?

Collection 是一个集合接口,它提供了对集合对象进行基本操作的通用接口方法;实现该接口的类主要有 List 和 Set ,该接口的设计目的是为各种具体的集合提供最大化的统一操作方式

Collections 是针对集合类的一个包装类,它提供了一系列的静态方法来实现对集合的搜索,排序,线程安全化等操作,其中大多数方法都是用来处理线性表,且Coolections类不能实例化

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

List 是一个有序的集合

Set 不重复集合,LinkedHashSet按照插入排序,SortedSet可排序,HashSet无序

Map 键值对集合

21. HashMap 和 Hashtable 有什么区别?

都是用于存储键(key)和值(value)的对应关系,都是map的实现类,都是使用哈希表的方式存储

1.线程安全性不同:

HashMap不是线程安全的,在多线程并发的环境下,可能会产生死锁等问题(效率高)

Hashtable是线程安全的,它的每个方法中都加入了Synchronize方法。在多线程并发的环境下,可以直接使用Hashtable,不需要自己为它的方法实现同步

2.继承的父类不同:

HashMap是继承自AbstractMap类,而Hashtable是继承自Dictionary类,但二者都同时实现了map,Cloneable(可复制),Serializable(可序列化)这三个接口

3.是否可以存null

HashMap可以使用null(key和value)都可以

HashTable不能存null

4.遍历方法不同

HashMap使用Iterator遍历

HashTable使用Enumeration遍历

5.初始化和扩容方式不同

HashMap默认的初始化大小为16。之后每次扩充,容量变为原来的2倍

Hashtable默认的初始大小为11,之后每次扩充,容量变为原来的2n+1

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

HashMap 是基于桶(数组和链表)实现;而TreeMap是基于红黑树实现;

HashMap是无序的;TreeMap是根据key值升序来排序的;

HashMap在读数据时性能更高,所以在没有要求排序时,使用HashMap.

23.HashMap的底层实现原理?

当new HashMap( ) 时,底层会开辟空间(桶),初始容量是16,使用默认加载因子0.75;当开始准备数据存入时,计算存放的位置 使用hash值(作为key的标记);判断如果位置是null,没有数据直接存;判断位置有数据,就形成链表(注意 : 当key相同时,覆盖原有的value,当key不同时,形成链表 );当桶内容量达到16*0.75时,会开始rehash(扩容,新桶的容量是原来的2倍)

底层为:数组 + 红黑树

24.HashSet的实现原理?

HashSet是基于HashMap实现的,底层就是数组,默认初始容量是16,加载因子0.75,封装了一个 HashMap 对象来存储所有的集合元素,当我们试图把某个类的对象当成 HashMap的 key,或试图将这个类的对象放入 HashSet 中保存时,重写该类的equals(Object obj)方法和 hashCode() 方法很重要,而且这两个方法的返回值必须保持一致:当该类的两个的 hashCode() 返回值相同时,它们通过 equals() 方法比较也应该返回 true。通常来说,所有参与计算 hashCode() 返回值的关键属性,都应该用于作为 equals() 比较的标准。

25.ArrayList 和 LinkedList 的区别?

两者都是非线程安全的;ArrayList底层是数组结构,适合做查询效率更高;LinkedList底层是链表结构,适合做增删效率更高

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

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

import java.util.Arrays;
import java.util.List;public class test {public static void main(String[] args) {String[] strs = new String[] {"aaa", "bbb", "ccc"}; //数组List<String> list = Arrays.asList(strs); //listfor (String s : list) {System.out.println(s); //循环输出}}
}

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

Vector比ArrayList先存在。Vector是同步的,Vector的对象是线程安全的;ArrayList是异步的,ArrayList的对象不是线程安全的。同步影响执行效率,所以ArrayList比Vector性能好。

ArrayList和Vector都有一个初始的容量大小,当存储的空间不够时,需要增加存储空间,Vector默认增长原来的一倍,而ArrayList是原来的0.5倍。ArrayList与Vector都可以设置初始的空间大小,Vector还可以设置增长的空间大小。

28. Array 和 ArrayList 有何区别?

1、存储内容比较:

Array 数组可以包含基本类型和对象类型;
ArrayList 却只能包含对象类型(集合);

2、空间大小比较:

Array 数组的空间大小是固定的,所以需要事前确定合适的空间大小。
ArrayList 集合的空间是动态增长的,而且,每次添加新的元素的时候都会检查内部数组的空间是否足够。

3.方法上的比较:

ArrayList 方法上比 Array 更多样化,比如添加全部 addAll()、删除全部 removeAll()、返回迭代器 iterator() 等。

注:

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

  • 对于基本数据类型,集合(ArrayList)使用自动装箱来减少编码工作量;但是Array相对较慢。

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

队列(queue)是一个典型的先进先出(FIFO)的容器。即从容器的一端放入事物,从另一端取出,并且事物放入容器的顺序与取出的顺序是相同的。

相同点:都是返回第一个元素,并在队列中删除返回的对象。

不同点:

  • remove() ,如果队列为空的时候,则会抛出异常

  • 而poll()只会返回null

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

Vector:就比Arraylist多了个同步化机制(线程安全)。

Hashtable:就比Hashmap多了个线程安全。

Stack: 栈,也是线程安全的,继承于Vector。

ConcurrentHashMap:是一种高效但是线程安全的集合  

31. 迭代器 Iterator 是什么?

Iterator是可以遍历集合的对象,为各种容器提供了公共的接口,隔离对容器的遍历操作和底层实现(解耦)

缺点是增加新的集合类需要对应增加新的迭代器类,迭代器类与集合类也成对增加.

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

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

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

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

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

33. Iterator 和 ListIterator 有什么区别?

ListIterator继承自Iterator, 且比Iterator有更多的方法

在使用范围上,Iterator可以迭代所有集合;ListIterator只能用于List及其子类

ListIterator 有 add 方法,可以向 List 中添加对象;Iterator 不能

ListIterator 有 set()方法,可以实现对 List 的修改;Iterator 仅能遍历,不能修改

ListIterator 有 hasPrevious() 和 previous() 方法,可以实现逆向遍历;Iterator不能

ListIterator 有 nextIndex() 和previousIndex() 方法,可定位当前索引的位置;Iterator不能

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

可以使用 Collections. unmodifiableCollection(Collection c) 方法来创建一个只读集合,这样改变集合的任何操作都会抛出 Java.lang.UnsupportedOperationException 异常

List<String> list = new ArrayList<>();
list. add("x");
Collection<String> clist = Collections. unmodifiableCollection(list);
clist. add("y"); // 运行时此行报错
System. out. println(list. size());

同理:Collections包也提供了对list和set集合的方法 :

Collections.unmodifiableList(List)

Collections.unmodifiableSet(Set)

-------------------------多线程-------------------------

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

并行(Parallel):当系统有一个以上CPU时,一个CPU执行一个进程,而另一个CPU可以执行另一个进程。两个进程互不抢占CPU资源,可以同时进行。

并发(Concurrent):多个任务在同一个 CPU 核上,按细分的时间片轮流(交替)执行,但从逻辑上来看那些任务是同时执行。

区别 :

并行:多个事情,在同一时间点上同时发生了;且多个任务之间是不互相抢占资源的。

并发:多个事情,在同一时间段内同时发生了;且多个任务之间是互相抢占资源的。

36. 线程和进程的区别?

进程:是执行中一段程序,即一旦程序被载入到内存中并准备执行,它就是一个进程。进程是表示资源分配的的基本概念,又是调度运行的基本单位,是系统中的并发执行的单位

线程:单个进程中执行中每个任务就是一个线程。线程是进程中执行运算的最小单位

根本区别:进程是一段正在执行的程序,是资源分配的基本单元;而线程是CPU调度(程序执行)的基本单元

一个线程只能属于一个进程,但是一个进程可以拥有多个线程。多线程处理就是允许一个进程中在同一时刻执行多个任务

37. 守护线程是什么?

守护线程,专门用于服务其他的线程,如果其他的线程(即用户自定义线程)都执行完毕,连main线程也执行完毕,那么jvm就会退出(即停止运行)此时,连jvm都停止运行了,守护线程当然也就停止执行了

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

1.继承Thread类创建线程类:
(1)定义Thread类的子类,并重写该类的run方法,该run方法的方法体就代表了线程要完成的任务。因此把run()方法称为执行体。
(2)创建Thread子类的实例,即创建了线程对象。
(3)调用线程对象的start()方法来启动该线程。


2.通过Runnable接口创建线程类:
(1)定义runnable接口的实现类,并重写该接口的run()方法,该run()方法的方法体同样是该线程的线程执行体。
(2)创建 Runnable实现类的实例,并依此实例作为Thread的target来创建Thread对象,该Thread对象才是真正的线程对象。
(3)调用线程对象的start()方法来启动该线程。


3.通过Callable和Future创建线程(此种方式存在返回值):
(1)创建Callable接口的实现类,并实现call()方法,该call()方法将作为线程执行体,并且有返回值。
(2)创建Callable实现类的实例,使用FutureTask类来包装Callable对象,该FutureTask对象封装了该Callable对象的call()方法的返回值。
(3)使用FutureTask对象作为Thread对象的target创建并启动新线程。
(4)调用FutureTask对象的get()方法来获得子线程执行结束后的返回值

4.通过线程池启动多线程
使用线程池创建线程的步骤:
(1)使用Executors类中的newFixedThreadPool(int num)方法创建一个线程数量为num的线程池。
(2)调用线程池中的execute()方法执行由实现Runnable接口创建的线程;调用submit()方法执行由实现Callable接口创建的线程。
(3)调用线程池中的shutdown()方法关闭线程池

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

Runnable接口中的值void run()方法没有返回,它做的事情只是纯粹地去执行run()方法中的代码且不能抛出异常

Callable接口中的call()方法是有返回值的,是一个泛型,和Future、FutureTask配合可以用来获取异步执行的结果,可以抛出受检查的异常

40. 线程有哪些状态?

分为五种:

新建状态

就绪状态

运行状态

阻塞状态

死亡状态

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

sleep()和wait()都是使线程暂停的方法

最大区别: sleep()后,程序并不会不释放同步锁

                wait()后,程序会释放同步锁。 使得其他线程可以使用同步控制块或者方法

用法不同: sleep()可以用时间指定来使他自动醒过来。如果时间不到你只能调用interreput()来强行打断

                wait()可以用notify()直接唤起

属于不同的类属: 

sleep()的类是Thread

wait()的类是Object

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

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

notifyAll() 唤醒对象的等待池中的所有线程,进入锁池

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

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

start()是启动线程对象,让被启动的线程执行run()中的任务代码

而直接调用run()并没有启动线程,执行run()的只有main线程

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

通常开发者都是利用Executors提供的通用线程池创建方法,去创建不同配置的线程池:

1、newCachedThreadPool(),它是用来处理大量短时间工作任务的线程池,具有几个鲜明特点:它会试图缓存线程并重用,当无缓存线程可用时,就会创建新的工作线程;如果线程闲置时间超过60秒,则被终止并移除缓存;长时间闲置时,这种线程池,不会消耗什么资源。其内部使用SynchronousQueue作为工作队列

2、newFixedThreadPool(int nThreads),重用指定数目(nThreads)的线程,其背后使用的是无界的工作队列,任何时候最多有nThreads个工作线程是活动的。这意味着,如果任务数量超过了活动线程数目,将在工作队列中等待空闲线程出现;如果工作线程退出,将会有新的工作线程被创建,以补足指定数目nThreads

3、newSingleThreadExecutor(),它的特点在于工作线程数目限制为1,操作一个无界的工作队列,所以它保证了所有的任务都是被顺序执行,最多会有一个任务处于活动状态,并且不予许使用者改动线程池实例,因此可以避免改变线程数目

4、newSingleThreadScheduledExecutor()和newScheduledThreadPool(int corePoolSize),创建的是个ScheduledExecutorService,可以进行定时或周期性的工作调度,区别在于单一工作线程还是多个工作线程

5、newWorkStealingPool(int parallelism),这是一个经常被人忽略的线程池,Java 8 才加入这个创建方法,其内部会构建ForkJoinPool,利用Work-Stealing算法,并行地处理任务,不保证处理顺序

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

线程池有5种状态:RunningShutDownStopTidyingTerminated

1.RUNNING:这是最正常的状态,接受新的任务,处理等待队列中的任务。线程池的初始化状态是RUNNING。线程池被一旦被创建,就处于RUNNING状态,并且线程池中的任务数为0

2.SHUTDOWN:不接受新的任务提交,但是会继续处理等待队列中的任务。调用线程池的shutdown()方法时,线程池由RUNNING -> SHUTDOWN

3.STOP:不接受新的任务提交,不再处理等待队列中的任务,中断正在执行任务的线程。调用线程池的shutdownNow()方法时,线程池由(RUNNING or SHUTDOWN ) -> STOP

4.TIDYING:所有的任务都销毁了,workCount 为 0,线程池的状态在转换为 TIDYING 状态时,会执行钩子方法 terminated()。因为terminated()在ThreadPoolExecutor类中是空的,所以用户想在线程池变为TIDYING时进行相应的处理;可以通过重载terminated()函数来实现

当线程池在SHUTDOWN状态下,阻塞队列为空并且线程池中执行的任务也为空时,就会由 SHUTDOWN -> TIDYING

当线程池在STOP状态下,线程池中执行的任务为空时,就会由STOP -> TIDYING。

5.TERMINATED:线程池处在TIDYING状态时,执行完terminated()之后,就会由 TIDYING -> TERMINATED

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

接收的参数不一样:

  • execute() 参数 Runnable ;submit() 参数 (Runnable) 或 (Runnable 和 结果 T) 或 (Callable)

submit有返回值,而execute没有

submit() 的返回值 Future 调用get方法时,可以捕获处理异常

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

线程的安全性问题体现在:

  • 原子性:一个或者多个操作在 CPU 执行的过程中不被中断的特性
  • 可见性:一个线程对共享变量的修改,另外一个线程能够立刻看到
  • 有序性:程序执行的顺序按照代码的先后顺序执行

导致原因:

  • 缓存导致的可见性问题
  • 线程切换带来的原子性问题
  • 编译优化带来的有序性问题

解决办法:

  • JDK Atomic开头的原子类、synchronized、LOCK,可以解决原子性问题
  • synchronized、volatile、LOCK,可以解决可见性问题
  • Happens-Before 规则可以解决有序性问题

48. 多线程锁的升级原理是什么?

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

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

锁状态对比:

偏向锁轻量级锁重量级锁
适用场景只有一个线程进入同步块虽然很多线程,但是没有冲突:多条线程进入同步块,但是线程进入时间错开因而并未争抢锁发生了锁争抢的情况:多条线程进入同步块并争用锁
本质取消同步操作CAS操作代替互斥同步互斥同步
优点不阻塞,执行效率高(只有第一次获取偏向锁时需要CAS操作,后面只是比对ThreadId)不会阻塞不会空耗CPU
缺点适用场景太局限。若竞争产生,会有额外的偏向锁撤销的消耗长时间获取不到锁空耗CPU阻塞,上下文切换,重量级操作,消耗操作系统资源

49. 什么是死锁?

死锁是指两个或两个以上的进程在执行过程中,由于竞争资源或者由于彼此通信而造成的一种阻塞的现象,若无外力作用,它们都将无法推进下去。此时称系统处于死锁状态或系统产生了死锁,这些永远在互相等待的进程称为死锁进程。是操作系统层面的一个错误,是进程死锁的简称,最早在 1965 年由 Dijkstra 在研究银行家算法时提出的,它是计算机操作系统乃至整个并发程序设计领域最难处理的问题之一

50. 怎么防止死锁?

死锁的四个必要条件:

互斥条件:线程要求对所分配的资源(如打印机)进行排他性控制,即在一段时间内某资源仅为一个线程所占有。此时若有其他线程请求该资源,则请求线程只能等待
不剥夺条件:线程所获得的资源在未使用完毕之前,不能被其他线程强行夺走,即只能由获得该资源的线程自己主动释放
请求和保持条件:线程已经保持了至少一个资源,但又提出了新的资源请求,而该资源已被其他线程占有,此时请求线程被阻塞,但对自己已获得的资源保持不放
循环等待条件:存在一种线程资源的循环等待链,链中每一个线程已获得的资源同时被链中下一个线程所请求。即存在一个处于等待状态的线程集合{Pl, P2, ..., pn},其中Pi等待的资源被P(i+1)占有(i=0, 1, ..., n-1),Pn等待的资源被P0占有

避免死锁的方式:

  • 加锁顺序(线程按照一定的顺序加锁)
  • 加锁时限(线程尝试获取锁的时候加上一定的时限,超过时限则放弃对该锁的请求,并释放自己占有的锁)
  • 死锁检测

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

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

经典的使用场景是为每个线程分配一个 JDBC 连接 Connection。这样就可以保证每个线程的都在各自的 Connection 上进行数据库的操作,不会出现 A 线程关了 B线程正在使用的 Connection; 还有 Session 管理 等问题

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

synchronized可以保证方法或者代码块在运行时,同一时刻只有一个方法可以进入到临界区,同时它还可以保证共享变量的内存可见性。

Java中每一个对象都可以作为锁,这是synchronized实现同步的基础:

  • 普通同步方法,锁是当前实例对象
  • 静态同步方法,锁是当前类的class对象
  • 同步方法块,锁是括号里面的对象

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

(1)、volatile只能作用于变量,使用范围较小。synchronized可以用在变量、方法、类、同步代码块等,使用范围比较广。

(2)、volatile只能保证可见性和有序性,不能保证原子性。而可见性、有序性、原子性synchronized都可以包证。

(3)、volatile不会造成线程阻塞。synchronized可能会造成线程阻塞。

54. synchronized 和 Lock 有什么区别?

synchronizedjava内置关键字,在jvm层面,Lock是个java

采用synchronized不需要用户去手动释放锁,当synchronized方法或者synchronized代码块执行完之后,系统会自动让线程释放对锁的占用;而Lock则必须要用户去手动释放锁,如果没有主动释放锁,就有可能导致出现死锁现象

synchronized无法判断是否获取锁的状态,Lock可以判断是否获取到锁

区别: 1.用法不一样。synchronized既可以加在方法上,也可以加载特定的代码块上,括号中表示需要锁的对象。而Lock需要显示地指定起始位置和终止位置。synchronzied是托管给jvm执行的,Lock锁定是通过代码实现的。 2.在性能上来说,如果竞争资源不激烈,两者的性能是差不多的,而当竞争资源非常激烈时(即有大量线程同时竞争),此时Lock的性能要远远优于synchronized。所以说,在具体使用时要根据适当情况选择。 3.锁的机制不一样。synchronized获得锁和释放的方式都是在块结构中,而且是自动释放锁。而Lock则需要开发人员手动去释放,并且必须在finally块中释放,否则会引起死锁问题的发生。 4.Lock是一个接口,而synchronized是Java中的关键字,synchronized是内置的语言实现; 5.synchronized在发生异常时,会自动释放线程占有的锁,因此不会导致死锁现象发生;而Lock在发生异常时,如果没有主动通过unLock()去释放锁,则很可能造成死锁现象,因此使用Lock时需要在finally块中释放锁; 6.Lock可以让等待锁的线程响应中断,而synchronized却不行,使用synchronized时,等待的线程会一直等待下去,不能够响应中断;通过Lock可以知道有没有成功获取锁,而synchronized却无法办到。Lock可以提高多个线程进行读操作的效率

55. synchronized 和 ReentrantLock 区别是什么?

synchronized 竞争锁时会一直等待;ReentrantLock 可以尝试获取锁,并得到获取结果
synchronized 获取锁无法设置超时;ReentrantLock 可以设置获取锁的超时时间
synchronized 无法实现公平锁;ReentrantLock 可以满足公平锁,即先等待先获取到锁
synchronized 控制等待和唤醒需要结合加锁对象的 wait() 和 notify()、notifyAll();ReentrantLock 控制等待和唤醒需要结合 Condition 的 await() 和 signal()、signalAll() 方法
synchronized 是 JVM 层面实现的;ReentrantLock 是 JDK 代码层面实现
synchronized 在加锁代码块执行完或者出现异常,自动释放锁;ReentrantLock 不会自动释放锁,需要在 finally{} 代码块显示释放

56. 说一下 atomic 的原理?

CAS解决原子性问题,在VEN(但V=E是替换N,不相等),v不等于E,已经被更新,会返回失败

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

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

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

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

----------------------反射----------------------

57. 什么是反射?

是 Java 程序开发语言的特征之一,它允许运行中的 Java 程序对自身进行检查,或者说“自审”,也有称作“自省”。反射非常强大,它甚至能直接操作程序的私有属性

作用   :   用来解析.class文件里的所有资源,包括:构造方法\成员变量\方法\注解------利用class工具类提供的各种方法,获取各种资源

58. 什么是 java 序列化?什么情况下需要序列化?

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

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

当 Java 对象需要在网络上传输 或者 持久化存储到文件中时,就需要对 Java 对象进行序列化处理。

序列化的实现:类实现 Serializable 接口,这个接口没有需要实现的方法。实现 Serializable 接口是为了告诉 jvm 这个类的对象可以被序列化

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

动态代理:就是当想要给实现了某个接口的类中的方法,加一些额外的处理。比如说加日志,加事务等。简单地说就是在运行时,创建目标类,可以调用和扩展目标类的方法,

主要应用的框架:Spring中的AOP,Struts2中的拦截器,加事务,加权限,加日志

60. 怎么实现动态代理?

首先必须定义一个接口,还要有一个InvocationHandler(将实现接口的类的对象传递给它)处理类。再有一个工具类Proxy(习惯性将其称为代理类,因为调用他的newInstance()可以产生代理对象,其实他只是一个产生代理对象的工具类)。利用到InvocationHandler,拼接代理类源码,将其编译生成代理类的二进制码,利用加载器加载,并将其实例化产生代理对象,最后返回


----------------------对象拷贝----------------------

61. 为什么要使用克隆?

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

克隆分浅克隆和深克隆,浅克隆后的对象中非基本对象和原对象指向同一块内存,因此对这些非基本对象的修改会同时更改克隆前后的对象。深克隆可以实现完全的克隆,可以用反射的方式或序列化的方式实现

62. 如何实现对象克隆?

有两种方式:

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

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

注意:基于序列化和反序列化实现的克隆不仅仅是深度克隆,更重要的是通过泛型限定,可以检查出要克隆的对象是否支持序列化,这项检查是编译器完成的,不是在运行时抛出异常,这种是方案明显优于使用Object类的clone方法克隆对象。让问题在编译的时候暴露出来总是优于把问题留到运行时

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

复制一个 Java 对象

浅拷贝:复制基本类型的属性;引用类型的属性复制,复制栈中的变量 和 变量指向堆内存中的对象的指针,不复制堆内存中的对象。

深拷贝:复制基本类型的属性;引用类型的属性复制,复制栈中的变量 和 变量指向堆内存中的对象的指针和堆内存中的对象。

----------------------Java Web----------------------

64. jsp 和 servlet 有什么区别?

jsp就是特别的servlet+html

Servlet 适合动态输出 Web 数据和业务逻辑处理,对于 html 页面内容的修改非常不方便;Jsp 是在 Html 代码中嵌入 Java 代码,适合页面的显示,内置对象不同,获取内置对象的方式不同,JSP中的内置对象都是必须通过HttpServletRequest对象,HttpServletResponse对象以及HttpServlet对象得到

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

JSP中一共预先定义了9个这样的对象,分别为:request、response、session、application、out、pagecontext、config、page、exception

Page:指的是JSP被翻译成Servlet的对象的引用。

pageContext:对象可以用来获得其他8个内置对象,还可以作为JSP的域范围对象使用,pageContext中存的值是当前的页面的作用范围

request:代表的是请求对象,可以用于获得客户机的信息,也可以作为域对象来使用,使用request保存的数据在一次请求范围内有效

Session:代表的是一次会话,可以用于保存用户的私有的信息,也可以作为域对象使用,使用session保存的数据在一次会话范围有效

Application:代表整个应用范围,使用这个对象保存的数据在整个web应用中都有效

Response:是响应对象,代表的是从服务器向浏览器响应数据

Out:JSPWriter是用于向页面输出内容的对象

Config:指的是ServletConfig用于JSP翻译成Servlet后 获得Servlet的配置的对象.

Exception:在页面中设置isErrorPage=”true”,即可使用,是Throwable的引用,用来获得页

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

4个JSP内置对象的作用域分别为:application、session、request、page

名称

作用域

application

在所有应用程序中有效

session

在当前会话中有效

request

在当前请求中有效

page

在当前页面有效

67. session 和 cookie 有什么区别?

一个在浏览器,一个在服务器,一个是ASCLL,一个是任何数据都可以储存,储存时间一个可以长期储存,一个不可以,隐秘性的区别,一个支持跨域,一个不支持

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

session 的工作原理是客户端登录完成之后,服务器会创建对应的 session,session 创建完之后,会把 session 的 id 发送给客户端,客户端再存储到浏览器中。这样客户端每次访问服务器时,都会带着 sessionid,服务器拿到 sessionid 之后,在内存找到与之对应的 session 这样就可以正常工作了

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

不能直接使用

但可以通过以下方法 :

  1. URL重写:URL重写要求将站点中的所有超链接都进行改造,在超链接后用一个特殊的参数JSESSIONID保存当前浏览器对应session的编号,这样一来,当用户点击超链接访问服务器时,服务器可以从URL后的参数中分析出JSESSIONID,从而找到对应的sesison使用
  2. 用文件、数据库等形式保存Session ID,在跨页过程中手动调用
  3. 设置php.ini配置文件中的“session.use_trans_sid = 1”,或者编译时打开打开了“–enable-trans-sid”选项,让PHP自动跨页传递Session ID

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

1. 机制:spring mvc的入口是servlet,而struts2是filter

2. 性能:spring会稍微比struts快。spring mvc是基于方法的设计,而sturts是基于类

3. 参数传递:struts是在接受参数的时候,可以用属性来接受参数,这就说明参数是让多个方法共享的

4. 设计思想上:struts更加符合oop(面向对象编程)的编程思想, spring就比较谨慎,在servlet上扩展

5. intercepter的实现机制:struts有自己的interceptor机制,spring mvc用的是独立的AOP方式

71. 如何避免 sql 注入?

1:遵循编程规范,首先执行预编译,随后再填写参数,这样参数会替换掉编译好的语句中的?占位符,最后执行完整的sql语句

2:使用存储过程,存储过程(Stored Procedure)是一组完成特定功能的SQL语句集,经编译后存储在数据库中,用户通过调用存储过程并给定参数(如果该存储过程带有参数)就可以执行它,也可以避免SQL注入攻击

3:mybatis半自动持久化框架,其底层原理也是预编译,参数替换占位符, 简单说,#{}是经过预编译的,是安全的;${}是未经过预编译的,仅仅是取变量的值,是非安全的,存在SQL注入

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

xss(Cross Site Scripting),即跨站脚本攻击,也就是代码注入攻击, 是一种常见于web应用程序中的计算机安全漏洞

避免 :

  • 获取用户的输入,不用innerHtml,用innerText.
  • 对用户的输入进行过滤,如对& < > " ' /等进行转义

不管是用户端从任何的输入到任何输出都进行过滤,转义,让攻击者的代码注入不能识别,就可以避免攻击了

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

CSRF:Cross Site Request Forgery(跨站点请求伪造)。
CSRF 攻击者在用户已经登录目标网站之后,诱使用户访问一个攻击页面,利用目标网站对用户的信任,以用户身份在攻击页面对目标网站发起伪造用户操作的请求,达到攻击目的

避免方法:

  • CSRF 漏洞进行检测的工具,如 CSRFTester、CSRF Request Builder...
  • 验证 HTTP Referer 字段
  • 添加并验证 token
  • 添加自定义 http 请求头
  • 敏感操作添加验证码
  • 使用 post 请求

----------------------异常----------------------

74. throw 和 throws 的区别?

throws是用来声明一个方法可能抛出的所有异常信息,throws是将异常声明但是不处理,而是将异常往上传,谁调用我就交给谁处理。

而throw则是指抛出的一个具体的异常类型

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

final:是用来修饰类,方法,变量,并具有不同的意义

fianlly:则是保证Java代码必须被执行的一种机制 : 使用try-finally或者try-catch-finally来进行1.关闭JDBC连接,2.保证unlock锁等动作

finalize则是java.lang.Object的一个方法,保证对象在被垃圾收集前完成特定资源的回收,所以称为java GC的阻碍,成为了特等公民,其次,finalize还可以吞掉Throwable,导致程序检查不出错误也无法运行,现在已经被定义为Old方法

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

以下三种情况都是可以的:
try-catch
try-finally
try-catch-finally
可以省略catch或者finally。catch和finally不可以同时省略

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

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

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

1. java.lang.nullpointerexception        空指针异常

2. java.lang.classnotfoundexception        指定类不存在

3. java.lang.illegalargumentexception        方法的参数错误

4.java.lang.ArrayIndexOutOfBoundsException        数组下标越界异常

5. NoSuchMethodException       方法未找到异常

6.java.lang.ExceptionInInitializerError        初始化程序错误

7.java.lang.InstantiationError        实例化错误

----------------------网络----------------------

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

301 redirect: 301 代表永久性转移(Permanently Moved)

302 redirect: 302 代表暂时性转移(Temporarily Moved )

详细来说,301和302状态码都表示重定向,就是说浏览器在拿到服务器返回的这个状态码后会自动跳转到一个新的URL地址,这个地址可以从响应的Location首部中获取(用户看到的效果就是他输入的地址A瞬间变成了另一个地址B)——这是它们的共同点。他们的不同在于。301表示旧地址A的资源已经被永久地移除了(这个资源不可访问了),搜索引擎在抓取新内容的同时也将旧的网址交换为重定向之后的网址;302表示旧地址A的资源还在(仍然可以访问),这个重定向只是临时地从旧地址A跳转到地址B,搜索引擎会抓取新的内容而保存旧的网址

80. forward 和 redirect 的区别?

1、请求方不同

redirect:客户端发起的请求

forward:服务端发起的请求

2、浏览器地址表现不同

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

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

3、参数传递不同

redirect:重新开始一个request,原页面的request生命周期结束

forward:forward另一个连接的时候。request变量是在其生命周期内的。另一个页面也可以使用,其实质是把目标地址include

4、底层运作不同

redirect:发送的请求信息又回送给客户机,让客户机再转发到另一个资源上,需要在服务器和客户机之间增加一次通信

forward:服务器端直接找到目标,并include过来

5、定义不同

直接转发方式(Forward):客户端和浏览器只发出一次请求,Servlet、HTML、JSP或其它信息资源,由第二个信息资源响应该请求,在请求对象request中,保存的对象对于每个信息资源是共享的

间接转发方式(Redirect)实际是两次HTTP请求,服务器端在响应第一次请求的时候,让浏览器再向另外一个URL发出请求,从而达到转发的目的

81. 简述 tcp 和 udp的区别?

TCP和UDP都是传输层的协议

udp面向无连接,数据量大,不稳定性 / tcp面向连接稳定,安全

TCP(Transmission Control Protocol,传输控制协议)提供的是面向连接的,可靠的字节流服务。通过三次握手建立连接,通讯完成时四次挥手,即客户和服务器交换数据前,必须现在双方之间建立一个TCP连接,之后才能传输数据。并且提供超时重发,丢弃重复数据,检验数据,流量控制等功能,保证数据能从一端传到另一端

UDP(User Data Protocol,用户数据报协议)是一个简单的面向数据报的运输层协议。它不提供可靠性,只是把应用程序传给IP层的数据报发送出去,但是不能保证它们能到达目的地。由于UDP在传输数据报前不用再客户和服务器之间建立一个连接,且没有超时重发等机制,所以传输速度很快

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

例:

第一次握手 a发给b,此时b知道ab是通的,但a还不知道

第二次握手是b发给a,此时a知道ab和ba都是通的,但b只知道ab通,不知道ba通不通!

第三次握手是a发给b,此时b也知道ba通的,完毕

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

tcp 粘包可能发生在发送端或者接收端,分别来看两端各种产生粘包的原因:

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

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

OSI模型分为七层,自下而上为 物理层(Physical Layer)、数据链路层(Data Link Layer)、网络层(Network Layer)、传输层(Transport Layer)、会话层(Session Layer)、表达层(Presentation Layer)、应用层(Application Layer)

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

在浏览器进行回退操作时,get请求是无害的,而post请求则会重新请求一次
get请求参数是连接在url后面的,而post请求参数是存放在requestbody内的
get请求因为浏览器对url长度有限制(不同浏览器长度限制不一样)对传参数量有限制,而post请求,为参数存放在requestbody内所以参数数量没有限制(事实上get请求也能在requestbody内携带参数,只不过不符合规定,有的浏览器能够获取到数据,而有的不能)
因为get请求参数暴露在url上,所以安全方面post比get更加安全
get请求浏览器会主动cache,post并不会,除非主动设置
get请求参数会保存在浏览器历史记录内,post请求并不会
get请求只能进行url编码,而post请求可以支持多种编码方式
get请求产生1个tcp数据包,post请求产生2个tcp数据包
浏览器在发送get请求时会将header和data一起发送给服务器,服务器返回200状态码,而在发送post请求时,会先将header发送给服务器,服务器返回100,之后再将data发送给服务器,服务器返回200OK

86. 如何实现跨域?

跨域:当浏览器执行脚本时会检查是否同源,只有同源的脚本才会执行,如果不同源即为跨域

jsonp,cros,nginx跨域

1、jsonp
利用了 script 不受同源策略的限制
缺点:只能 get 方式,易受到 XSS攻击

2、CORS(Cross-Origin Resource Sharing),跨域资源共享
当使用XMLHttpRequest发送请求时,如果浏览器发现违反了同源策略就会自动加上一个请求头 origin;
后端在接受到请求后确定响应后会在后端在接受到请求后确定响应后会在 Response Headers 中加入一个属性 Access-Control-Allow-Origin;
浏览器判断响应中的 Access-Control-Allow-Origin 值是否和当前的地址相同,匹配成功后才继续响应处理,否则报错
缺点:忽略 cookie,浏览器版本有一定要求

3、代理跨域请求
前端向发送请求,经过代理,请求需要的服务器资源
缺点:需要额外的代理服务器

4、Html5 postMessage 方法
允许来自不同源的脚本采用异步方式进行有限的通信,可以实现跨文本、多窗口、跨域消息传递
缺点:浏览器版本要求,部分浏览器要配置放开跨域限制

5、修改 document.domain 跨子域
相同主域名下的不同子域名资源,设置 document.domain 为 相同的一级域名
缺点:同一一级域名;相同协议;相同端口

6、基于 Html5 websocket 协议
websocket 是 Html5 一种新的协议,基于该协议可以做到浏览器与服务器全双工通信,允许跨域请求
缺点:浏览器一定版本要求,服务器需要支持 websocket 协议

7、document.xxx + iframe
通过 iframe 是浏览器非同源标签,加载内容中转,传到当前页面的属性中
缺点:页面的属性值有大小限制

87. 说一下 JSONP 实现原理?

创建一个回调函数,然后在远程服务上调用这个函数并且将JSON 数据形式作为参数传递,完成回调。将JSON数据填充进回调函数

----------------------设计模式----------------------

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

设计模式的定义:设计模式(Design Pattern)是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结,使用设计模式是为了可重用代码、让代码更容易被他人理解并且保证代码可靠性

创建型模式,共五种:
工厂方法模式、抽象工厂模式、单例模式、建造者模式、原型模式。
结构型模式,共七种:
适配器模式、装饰器模式、代理模式、外观模式、桥接模式、组合模式、享元模式。
行为型模式,共十一种:
策略模式、模板方法模式、观察者模式、迭代子模式、责任链模式、命令模式、备忘录 模式、状态模式、访问者模式、中介者模式、解释器模式


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

  • 简单工厂模式:是由一个工厂对象创建产品实例,简单工厂模式的工厂类一般是使用静态方法,通过不同的参数的创建不同的对象实例,可以生产结构中的任意产品,不能增加新的产品
  • 抽象工厂模式:提供一个创建一系列相关或相互依赖对象的接口,而无需制定他们具体的类,生产多个系列产品,生产不同产品族的全部产品,不能新增产品,可以新增产品族

----------------------Spring/Spring MVC----------------------

90. 为什么要使用 spring?

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

1.方便解耦,便于开发(Spring就是一个大工厂,可以将所有对象的创建和依赖关系维护都交给spring管理)

2.spring支持aop编程(spring提供面向切面编程,可以很方便的实现对程序进行权限拦截和运行监控等功能)

3.声明式事务的支持(通过配置就完成对事务的支持,不需要手动编程)

4.方便程序的测试,spring 对junit4支持,可以通过注解方便的测试spring 程序

5.方便集成各种优秀的框架()

6.降低javaEE API的使用难度(Spring 对javaEE开发中非常难用的一些API 例如JDBC,javaMail,远程调用等,都提供了封装,是这些API应用难度大大降低)
 

91. 解释一下什么是 aop?

通过AOP面向切面将非核心部分的共同的部分单独处理,还有IOC(控制反转)将创建对象交给第三方,并依依赖注入,说深一点就是就是将影响多个类的公共行为封装成一个模块就是所谓的切面,这样可以减少重复代码并且降低耦合

92. 解释一下什么是 ioc?

控制反转IoC(Inversion of Control)是说创建对象的控制权进行转移,以前创建对象的主动权和创建时机是由自己把控的,而现在这种权力转移到第三方,比如转移交给了IoC容器,它就是一个专门用来创建对象的工厂,你要什么对象,它就给你什么对象,有了 IoC容器,依赖关系就变了,原先的依赖关系就没了,它们都依赖IoC容器了,通过IoC容器来建立它们之间的关系

IoC是设计思想,IoC有三个核心:BeanFactory、反射、DI。BeanFactory利用反射实现对象的创建,DI实现对象关系管理

93. spring 有哪些主要模块?

1. Spring AOP 面相切面编程

2. Spring ORM Hibernate|mybatis|JDO

3. Spring Core 提供bean工厂 IOC

4. Spring Dao JDBC支持

5. Spring Context 提供了关于UI支持,邮件支持等

6. Spring Web 提供了web的一些工具类的支持

7. Spring MVC 提供了web mvc , webviews , jsp ,pdf ,export

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

Spring通过DI(依赖注入)实现IOC(控制反转),常用的注入方式主要有三种:构造方法注入,setter注入,基于注解的注入

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

不是线程安全的

原型Bean : 对于原型Bean,每次创建一个新对象,也就是线程之间并不存在Bean共享,自然是不会有线程安全的问题

单例Bean : 对于单例Bean,所有线程都共享一个单例实例Bean,因此是存在资源的竞争

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

Spring框架支持以下五种bean的作用域:

singleton:单例模式, 在整个Spring IoC容器中,使用 singleton 定义的 bean 只有一个实例

prototype:原型模式, 次通过容器的getbean方法获取 prototype 定义的 bean 时,都产生一个新的 bean 实例

只有在 Web 应用中使用Spring时,request、session、global-session 作用域才有效

request:对于每次 HTTP 请求,使用 request 定义的 bean 都将产生一个新实例,即每次 HTTP 请求将会产生不同的 bean 实例。
session:同一个 Session 共享一个 bean 实例。
global-session:同 session 作用域不同的是,所有的Session共享一个Bean实例。

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

自动装配的不同模式:

  • no - 这是默认设置,表示没有自动装配。应使用显式 Bean 引用进行装配
  • byName - 它根据 Bean 的名称注入对象依赖项。它匹配并装配其属性与 XML 文件中由相同名称定义的 Bean
  • 【最常用】byType - 它根据类型注入对象依赖项。如果属性的类型与 XML 文件中的一个 Bean 类型匹配,则匹配并装配属性
  • 构造函数 - 它通过调用类的构造函数来注入依赖项。它有大量的参数
  • autodetect - 首先容器尝试通过构造函数使用 autowire 装配,如果不能,则尝试通过 byType 自动装配

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

编程式事务和声明式事务两种实现方式

编程式事务允许用户在代码中精确定义事务的边界,而声明式事务(基于AOP)有助于用户将操作与事务规则进行解耦

简单地说,编程式事务侵入到了业务代码里面,但是提供了更加详细的事务管理;而声明式事务由于基于AOP,所以既能起到事务管理的作用,又可以不影响业务代码的具体实现

事务的4个特性:原子性 / 一致性 / 隔离性 / 持久性

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

分五个级别 :

默认 ISOLATION_DEFAULT(使用数据库的设置)

读未提交(Read uncommitted)          安全性最差,可能发生并发数据问题,性能最好

读提交(read committed)      Oracle默认的隔离级别--效率较低,安全性较高

可重复读(repeatable read)MySQL默认的隔离级别,安全性较好,性能一般

串行化(Serializable)       表级锁,读写都加锁,效率低下,安全性高,不能并发

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

1.用户发送请求至前端控制器DisptcherServlet

2.前端控制器(DispatcherServlet)收到请求调用处理器映射器(HandlerMapping)

3.处理器映射器(HandlerMapping)找到具体的处理器(可根据xml配置文件,注解进行查找),生成处理器对象及处理器拦截器(如果有则生成)一并返回给前端控制器(DispatcherServlet)

4.前端控制器(DispatcherServlet)调用处理器适配器(HandlerAdapter)

5.处理器适配器(HandlerAdapter)经过适配调用具体的处理器(后端控制器Controller)

6.后端控制器(Controller)执行完成返回到对象ModelAndView

7.处理器适配器(HandlerAdapter)将后端控制器(Controller)执行的结果ModelAndView 返回给前端控制器(DispatcherServlet)

8.前端控制器(DispatcherServlet)将ModelAndView传给视图解析器(ViewReslover)

9.视图解析器(ViewReslover)解析后返回具体的View

10前端控制器(DispatcherServlet)根据View进行渲染视图(即将模型数据填充到视图中)

11.前端控制器(DispatcherServlet) 响应用户

101. spring mvc 有哪些组件?

前端控制器(DispatcherServlet)
处理器映射器(HandlerMapping)
处理器适配器(HandlerAdapter)
拦截器(HandlerInterceptor)
语言环境处理器(LocaleResolver)
主题解析器(ThemeResolver)
视图解析器(ViewResolver)
文件上传处理器(MultipartResolver)
异常处理器(HandlerExceptionResolver)
数据转换(DataBinder)
消息转换器(HttpMessageConverter)
请求转视图翻译器(RequestToViewNameTranslator)
页面跳转参数管理器(FlashMapManager)
处理程序执行链(HandlerExecutionChain)

102. @RequestMapping 的作用是什么?

@RequestMapping是一个用来处理请求地址映射的注解,可用于类或者方法上。用于类上,表示类中的所有响应请求的方法都是以该地址作为父路径

103. @Autowired 的作用是什么?

@Autowired 是一个注释,它可以对类成员变量、方法及构造函数进行标注,让 spring 完成 bean 自动装配的工作
@Autowired 默认是按照类去匹配,配合 @Qualifier 指定按照名称去装配 bean

spring mvc常用注解:

@Controller          标识是一个Controller,Spring包扫描创建实例

@RequestMapping      请求后的映射路径

@PathVariable        标识接收单个参数

@ResponseBody        返回对象利用jackson工具类转换为json字符串

@RequestParam        参数名和请求参数名称不同时使用,可以设置默认值

----------------------Spring Boot/Spring Cloud----------------------

104. 什么是 spring boot?

Spring Boot是由Pivotal团队提供的全新框架,其设计目的是用来简化新Spring应用的初始搭建以及开发过程 / 简单的说就是 : 减少许多文件的配置,封装许多框架的使用方法

Spring Boot的核心功能

1、 可独立运行的Spring项目:Spring Boot可以以jar包的形式独立运行
2、 内嵌的Servlet容器:Spring Boot可以选择内嵌Tomcat、Jetty或者Undertow,无须以war包形式部署项目
3、 简化的Maven配置:Spring提供推荐的基础 POM 文件来简化Maven 配置
4、 自动配置Spring:Spring Boot会根据项目依赖来自动配置Spring 框架,极大地减少项目要使用的配置
5、 提供生产就绪型功能:提供可以直接在生产环境中使用的功能,如性能指标、应用信息和应用健康检查
6、 无代码生成和xml配置:Spring Boot不生成代码。完全不需要任何xml配置即可实现Spring的所有配置

105. 为什么要用 spring boot?

使用SpringBoot的最大好处就是简化配置,它实现了自动化配置。

(1)简化配置,不需要编写太多的xml配置文件;

(2)基于Spring构建,使开发者快速入门,门槛很低;

(3)SpringBoot可以创建独立运行的应用而不需要依赖于容器;

(4)内置tomcat服务器,不需要打包成war包,可以直接放到tomcat中运行;

(5)提供maven极简配置,以及可视化的相关监控功能,比如性能监控,应用的健康程度等;

(6)为微服务SpringCloud奠定了基础,使得微服务的构建变得简单;

(7)Spring可以整合很多各式各样的框架,并能很好的集成;

(8)活跃的社区与论坛,以及丰富的开发文档;

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

Spring Boot 有两种类型的配置文件,application 和 bootstrap 文件
Spring Boot会自动加载classpath目前下的这两个文件,文件格式为 properties 或 yml 格式

*.properties 文件是 key=value 的形式
*.yml 是 key: value 的形式
*.yml 加载的属性是有顺序的,但不支持 @PropertySource 注解来导入配置,一般推荐用yml文件,看起来更加形象

bootstrap 配置文件是系统级别的,用来加载外部配置,如配置中心的配置信息,也可以用来定义系统不会变化的属性.bootstatp 文件的加载先于application文件
application 配置文件是应用级别的,是当前应用的配置文件

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

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

bootstrap 配置文件是系统级别的,用来加载外部配置,如配置中心的配置信息,也可以用来定义系统不会变化的属性.bootstatp 文件的加载先于application文件
application 配置文件是应用级别的,是当前应用的配置文件

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

1、模板热部署

2、使用调试模式Debug实现热部署

3、spring-boot-devtools

4、Spring Loaded

5、JRebel


109. jpa 和 hibernate 有什么区别?

JPA和Hibernate之间的主要区别在于JPA是一个规范。Hibernate是Red Hat对JPA规范的实现,但是其功能是JPA的超集。

110. 什么是 spring cloud?

微服务架构,是在Spring Boot 基础上构建的,用于快速构建分布式系统的通用模式的工具集

Spring Cloud有以下特点:

1.约定优于配置

2.适用于各种环境.开发,部署在PC Server 或各种云环境均可

3.隐藏了组件的复杂性,并提供声明式,无xml的配置方式

4.开箱即用

5.轻量级的组件. Spring Cloud整合的组件大多比较轻量.例如Eureka,Zuul,等等

6.组件丰富,功能齐全. Spring Cloud 为微服务架构提供了非常完整的支持.例如,配置管理,服务发现,断路器,微服务网关等;

7.选型中立,丰富. 例如,Spring Cloud 支持使用Eureka,Zookeeper或Consul实现服务发现.

8.灵活.Spring Cloud的组成部分是解耦的,开发人员可按需灵活挑选技术选型.

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

当一个服务调用另一个服务由于网络原因或者自身原因出现问题时,调用者就会等被调用者的响应,当更多的服务请求到这些资源时,导致更多的请求等待,这素以会发生连锁效应,断路器就是解决这一问题的。

        断路器有三种状态,完全打开状态、半开状态、关闭态。

完全打开态:一定时间内,达到一定的次数无法调用,并且多次检测没有恢复的迹象,断路器完全打开,那么下次的请求不会到该服务;
半开:短时间内有回复迹象,断路器会将部分请求发送给服务,当能正常调用时,断路器关闭。
关闭:当服务一直处于正常状态,能正常调用,断路器关闭

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

nacos:服务注册于发现。
Feign:基于动态代理机制,根据注解和选择的机器,拼接请求 url 地址,发起请求。
nginx:实现负载均衡,从一个服务的多台机器中选择一台。
Hystrix:提供线程池,不同的服务走不同的线程池,实现了不同服务调用的隔离,避免了服务雪崩的问题。
gateway:网关管理,由 Zuul 网关转发请求给对应的服务。

-----------------------------------Hibernate-----------------------------------

113. 为什么要使用 hibernate?

114. 什么是 ORM 框架?

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

116. hibernate 有几种查询方式?

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

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

119. hibernate 是如何工作的?

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

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

122. hibernate 对象有哪些状态?

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

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

-----------------------------------Mybatis-----------------------------------

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

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

2、MyBatis在处理#{}时,会将SQL中的#{}替换为?号,使用PreparedStatement的set方法来赋值;MyBatis在处理 $ { } 时,就是把 ${ } 替换成变量的值。

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

126. mybatis 有几种分页方式?

1.数组分页

2.SQL分页

3.拦截器分页

4.RowBounds分页

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

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

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

逻辑分页: 从数据库将所有记录查询出来,存储到内存中,展示当前页,然后数据再直接从内存中获取。优点:效率高;缺点:占用内存比较高。

物理分页: 只从数据库中查询当前页的数据。优点:不占用很多内存;缺点:效率比价低(相比于逻辑分页)。

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

Mybatis仅支持association关联对象和collection关联集合对象的延迟加载,association指的就是一对一,collection指的就是一对多查询。在Mybatis配置文件中,可以配置是否启用延迟加载lazyLoadingEnabled=true|false。

它的原理是,使用CGLIB创建目标对象的代理对象,当调用目标方法时,进入拦截器方法,比如调用a.getB().getName(),拦截器invoke()方法发现a.getB()是null值,那么就会单独发送事先保存好的查询关联B对象的sql,把B查询上来,然后调用a.setB(b),于是a的对象b属性就有值了,接着完成a.getB().getName()方法的调用。这就是延迟加载的基本原理。

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

一级缓存: 基于 PerpetualCache 的 HashMap 本地缓存,其存储作用域为 Session,当 Session flush 或 close 之后,该 Session 中的所有 Cache 就将清空,默认打开一级缓存。

二级缓存与一级缓存其机制相同,默认也是采用 PerpetualCache,HashMap 存储,不同在于其存储作用域为 Mapper(Namespace),并且可自定义存储源,如 Ehcache。默认不打开二级缓存,要开启二级缓存,使用二级缓存属性类需要实现Serializable序列化接口(可用来保存对象的状态),可在它的映射文件中配置;

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

Mybatis和hibernate不同,它不完全是一个ORM框架,因为MyBatis需要程序员自己编写Sql语句。

Mybatis直接编写原生态sql,可以严格控制sql执行性能,灵活度高,非常适合对关系数据模型要求不高的软件开发,因为这类软件需求变化频繁,一但需求变化要求迅速输出成果。但是灵活的前提是mybatis无法做到数据库无关性,如果需要实现支持多种数据库的软件,则需要自定义多套sql映射文件,工作量大。

Hibernate对象/关系映射能力强,数据库无关性好,对于关系模型要求高的软件,如果用hibernate开发可以节省很多代码,提高效率。

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

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批处理相同。

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

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

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

Mybatis自定义插件针对Mybatis四大对象(Executor、StatementHandler 、ParameterHandler 、ResultSetHandler )进行拦截,具体拦截方式为:

  • Executor:拦截执行器的方法(log记录)

  • StatementHandler :拦截Sql语法构建的处理

  • ParameterHandler :拦截参数的处理

  • ResultSetHandler :拦截结果集的处理

Mybatis自定义插件必须实现Interceptor接口:

自定义插件demo:

一个@Intercepts可以配置多个@Signature,@Signature中的参数定义如下:

  • type:表示拦截的类,这里是Executor的实现类;

  • method:表示拦截的方法,这里是拦截Executor的update方法;

  • args:表示方法参数。

-----------------------------------RabbitMQ-----------------------------------

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

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

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

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

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

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

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

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

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

144. rabbitmq 有几种广播类型?

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

146. rabbitmq 集群有什么用?

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

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

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

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

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

-----------------------------------Kafka-----------------------------------

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

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

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

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

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

-----------------------------------Zookeeper-----------------------------------

157. zookeeper 是什么?

158. zookeeper 都有哪些功能?

159. zookeeper 有几种部署模式?

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

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

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

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

-----------------------------------MySql-----------------------------------

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

1、第一范式:

当关系模式R的所有属性都不能在分解为更基本的数据单位时,称R是满足第一范式的,简记为1NF。满足第一范式是关系模式规范化的最低要求,否则,将有很多基本操作在这样的关系模式中实现不了。

2、第二范式:

如果关系模式R满足第一范式,并且R得所有非主属性都完全依赖于R的每一个候选关键属性,称R满足第二范式,简记为2NF。

3、第三范式:

设R是一个满足第一范式条件的关系模式,X是R的任意属性集,如果X非传递依赖于R的任意一个候选关键字,称R满足第三范式,简记为3NF。

165. 一张自增表里面总共有 7 条数据,删除了最后 2 条数据,重启 mysql 数据库,又插入了一条数据,此时 id 是几?

8或者6

一般情况下,我们创建的表的类型是InnoDB,如果新增一条记录(不重启mysql的情况下),这条记录的id是8;但是如果重启(文中提到的)MySQL的话,这条记录的ID是6。因为InnoDB表只把自增主键的最大ID记录到内存中,所以重启数据库或者对表OPTIMIZE操作,都会使最大ID丢失。

但是,如果我们使用表的类型是MylSAM,那么这条记录的ID就是8。因为MylSAM表会把自增主键的最大ID记录到数据文件里面,重启MYSQL后,自增主键的最大ID也不会丢失。

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

方法一:

  [root@db01 ~]# mysql 登录的时候会显示数据库的版本

方法二:

  mysql> status;

方法三:

  mysql> select version();

167. 说一下 ACID 是什么?

ACID 一般是指数据库事务的ACID,也就是数据库四大特性

1.Atomicity 原子性

2.Consistency 一致性

3.Isolation 隔离性

4.Durability 持久性

Atomicity(原子性):一个事务(transaction)中的所有操作,或者全部完成,或者全部不完成,不会结束在中间某个环节。事务在执行过程中发生错误,会被恢复(Rollback)到事务开始前的状态,就像这个事务从来没有执行过一样。即,事务不可分割、不可约简。
Consistency(一致性):在事务开始之前和事务结束以后,数据库的完整性没有被破坏。这表示写入的资料必须完全符合所有的预设约束、触发器、级联回滚等。
Isolation(隔离性):数据库允许多个并发事务同时对其数据进行读写和修改的能力,隔离性可以防止多个事务并发执行时由于交叉执行而导致数据的不一致。事务隔离分为不同级别,包括读未提交(Read uncommitted)、读提交(read committed)、可重复读(repeatable read)和串行化(Serializable)。
Durability(持久性):事务处理结束后,对数据的修改就是永久的,即便系统故障也不会丢失。

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

char长度固定不可变;var char长度可变。char如果插入的长度小于定义长度时,则用空格填充;varchar小于定义长度时,还是按实际长度存储,插入多长就存多长。

对 char 来说,最多能存放的字符个数 255,和编码无关。
而 varchar 呢,最多能存放 65532 个字符。varchar的最大有效长度由最大行大小和使用的字符集确定。整体最大长度是 65,532字节。

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

1、精度不一样,float是单精度,double是双精度;

2、表示小数的范围不一样,double能表示的范围比float大;

3、double在内存中,占8个字节,float在内存中,占4个字节。

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

1.内连接,显示两个表中有联系的所有数据;

2.左链接,以左表为参照,显示所有数据,右表中没有则以null显示

3.右链接,以右表为参照显示数据,,左表中没有则以null显示

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

索引是满足某种特定查找算法的数据结构,而这些数据结构会以某种方式指向数据,从而实现高效查找数据。具体来说 MySQL 中的索引,不同的数据引擎实现有所不同,但目前主流的数据库引擎的索引都是 B+ 树实现的,B+ 树的搜索效率,可以到达二分法的性能,找到数据区域之后就找到了完整的数据结构了,所有索引的性能也是更好的。

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

使用 explain 查看 SQL 是如何执行查询语句的,从而分析你的索引是否满足需求。explain 语法:explain select * from table where type=1。

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

MySQL 的事务隔离是在 MySQL. ini 配置文件里添加的,在文件的最后添加:

transaction-isolation = REPEATABLE-READ 1 可用的配置值:READ-UNCOMMITTED、READ-COMMITTED、REPEATABLE-READ、SERIALIZABLE。READ-UNCOMMITTED:未提交读,最低隔离级别、事务未提交前,就可被其他事务读取(会出现幻读、脏读、不可重复读)。

读提交

读未提交

可重复读

串行化

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

MySQL存储引擎主要有:MyIsam、InnoDB、Memory、Blackhole、CSV、Performance_Schema、Archive、Federated、Mrg_Myisam。

但是最常用的是InnoDB和Mylsam。

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

MyISAM 只支持表锁,InnoDB 支持表锁和行锁,默认为行锁。表级锁:开销小,加锁快,不会出现死锁。锁定粒度大,发生锁冲突的概率最高,并发量最低。行级锁:开销大,加锁慢,会出现死锁。锁力度小,发生锁冲突的概率小,并发度最高。

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

乐观锁:每次去拿数据的时候都认为别人不会修改,所以不会上锁,但是在提交更新的时候会判断一下在此期间别人有没有去更新这个数据。

悲观锁:每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁,这样别人想拿这个数据就会阻止,直到这个锁被释放。数据库的乐观锁需要自己实现,在表里面添加一个 version 字段,每次修改成功值加 1,这样每次修改的时候先对比一下,自己拥有的 version 和数据库现在的 version 是否一致,如果不一致就不修改,这样就实现了乐观锁。

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

使用 show processlist 命令查看当前所有连接信息。使用 explain 命令查询 SQL 语句执行计划。开启慢查询日志,查看慢查询的 SQL。

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

为搜索字段创建索引。

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

垂直分割分表。

选择正确的存储引擎。

-----------------------------------Redis-----------------------------------

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

Redis:REmote DIctionary Server(远程字典服务器)

是一个高性能的(key/value)分布式内存数据库,基于内存运行
并支持持久化的NoSQL数据库,是当前最热门的NoSql数据库之一,
也被人们称为数据结构服务器。

使用场景:

  1. 内存存储和持久化:redis支持异步将内存中的数据写到硬盘上,同时不影响继续服务
  2. 取最新N个数据的操作,如:可以将最新的10条评论的ID放在Redis的List集合里面
  3. 模拟类似于HttpSession这种需要设定过期时间的功能
  4. 发布、订阅消息系统
  5. 定时器、计数器

180. redis 有哪些功能?

  1. 数据缓存功能
  2. 分布式锁的功能
  3. 支持数据持久化
  4. 支持事务
  5. 支持消息队列

181. redis 和 memecache 有什么区别?

1、存储方式不同

memecache 把数据全部存在内存之中,断电后会挂掉,数据不能超过内存大小;redis有部份存在硬盘上,这样能保证数据的持久性,支持数据的持久化(笔者注:有快照和AOF日志两种持久化方式,在实际应用的时候,要特别注意配置文件快照参数,要不就很有可能服务器频繁满载做dump)。 

2、数据支持类型不同

redis在数据支持上要比memecache多的多。 

3、使用底层模型不同

新版本的redis直接自己构建了VM 机制 ,因为一般的系统调用系统函数的话,会浪费一定的时间去移动和请求。 

4、运行环境不同 

redis目前官方只支持LINUX 上去行,从而省去了对于其它系统的支持,这样的话可以更好的把精力用于本系统 环境上的优化,虽然后来微软有一个小组为其写了补丁。但是没有放到主干上。

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

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

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

如果在请求数据时,在缓存层和数据库层都没有找到符合条件的数据,也就是说,在缓存层和数据库层都没有命中数据,那么,这种情况就叫作缓存穿透。

第一种解决方案:就是把空对象缓存起来。当第一次从数据库中查询出来的结果为空时,我们就将这个空对象加载到缓存,并设置合理的过期时间,这样,就能够在一定程度上保障后端数据库的安全。

第二种解决缓存穿透问题的解决方案:就是使用布隆过滤器,布隆过滤器可以针对大数据量的、有规律的键值进行处理。一条记录是不是存在,本质上是一个Bool值,只需要使用 1bit 就可以存储。我们可以使用布隆过滤器将这种表示是、否等操作,压缩到一个数据结构中。比如,我们最熟悉的用户性别这种数据,就非常适合使用布隆过滤器来处理。

 

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

Redis支持五种数据类型:string(字符串),hash(哈希),list(列表),set(集合)及zset(sorted set:有序集合)。

185. redis 支持的 java 客户端都有哪些?

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

186. jedis 和 redisson 有哪些区别?

Jedis 和 Redisson 都是Java中对Redis操作的封装。Jedis 只是简单的封装了 Redis 的API库,可以看作是Redis客户端,它的方法和Redis 的命令很类似。Redisson 不仅封装了 redis ,还封装了对更多数据结构的支持,以及锁等功能,相比于Jedis 更加大。但Jedis相比于Redisson 更原生一些,更灵活。

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

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

一种是RDB持久化(原理是将Reids在内存中的数据库记录定时dump到磁盘上的RDB持久化),另外一种是AOF持久化(原理是将Reids的操作日志以追加的方式写入文件)。

RDB持久化是指在指定的时间间隔内将内存中的数据集快照写入磁盘,实际操作过程是fork一个子进程,先将数据集写入临时文件,写入成功后,再替换之前的文件,用二进制压缩存储。

AOF持久化以日志的形式记录服务器所处理的每一个写、删除操作,查询操作不会记录,以文本的方式记录,可以打开文件看到详细的操作记录。

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

为了保证分布式锁的可用性,至少要确保锁的实现要同时满足以下几点:

  • 互斥性。在任何时刻,保证只有一个客户端持有锁。
  • 不能出现死锁。如果在一个客户端持有锁的期间,这个客户端崩溃了,也要保证后续的其他客户端可以上锁。
  • 保证上锁和解锁都是同一个客户端。

一般来说,实现分布式锁的方式有以下几种:

  • 使用MySQL,基于唯一索引。
  • 使用ZooKeeper,基于临时有序节点。
  • 使用Redis基于setnx命令

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

1)setnx、expire是分两步操作而非一个原子性操作,可能会出现setnx成功,expire失败的情况下,导致锁没有设置过期时间而变成死锁;

2)没有设置等待时间,获取锁失败则不会尝试重新获取锁了。

3)释放锁时,判断锁是否已锁、是不是自己的锁、释放锁也是分了三步操作而非一个原子性操作。可能会出现判断是自己的锁了,即将执行释放锁操作但还未执行时,如果锁在此时超时释放了,别的线程同时获得了这个锁,我们继续执行释放锁的操作会导致释放了别人的锁;

4)没有实现锁的超时续期,导致可能业务还没执行完就过期释放了这个锁,从而出现线程安全问题;

5)上锁失败,就判断是否设置了过期时间,若是没有,则给它设置过期时间;这里虽然可以避免了死锁的问题,但是不够严谨,无法判断别的线程业务代码的执行时间,过期时间设置无法确定合不合理

191. redis 如何做内存优化?

1、缩减键值对象

2、共享对象池

3、字符串优化

4、编码优化

5、控制key的数量

192. redis 淘汰策略有哪些?

  • noeviction: 不删除策略, 达到最大内存限制时, 如果需要更多内存, 直接返回错误信息。 大多数写命令都会导致占用更多的内存(有极少数会例外, 如 DEL )。
  • allkeys-lru: 所有key通用; 优先删除最近最少使用(less recently used ,LRU) 的 key。
  • volatile-lru: 只限于设置了 expire 的部分; 优先删除最近最少使用(less recently used ,LRU) 的 key。
  • allkeys-random: 所有key通用; 随机删除一部分 key。
  • volatile-random: 只限于设置了 expire 的部分; 随机删除一部分 key。
  • volatile-ttl: 只限于设置了 expire 的部分; 优先删除剩余时间(time to live,TTL) 短的key。

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 的主要组成部分?及其作用?

JVM:类加载器,运行时数据区(Java内存),执行引擎,本地接口

1.类加载器(Class Loader):加载类文件到内存。Class loader只管加载,只要符合文件结构就加载,至于能否运行,它不负责,那是有Exectution Engine 负责的。

2.执行引擎(Execution Engine):也叫解释器,负责解释命令,交由操作系统执行。

3.本地库接口(Native Interface):本地接口的作用是融合不同的语言为java所用

4.运行时数据区(Runtime Data Area):

 

 

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

Java虚拟机在执行Java程序的过程中会把它管理的内存分为若干个不同的数据区域。这些区域有着各自的用途,一级创建和销毁的时间,有的区域随着虚拟机进程的启动而存在,有些区域则依赖用户线程的启动和结束而建立和销毁

 

196. 说一下堆栈的区别?

堆与栈的区别有:1、栈由系统自动分配,而堆是人为申请开辟;2、栈获得的空间较小,而堆获得的空间较大;3、栈由系统自动分配,速度较快,而堆一般速度比较慢;4、栈是连续的空间,而堆是不连续的空间。
堆和栈的区别主要有五大点,分别是:
1、申请方式的不同。栈由系统自动分配,而堆是人为申请开辟;
2、申请大小的不同。栈获得的空间较小,而堆获得的空间较大;
3、申请效率的不同。栈由系统自动分配,速度较快,而堆一般速度比较慢;
4、存储内容的不同。栈在函数调用时,函数调用语句的下一条可执行语句的地址第一个进栈,然后函数的各个参数进栈,其中静态变量是不入栈的。而堆一般是在头部用一个字节存放堆的大小,堆中的具体内容是人为安排;
5、底层不同。栈是连续的空间,而堆是不连续的空间。

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

1.队列(Queue):是限定只能在表的一端进行插入和在另一端进行删除操作的线性表

2.栈(Stack):是限定只能在表的一端进行插入和删除操作的线性表

3.队列先进先出(FIFO),栈先进后出(FILO)

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

双亲委派模型要求除顶层启动类加载器外其余类加载器都应该有自己的父类加载器;类加载器之间通过复用关系来复用父加载器的代码

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

类加载的过程主要分为三个部分:

  • 加载:加载指的是把class字节码文件从各个来源通过类加载器装载入内存中。

  • 链接

  • 初始化

而链接又可以细分为三个小部分:

  • 验证

  • 准备

  • 解析

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

什么是垃圾?

  • 简单来说就是内存中已经不在使用到的空间就是垃圾
  • 垃圾是指在运行程序中没有任何指针指向的对象,这个对象就是需要被回收的垃圾。

一般有两种方法来判断:

引用计数器:为每个对象创建一个引用计数,有对象引用时计数器 +1,引用被释放时计数 -1,当计数器为 0 时就可以被回收。它有一个缺点不能解决循环引用的问题;

可达性分析:从 GC Roots 开始向下搜索,搜索所走过的路径称为引用链。当一个对象到 GC Roots 没有任何引用链相连时,则证明此对象是可以被回收的。

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

强引用(strong reference):

就是指在程序代码之中普遍存在的,类似“Object obj=new Object()” 这类的引用,只要强引用还存在,垃圾收集器永远不会回收掉被引用的对象实例。

软引用(soft reference):

一些有用但是并非必需,用软引用关联的对象,系统将要发生OOM之前,这些对象就会被回收

弱引用(weak reference):

是一些有用(程度比软引用更低)但是并非必需,用弱引用关联的对象,只能生存到下一次垃圾回收之前,GC发生时,不管内存够不够,都会被回收

虚引用(phantom reference):

最弱,被垃圾回收的时候收到一个通知

一个对象 实例是否有虚引用的存在,完全不会对其生存时间构成影响,也无法通过虚引用 来取得一个对象实例。为一个对象设置虚引用关联的唯一目的就是能在这个对象 实例被收集器回收时收到一个系统通知

202. 说一下 jvm 有哪些垃圾回收算法?

常用的垃圾回收算法有四种:标记-清除算法、复制算法、标记-整理算法、分代收集算法。

203. 说一下 jvm 有哪些垃圾回收器?

新生代收集器:

Serial
ParNew
Parallel Scavenge


老年代收集器:

Serial Old
CMS
Parallel Old


堆内存垃圾收集器:

G1

204. 详细介绍一下 CMS 垃圾回收器?

CMS全称为:Concurrent Mark Sweep意为并发标记清除,他使用的是标记清除法。主要关注系统停顿时间。

CMS 处理过程有七个步骤:
1. 初始标记(CMS-initial-mark) ,会导致swt;
2. 并发标记(CMS-concurrent-mark),与用户线程同时运行;
3. 预清理(CMS-concurrent-preclean),与用户线程同时运行;
4. 可被终止的预清理(CMS-concurrent-abortable-preclean) 与用户线程同时运行;
5. 重新标记(CMS-remark) ,会导致swt;
6. 并发清除(CMS-concurrent-sweep),与用户线程同时运行;
7. 并发重置状态等待下次CMS的触发(CMS-concurrent-reset),与用户线程同时运行;

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自带监控工具:jconsole和jvisualvm,第三方有:
MAT(Memory AnalyzerTool)、GChisto。 jconsole,Java Monitoring and Management Console是从java5开始,在JDK中自带的
java监控和管理控制台,用于对JVM中内存, 线程和类等的监控。
jvisualvm,jdk自带全能工具,可以分析内存快照、线程快照;监控内存变化、GC变化等。
MAT,Memory Analyzer Tool,一个基于Eclipse的内存分析工具,是一个快速、功能丰富
的Javaheap分析工具,它可以帮助我们查找内存泄漏和减少内存消耗。
GChisto,一款专业分析gc日志的工具。

208. 常用的 jvm 调优的参数都有哪些?

jps,JVM Process Status Tool,显示指定系统内所有的HotSpot虚拟机进程。
jstat,JVM statistics Monitoring是用于监视虚拟机运行时状态信息的命令,它可以显示出
虚拟机进程中的类装载、内存、垃圾收集、JIT编译等运行数据。
jmap,JVM Memory Map命令用于生成heap dump文件
jhat,JVM Heap Analysis Tool命令是与jmap搭配使用,用来分析jmap生成的dump,jhat
内置了一个微型的HTTP/HTML服务器,生成dump的分析结果后,可以在浏览器中查看
jstack,用于生成java虚拟机当前时刻的线程快照。
jinfo,JVM Configuration info 这个命令作用是实时查看和调整虚拟机运行参数。


 


http://www.ppmy.cn/news/775093.html

相关文章

Eclipse架构演进

Eclipse软件架构 Kim Moir 实现软件模块化是一项众所周知的艰巨任务。与由不同社区编写的庞大代码库的互操作性也很难管理。在Eclipse&#xff0c;我们在这两方面都取得了成功。2010 年 6 月&#xff0c;Eclipse 基金会发布了 Helios 协调版本&#xff0c;来自 40 多家公司的 …

javaGUI学习1:GUI框架,工具介绍

1、AWT ​ AWT(Abstract Window Toolkit)&#xff0c;中文译为抽象窗口工具包&#xff0c;该包提供了一套与本地图形界面进行交互的接口&#xff0c;是Java提供的用来建立和设置Java的图形用户界面的基本工具。AWT中的图形函数与操作系统所提供的图形函数之间有着一一对应的关…

JVM(一)常见知识点及概述

思维导图 一、常见知识点 1.用户线程与内存线程&#xff1a; 1.1 多对一&#xff1a;不需要切换&#xff0c;线程创建、调度、同步非常快&#xff1b;但是如果其中一个用户线程阻塞会造成其他线程无法执行&#xff0c;且无法像内核线程一样实现较完整的调度、优先级&#xff…

使echarts图例legend只选中一个(selectedMode)

例如&#xff1a;两个块选中第一个&#xff0c;第二个自动取消&#xff0c;选第二个&#xff0c;第一个取消 selectedMode: single,

【Mysql】Linux 安装主从配置全流程

安装参考地址 https://dev.mysql.com/doc/refman/8.0/en/linux-installation-yum-repo.html "EL6"指的是Enterprise Linux 6&#xff0c;它是基于Red Hat Enterprise Linux (RHEL) 6版本的操作系统。这里可以指 Centos6 先更新再安装 sudo yum update sudo yum i…

获取component组件的name名称

方法1&#xff1a;component.name import sgComponent from "/vue/components/sgComponent"; sgComponent.name 就是组件的name 方法2&#xff1a;this.$options.name 在组件自身内部console.log(this.$options.name) 可以获取自己的name 此外&#xff0c;this.$op…

ChatGPT前身GPT的论文-译文

写在前面 论文 Improving Language Understanding by Generative Pre-Training 地址 https://www.cs.ubc.ca/~amuham01/LING530/papers/radford2018improving.pdf ChatGPT火了&#xff0c;改论文作为ChatGPT的前身&#xff0c;可以从这里看到ChatGPT的原始影子。 摘要 自然语言…

Win10拨号上网无法开启热点

Win10拨号上网无法开启热点 网上看了很多教程&#xff0c;比如更改适配器配置啊修改共享啊啥的&#xff0c;弄了半天啥也没做好。 最简单的方法&#xff0c;直接下载一个360随身WiFi&#xff0c;简单有效