Java 后台开发面试题分享七

2020-11-04 15:22:43 浏览数 (1)

数据库中 CHAR 和 VARCHAR 的区别?

1) Char 固定长度

2) Varchar 可变长度

3) Char 类型,如果存入数据的实际长度比指定长度要小,会补空格至指定长度;如果存入的数据的实际长度大于指定长度,低版本会被截取,高版本会报错

4 ) Varchar 类型,如果存入的数据的实际长度比指定的长度小,会缩短到实际长度;如果存入数据的实际长度大于指定长度,低版本会被截取 高版本会报错

5) Varchar 比 Char 节省存储空间

6) Char 效率会更高 Varchar 效率偏低

7) Char 和 Varchar 在指定时必须要指定后面的数字

TCP 建立连接为什么是 3 次握手,为什么不是 2 次握手或者 4 次握手呢?

不是 2 次握手的原因:防止客户端失效的连接请求报文段突然又传到服务器。

代码语言:javascript复制
例如,以下情况如果使用 2 次握手
1)如果客户端向服务器发送第 1 次连接请求在网络节点上滞留了,没有收到服务器的确认,又重新发送了一次连接请求
2)服务器收到客户端的第 2 次请求发送确认,则连接建立完成
3)服务器客户端进行数据传输,传输完成断开连接。
4)此时,在网络上滞留的客户端第 1 次连接请求到达服务器,服务器发送确认连接但是客户端实际上并没有发送请求,因此不会理睬服务器发送的请求;但是服务器认为连接已完成,并等待客户端进行数据传输;这样就造成了资源的浪费。

如果采用 3 次握手:滞留在网络上的客户端第 1 次请求到达服务器之后,服务器发送确认,但实际上服务器并没有发送请求,因此不会理睬服务器的确认,故不会发送确认,服务器等不到客户端的确认则连接建立失败。这样就防止了客户端失效的连接请求报文段突然又传到服务器。

不是 4 次握手的原因:

代码语言:javascript复制
模拟一下 4 次握手的过程
1)客户端发送请求报文,发送自己的序列号
2)服务器发送确认报文
3)服务器发送自己的序列号
4)客户端发送确认报文

上述过程中 2、3 步可以合为一步进行发送,因此没有必要进行 4 次握手

数据库中 delete、drop、truncate 区别

  • Truncate 和 Delete 只删除数据,不删除表结构,drop 删除表结构,并且释放所占的空间。
  • 删除数据的速度:drop > truncate > delete
  • Delete 属于 DML 语言,需要事务管理,commit 之后才能生效;drop 和 truncate 属于 DDL 语言,操作立刻生效,不可回滚
  • 使用场合:
代码语言:javascript复制
- 当不再需要该表时,用 drop
- 当仍要保留该表,但要删除所有记录时,用 truncate
- 当要删除部分记录时(带有 where 子句), 用 delete

注意: 对于有主外键关系的表,如果需要删除所有数据,不能使用 truncate,而应该使用不带 where 子句的 delete 语句,由于 truncate 不记录在日志中,不能够激活触发器

Java 传参 - 基本数据类型和引用数据类型作为参数的区别(值传递)

代码语言:javascript复制
1. 所谓值传递就是当参数是基本类型时,传递参数的值,比如传递 i = 10,真实传参时,把 10 赋值给了形参。
2. 当参数是对象时,传递的是对象的值,也就是对象的首地址,就是把对象的地址赋值给形参。
3. 基本数据类型的变量中直接存放数据值本身,所以改的时候改的是数据值本身。
4. 引用类型不同的地方在于真正的数据并没有在栈区的变量中保存,而是在堆区里面保存着;所以虽然也拷贝了一份,是副本,但是二者指向的是同一块堆区。

当使用基本数据类型作为方法的形参时,在方法体中对形参的修改不会影响到实参的数值;

当使用引用数据类型作为方法的形参时,若在方法体中修改形参指向的数据内容,则会对实参变量的数值产生影响,因为形参变量和实参变量共享同一块堆区;

当使用引用数据类型作为方法的形参时,若在方法体中修改形参变量的指向,此时不会对实参变量的数值产生影响,形参变量和实参变量分别指向不同的堆区。

Java 四种引用类型是?

强引用:在 Java 中最常见的就是强引用,把一个对象赋给一个引用变量,这个引用变量就是一个强引用;当一个对象被强引用变量引用时,它处于可达状态,它是不可能被垃圾回收机制回收的,即使该对象以后永远都不会被用到, JVM 也不会回收;因此强引用是造成 Java 内存泄漏的主要原因之一。

