1.12 fail-fast机制和fail-safe机制分别有什么作用;
fail-fast机制和fail-safe机制是多线程并发操作集合时的失败处理机制;
fail-fast表示快速失败,在集合遍历过程中,一旦发现容器的数据被修改了,会立刻抛出ConcurrentModificationException,从而导致遍历失败;
Java.util包下的集合类都是fail-fast机制,常见使用fail-fast方式遍历的容器有HashMap、ArrayList等;
fail-safe表示失败安全,在这种机制下,出现集合元素的修改不会抛出ConcurrentModificationException,因为采用fail-safe机制的集合容器,在遍历时不是直接在集合内容上访问的,而是先复制原有集合内容,在复制的集合上进行遍历,所以在遍历过程中对原集合所做的修改不会被迭代器检测到;
Java.util.concurrent包下的容器都是fail-safe机制的,可以在多线程下并发使用、并发修改;常见的采用fail-safe机制的容器有ConcurrentHashMap、CopyOnWriteArrayList等;
1.13 如何理解序列化和反序列化;
序列化的核心目的是要解决网络通信中的对象传输问题;序列化就是将内存中的对象转化为字节流;
反序列化就是根据从文件或者网络上获得的字节流数据,根据字节流中保存的描述信息和状态重新构建一个新的对象。
1.13.1 序列化的前提;
序列化的前提是保证通信双方对于对象的可识别性,在很多时候我们通常会把对象先转化为通用的解析格式,比如JSON、XML等,再把他们转化为数据流进行传输,从而提高跨平台和跨语言的可识别性。
1.13.2 如何在实际的应用中选择序列化技术;
1.根据序列化之后的数据大小;
2.序列化的性能;
3.是否支持跨平台和跨语言;
4.技术的成熟度;
1.14 什么是SPI,它有什么用;
SPI全称是Service Provider Interface,是一种基于接口的动态扩展机制,Java SPI相当于Java里面提供了一套接口,第三方可以根据这个接口来完成工具的扩展;
简单来说,就是我们定义一个标准接口,第三方的库可以来实现这个接口;程序在运行的时候会根据配置信息动态加载第三方实现的类,从而完成功能的动态扩展。
1.14.1 实现Java的SPI所需格式;
1.需要定义一个接口,作为扩展的标准;
2.在classpath目录创建META-INF/service目录;
3.在创建的目录中,以接口的全限定名命名配置文件,文件内容就是这个接口的实现类;
4.在应用程序中,使用ServiceLoad就可以根据接口名称找到classpath所有的扩展实现,然后根据实际应用来具体选择实现类来完成功能的调用;
1.14.2 SPI的不足之处;
不能根据需求加载需要的扩展实现,每次都会加载接口的所有实现类并进行实例化,这样会造成性能的浪费;
1.15 finally语句一定会执行吗;
finally语句和try/catch语句块组合使用,通常情况下,不管有没有出现异常,finally里面的语句块都会执行。
1.15.1 finally在什么情况下不会执行;
1.在程序没有进入try语句时因为异常导致程序终止,出现这个问题的原因是在编写代码的时候捕获异常的范围不够;
2.在try/catch语句块中,执行了System.exit(0)的语句,导致JVM异常退出;
1.16 什么是内存溢出,什么是内存泄漏;
内存溢出是当内存不足以创建这个对象的时候,叫做内存溢出;
当我们创建对象,并使用完之后,这两个对象并没有被释放一直被占用,随着时间的积累,对象不能得到回收而发生内存溢出的情况叫做内存泄漏;
内存泄露最终会导致内存溢出;
1.17 J.U.C和锁;
1.17.1 什么是AQS;
AQS是多线程同步器。它是J.U.C包中多个组件的底层实现;
AQS提供了两种机制,分别是排他锁和共享锁;
排他锁是指在多线程竞争同一个共享资源时,同一时刻只允许一个线程访问该共享资源;
共享锁也称为读锁,是指在同一时刻允许多个线程同时获得锁资源;