1. 子线程中遇到错误怎么排查
题目理解:咨询的是怎么捕获子线程中的异常。
- try catch
- 设置线程的异常回调接口
thread.setUncaughtExceptionHandler
, 当线程运行过程中出现异常时,JVM 会调用 Thread 类的 dispatchUncaughtException 方法,该方法会调用getUncaughtExceptionHandler().uncaughtException(this,e)
来处理异常。
总结: 如果线程运行中产生了异常,首先会生成一个异常对象。我们平时 throw 抛出异常,就是把异常交给 jvm 处理。jvm 首先会去找有没有能够处理该异常的处理者(首先找到当前抛出异常的调用者,如果当前调用者无法处理,则会沿着方法调用栈一路找下去),能够处理的调用者实际就是看方法的 catch 关键字,jvm 会把该异常对象封装到 catch 入参,允许开发者手动处理异常。若找不到能够处理的处理者(实际就是没有手动 catch 异常,比如未受检异常),就会交该线程处理;JVM 会调用 Thread 类的 dispatchUncaughtException()
方法,该方法调用了 getUncaughtExceptionHandler()
,uncaughtExceptoin(this,e)
来处理了异常,如果当前线程设置了自己的 UncaughtExceptionHandler, 则使用该 handler, 调用自己的 uncaughtException
方法,如果没有,则使用当前线程所在的线程组的 Handler 的 uncaughtExceptoin()
方法,如果线程中中也没有设置,则直接把异常定向到 System.err 中,打印异常信息(控制台红色字体输出的异常就是被定向到 System.err 的异常)
2. 项目难点
有待整理
3. docker 和虚拟机区别
容器虚拟化的是操作系统而不是硬件,容器之间是共享同一套操作系统资源的。虚拟机技术是虚拟出一套硬件后,在其上运行一个完整操作系统。因此容器的隔离级别会稍低一些。
特性 | 容器 | 虚拟机 |
---|---|---|
启动 | 秒级 | 分钟级 |
硬盘使用 | 一般为 MB | 一般为 GB |
性能 | 接近原生 | 弱于 |
系统支持量 | 单机支持上千个容器 | 一般几十个 |
-
容器是一个应用层抽象,用于将代码和依赖资源打包在一起。 多个容器可以在同一台机器上运行,共享操作系统内核,但各自作为独立的进程在用户空间中运行 。与虚拟机相比, 容器占用的空间较少(容器镜像大小通常只有几十兆),瞬间就能完成启动 。
-
虚拟机 (VM) 是一个物理硬件层抽象,用于将一台服务器变成多台服务器。 管理程序允许多个 VM 在一台机器上运行。每个 VM 都包含一整套操作系统、一个或多个应用、必要的二进制文件和库资源,因此 占用大量空间 。而且 VM 启动也十分缓慢 。
-
虚拟机更擅长于彻底隔离整个运行环境, Docker 通常用于隔离不同的应用。
4. 容器为什么小?容器缺少所需资源怎么办?
docker 是分层的,
Docker 镜像是一个特殊的文件系统,除了提供容器运行时所需的程序、库、资源、配置等文件外,还包含了一些为运行时准备的一些配置参数(如匿名卷、环境变量、用户等)。 镜像不包含任何动态数据,其内容在构建之后也不会被改变。
镜像构建时,会一层层构建,前一层是后一层的基础。每一层构建完就不会再发生改变,后一层上的任何改变只发生在自己这一层。 比如,删除前一层文件的操作,实际不是真的删除前一层的文件,而是仅在当前层标记为该文件已删除。在最终容器运行的时候,虽然不会看到这个文件,但是实际上该文件会一直跟随镜像。
分层存储的特征还使得镜像的复用、定制变的更为容易。甚至可以用之前构建好的镜像作为基础层,然后进一步添加新的层,以定制自己所需的内容,构建新的镜像。
5. find 命令根据文件内容查文件
find / -name "*.log" | xargs grep "ERROR"
xargs 可以将管道或标准输入(stdin)数据转换成命令行参数,也能够从文件的输出中读取数据。
6. vim 跳转到某行
:n
跳转到 n 行。
gg
第一行
G
末行
7. 快速排序
public void quicksort(int[] nums, int l, int r) {
if (l < r) {
int pos = partition(nums, l, r);
quicksort(nums, l, pos - 1);
quicksort(nums, pos + 1, r);
}
}
private int partition(int[] nums, int l, int r) {
int x = nums[l];
int k = l - 1; // k 一直指向 <=x 的最后一个下标
for (int i = l; i <= r; i++) {
if (nums[i] <= x) {
swap(nums, ++k, i);
}
}
swap(nums, k, l);
return k;
}