Java面试总结(五)
sleep() 方法和 wait() 方法对比
相同点
- 两者都可以暂停线程的执行;
- 两者都可以响应中断。
不同点
-
sleep()方法不会释放锁,wait()方法会释放锁;
-
sleep()方法主要用于暂停线程的执行,wait()方法主要用于线程之间的交互/通信;
-
sleep() 方法执行完成后,线程会自动苏醒;wait() 方法被调用后,线程不会自动苏醒,需要其他线程调用同一个对象上的 notify()或者 notifyAll() 方法。或者也可以使用 wait(long timeout) 超时后线程会自动苏醒;
-
sleep()方法是Thread类的静态方法,wait()方法是Object类的本地方法;
-
wait()、notify()方法必须写在同步方法/同步代码块中,是为了防止死锁和永久等待,使线程更安全,而sleep()方法没有这个限制。
如果想要详细了解这个问题,可以参考我的另一篇文章——Java并发常见面试题(二)。
synchronized 和 volatile 的区别
- volatile 是线程同步的轻量级实现,性能要比 synchronized 关键字要好。但是 volitale 只能用于修饰变量,而 synchronized 关键字可以用于修饰代码块和方法;
- volatile 关键字只能保证数据的可见性,不能保证数据的原子性,而 synchronized 关键字两者都能保证;
- volatile 关键字主要用于解决变量在多个线程之间的可见性,而 synchronized 关键字主要用于解决多个线程之间访问资源的同步性。
如果想要详细了解这个问题,可以参考我的另一篇文章——Java并发常见面试题(三)。
OSI 的七层网络模型,他们各自的作用
自上到下依次是:
- 应用层:直接向计算机用户提供服务,完成用户希望在网络上完成的各种工作;
- 表示层:数据处理(编解码、加密解密、压缩解压缩);
- 会话层:管理(建立、维护、重连)应用程序之间的会话;
- 传输层:为两台主机进程之间通信提供数据传输服务;
- 网络层:路由和寻址(决定数据在网络中的游走路径);
- 数据链路层:通过各种控制协议,将有差错的物理信道变为无差错的、能可靠传输数据帧的数据链路;
- 物理层:利用传输介质为数据链路层提供物理连接,实现比特流的透明传输。
如果想要详细了解这个问题,可以参考这篇文章——OSI七层模型详解。
TCP 与 UDP 的区别
-
是否面向连接 :UDP 在传送数据之前不需要先建立连接。而 TCP 提供面向连接的服务,在传送数据之前必须先建立连接,数据传送结束后要释放连接;
-
是否是可靠传输:远地主机在收到 UDP 报文后,不需要给出任何确认,并且不保证数据不丢失,不保证是否顺序到达。TCP 提供可靠的传输服务,TCP 在传递数据之前,会有三次握手来建立连接,而且在数据传递时,有确认、窗口、重传、拥塞控制机制。通过 TCP 连接传输的数据,无差错、不丢失、不重复、并且按序到达;
-
是否有状态 :这个和上面的“是否可靠传输”相对应。TCP 传输是有状态的,这个有状态说的是 TCP 会去记录自己发送消息的状态比如消息是否发送了、是否被接收了等等。为此 ,TCP 需要维持复杂的连接状态表。而 UDP 是无状态服务,简单来说就是不管发出去之后的事情了;
-
传输效率 :由于使用 TCP 进行传输的时候多了连接、确认、重传等机制,所以 TCP 的传输效率要比 UDP 低很多;
-
传输形式 : TCP 是面向字节流的,UDP 是面向报文的;
-
首部开销 :TCP 首部开销(20 ~ 60 字节)比 UDP 首部开销(8 字节)要大;
-
是否提供广播或多播服务 :TCP 只支持点对点通信,UDP 支持一对一、一对多、多对一、多对多。
Autowired 和 @Resource 的区别是什么?
-
@Autowired 是 Spring 提供的注解,@Resource 是 JDK 提供的注解。
-
Autowired 默认的注入方式为byType(根据类型进行匹配),@Resource默认注入方式为 byName(根据名称进行匹配)。
-
当一个接口存在多个实现类的情况下,@Autowired 和@Resource都需要通过名称才能正确匹配到对应的 Bean。Autowired 可以通过 @Qualifier 注解来显式指定名称,@Resource可以通过 name 属性来显式指定名称。
Bean 的生命周期
如果想要详细了解这个问题,可以参考这篇文章——Spring Bean的生命周期。
hashmap、hashtable和concurrenthashmap的区别
HashMap 和 Hashtable 的区别
-
线程是否安全: HashMap 是非线程安全的,Hashtable 是线程安全的,因为 Hashtable 内部的方法基本都经过synchronized 修饰。(如果你要保证线程安全的话就使用 ConcurrentHashMap 吧!);
-
效率: 因为线程安全的问题,HashMap 要比 Hashtable 效率高一点。另外,Hashtable 基本被淘汰,不要在代码中使用它;
-
对 Null key 和 Null value 的支持: HashMap 可以存储 null 的 key 和 value,但 null 作为键只能有一个,null 作为值可以有多个;Hashtable 不允许有 null 键和 null 值,否则会抛出 NullPointerException。
-
初始容量大小和每次扩充容量大小的不同 : ① 创建时如果不指定容量初始值,Hashtable 默认的初始大小为 11,之后每次扩充,容量变为原来的 2n+1。HashMap 默认的初始化大小为 16。之后每次扩充,容量变为原来的 2 倍。② 创建时如果给定了容量初始值,那么 Hashtable 会直接使用你给定的大小,而 HashMap 会将其扩充为 2 的幂次方大小(HashMap 中的tableSizeFor()方法保证,下面给出了源代码)。也就是说 HashMap 总是使用 2 的幂作为哈希表的大小,上面已经介绍过为什么是 2 的幂次方。
-
底层数据结构: JDK1.8 以后的 HashMap 在解决哈希冲突时有了较大的变化,当链表长度大于阈值(默认为 8)时,将链表转化为红黑树(将链表转换成红黑树前会判断,如果当前数组的长度小于 64,那么会选择先进行数组扩容,而不是转换为红黑树),以减少搜索时间(后文中我会结合源码对这一过程进行分析)。Hashtable 没有这样的机制。
如果想要详细了解这个问题,可以参考我的另一篇文章——Java集合常见面试题(四)
如果想要详细了解这个问题,可以参考我的另一篇文章——Java集合常见面试题(五)
binlog 和 redolog 区别
- binlog 主要用于数据库还原,属于数据库级别的数据恢复(主从复制),redolog 主要用于保证事务的持久性(事务中修改的数据写入了Buffer Pool,但还没有提交,MySQL突然宕机,恢复之后可以通过 redolog 中记录的内容进行恢复),属于事务级的数据恢复;
- redolog 属于 InnoDB 数据引擎特有,binlog 是所有数据引擎共有的,因为 binlog 是 MySQL 的 Server 层实现的;
- binlog 属于逻辑日志,主要记录数据库执行的所有 DDL、DML 语句,redolog 属于物理日志,主要记录数据库某个页的修改;
- binlog 使用追加写的方式写入日志,大小没有限制,redolog 使用循环写的方式写入日志,大小固定,当写到结尾,会回到开头循环写入。
总结:用途(数据库还原 保证事务持久性),(是否为所有引擎共有),(逻辑日志/物理日志),(写入方式)
逻辑日志和物理日志
-
逻辑日志:可以简单理解为记录的就是sql语句;
-
物理日志:因为mysql数据最终是保存在数据页中的,物理日志记录的就是数据页变更。
redo日志保证事务持久性
- 先将原始数据从磁盘读入内存(缓冲池 Buffer pool),事务发生时,会修改内存中的拷贝,此时还未写入磁盘
- 生成redo日志,写入redo log buffer
- 当事务commit之后,以一定的频率 (innodb_flush_log_at_trx_commit也就是刷盘策略)写入redo log file(在磁盘中)
- innodb_flush_log_at_trx_commit
1. 设置 0 不刷盘,操作系统默认每1秒进行同步
2. 事务提交就刷盘(其实就是写入PageCache 立即刷盘 写入redo log file )
3. 事务提交将redo log buffer写入PageCache 每秒刷新一次到磁盘 - redo log file里有个checkpoint(之前都写入磁盘),write pos(写入位置)保证事物的持久性
Spring的优点
Spring是java企业版(Java Enterprise Edition,JEE,也称J2EE)的轻量型代替品,无需开发重量级的Enterprise JavaBean (EJB),Spring为企业级java开发提供了一种相对简单的方法,通过依赖注入和面向切面编程,用简单的java对象(Plain Old java Object,POJO)实现了EJB的功能。
Spring的缺点
虽然Spring的组件代码是轻量级的,但它的配置却是重量级的。
一开始,spring用XML配置,而且是很多XML配置。
Sring2.5引入了基于 注解的组件扫描,这消除了大量针对应用程序自身组件的显示XML配置。
Spring3.0引入了基于 java的配置 ,这是一种类型安全的可重构配置方式,可以代替XML。
此外,项目的依赖管理也是一件耗时耗力的事情。
在环境搭建时,需要分析要导入哪些库的坐标,而且还需要分析导入与之有依赖关系的其他库的坐标,一旦选错依赖的版本,随之而来的不兼容问题就会严重阻碍项目的开发进度。
总结:需要手动编写大量配置文件(xml),需要自己进行项目依赖管理。
SpringBoot的优点
-
Spring Boot 可以快速创建独立的Spring应用程序。
-
Spring Boot 内嵌了如Tomcat,Jetty和Undertow这样的容器,也就是说可以直接运行,不用再做部署工作了。
-
Spring Boot 无需再像Spring一样使用一堆繁琐的xml文件配置。
-
Spring Boot 可以自动配置(核心)Spring。SpringBoot将原有的XML配置改为Java配置,将bean注入改为使用注解注入的方式(@Autowire、@Resource),并将多个xml、properties配置浓缩在一个appliaction.yml配置文件中。
-
Spring Boot 提供了一些现有的功能,如量度工具,表单数据验证以及一些外部配置这样的一些第三方功能。
-
Spring Boot 可以快速整合常用依赖(开发库,例如spring-webmvc、jackson-json、validation-api和tomcat等),提供的POM可以简化Maven的配置。当我们引入核心依赖时,SpringBoot会自引入其他依赖。
总结一下:可以快速创建独立的Spring应用程序,简化配置无需配置大量xml文件,内嵌了Tomcat、Jetty等Servlet容器可以轻松运行 SpringBoot Web项目,可以快速整合一些常用的依赖。