软引用:软引用需要用 SoftReference 类来实现,对于只有软引用的对象来说,当系统内存足够时它不会被回收,当系统内存空间不足时它会被回收;软引用通常用在对内存敏感的程序中。

弱引用:弱引用需要用 WeakReference 类来实现,它比软引用的生存期更短;对于只有弱引用的对象来说,只要垃圾回收机制一运行,不管 JVM 的内存空间是否足够,总会回收该对象占用的内存。

虚引用:虚引用需要 PhantomReference 类来实现;与软引用、弱引用不同,它不能单独使用,必须和引用队列联合使用;虚引用的主要作用是跟踪对象被垃圾回收的状态。

另外:引用队列可以与软引用、弱引用以及虚引用一起配合使用;当垃圾回收器准备回收一个对象时,如果发现它还有引用,那么就会在回收对象之前,把这个引用加入到与之关联的引用队列中去;程序可以通过判断引用队列中是否已经加入了引用,来判断被引用的对象是否将要被垃圾回收,这样就可以在对象被回收之前采取一些必要的措施。

事务具有的 4 个基本特征

1、Atomic - 原子性:事务中包含的操作被看做一个逻辑单元,这个逻辑单元中的操作要么全部成功,要么全部失败。

2、Consistency - 一致性:事务完成时,数据必须处于一致状态,数据的完整性约束没有被破坏,事务在执行过程中发生错误,会被回滚(Rollback)到事务开始前的状态,就像这个事务从来没有执行过一样。

3、Isolation - 隔离性:事务允许多个用户对同一个数据进行并发访问,而不破坏数据的正确性和完整性;同时,并行事务的修改必须与其他并行事务的修改相互独立。

4、Durability - 持久性:事务结束后,事务处理的结果必须能够得到固化。

高并发、任务执行时间短的业务怎样使用线程池?低并发、任务执行时间长的业务怎样使用线程池?高并发、业务执行时间长的业务怎样使用线程池?

1)高并发、任务执行时间短的业务:线程池线程数可以设置为 CPU 核数 1,减少线程上下文的切换。

2)低并发、任务执行时间长的业务:

代码语言:javascript复制
- 假如是业务集中在 IO 操作上,也就是 IO 密集型的任务:因为 IO 操作并不占用 CPU,所以不要让所有的 CPU 闲下来,可以加大线程池中的线程数目,让 CPU 处理更多的业务
- 假如是业务集中在计算操作上,也就是计算密集型任务:线程池中的线程数设置得少一些,减少线程上下文的切换,和“高并发、任务执行时间短的业务”设置一样。

3)高并发、业务执行时间长的业务:解决这种类型任务的关键不在于线程池而在于整体架构的设计;第一步看看这些业务里面某些数据是否能做缓存;第二步增加服务器;至于线程池的设置,参考“低并发、任务执行时间长的业务”;最后,业务执行时间长的问题,也可能需要分析一下,看看能不能使用中间件对任务进行拆分和解耦。

线程类的构造方法、静态块是被哪个线程调用的?

线程类的构造方法、静态块是被 new 这个线程类所在的线程所调用的,而 run 方法里面的代码才是被线程自身所调用的。

假设 Thread 2 中 new 了 Thread 1,main 函数中 new 了 Thread 2,那么:

代码语言:javascript复制
(1)Thread 2 的构造方法、静态块是 main 线程调用的,Thread 2 的 run() 方法是 Thread 2 自己调用的
(2)Thread 1 的构造方法、静态块是 Thread 2 调用的,Thread 1 的 run() 方法是 Thread 1 自己调用的

Thread.sleep(0) 的作用是什么

Thread.Sleep(0) 并非是真的要线程挂起 0 毫秒,意义在于这次调用 Thread.Sleep(0) 的当前线程确实的被冻结了一下,让其他线程有机会优先执行;

Thread.Sleep(0) 是让线程暂时放弃 cpu,也就是释放一些未用的时间片给其他线程或进程使用,就相当于一个让位动作。

什么是线程上下文的切换?

CPU 通过分配时间片来执行任务,当一个任务的时间片用完,就会切换到另一个任务;在切换之前会保存上一个任务的状态,当下次再切换到该任务,就会加载这个状态;任务从保存到再加载的过程就是一次上下文切换。

0 人点赞