某金融科技公司Java一面

1. AIO BIO NIO 有什么区别

  • 区别在于阻塞与非阻塞、同步与异步。
  • BIO是阻塞同步模型,NIO是非阻塞同步模型,而AIO是非阻塞异步模型。

BIO(Blocking I/O,阻塞I/O):

  • BIO 是传统的I/O模型,它是同步阻塞的。
  • 在BIO中,每个I/O操作都会阻塞线程,直到I/O操作完成。这意味着当一个线程执行I/O操作时,它无法执行其他任务,导致线程资源的浪费。
  • BIO适用于连接数较少且每个连接的I/O操作比较耗时的情况。

NIO(Non-blocking I/O,非阻塞I/O):

  • NIO是Java的新I/O模型,引入了Channel和Selector的概念,它是同步非阻塞的。
  • 在NIO中,一个线程可以同时处理多个I/O操作,因为它可以等待多个通道变得可用,而不需要阻塞等待每个I/O操作完成。
  • NIO适用于需要处理大量连接的高并发情况,如网络服务器。

AIO(Asynchronous I/O,异步I/O):

  • AIO是Java 7引入的I/O模型,它是异步非阻塞的。
  • 在AIO中,I/O操作是异步的,线程不需要等待I/O操作完成,而是可以继续执行其他任务。当I/O操作完成时,会通知应用程序。
  • AIO适用于需要处理大量连接且每个连接的I/O操作不是很耗时的情况,例如高性能的网络通信应用。

同步:

  • 调用者要一直等待调用结果的通知后才能进行后续的执行,
  • 现在就要,我可以等,等出结果为止

异步:

  • 被调用方先返回应答让调用者先回去,
  • 然后再计算调用结果,计算完最终结果后再通知并返回给调用方

异步调用要想获得结果一 般通过回调

同步与异步的理解:同步、 异步的讨论对象是被调用者(服务提供者),重点在于获得调用结果的消息通知方式上。

阻塞

  • 调用方一直在等待而且别的事情什么都不做,当前进/线程会被挂起,啥都不干

非阻塞

  • 调用在发出去后,调用方先去忙别的事情,不会阻塞当前进/线程,而会立即返回

阻塞与非阻塞的理解

阻塞、非阻塞的讨论对象是调用者(服务请求者),重点在于等消息时候的行为,调用者是否能干其它事

2.Java中的锁有哪些

Java 中提供了多种锁机制来实现多线程并发控制,以下是一些常见的锁类型:

1.互斥锁(Mutex Lock):

  • 互斥锁是最常见的锁类型,用于确保在同一时间只有一个线程能够访问共享资源。在 Java 中,synchronized 关键字和 ReentrantLock 类都提供了互斥锁的实现。

2.可重入锁(Reentrant Lock):

  • 可重入锁允许同一个线程在多个代码块中获取锁,而不会造成死锁。ReentrantLock 是 Java 中的可重入锁的实现。

3.读写锁(Read-Write Lock):

  • 读写锁允许多个线程同时读取共享资源,但只有一个线程能够写入资源。这对于读多写少的情况非常有用。在 Java 中,ReentrantReadWriteLock 提供了读写锁的实现。

4.独占锁(Exclusive Lock):

  • 独占锁用于限制只有一个线程可以同时访问共享资源synchronized 和 ReentrantLock 都是独占锁的实现。

5.共享锁(Shared Lock):

  • 共享锁允许多个线程同时访问共享资源。读写锁是一种常见的共享锁。

6.条件锁(Condition Lock):

  • 条件锁允许线程等待某个条件为真时才能继续执行。在 Java 中,ReentrantLock 的 Condition 接口提供了条件锁的支持。

7.自旋锁(Spin Lock):

  • 自旋锁是一种非阻塞锁,它不会让线程休眠,而是一直尝试获取锁。在 Java 中,AtomicInteger 和 AtomicReference 等类提供了自旋锁的实现。

8.信号量(Semaphore):

  • 信号量是一种控制并发访问资源的机制,它允许多个线程同时访问资源,但根据信号量的许可数量限制访问的线程数量。在 Java 中,Semaphore 类提供了信号量的实现。

9.倒计时门闩(CountDownLatch):

  • 倒计时门闩是一种同步工具,它允许一个或多个线程等待其他线程完成某个操作后再继续执行。在 Java 中,CountDownLatch 类提供了倒计时门闩的实现。

3.redis 持久化策略 对比优缺点

Redis支持两种主要的持久化策略,分别是RDB快照和AOF日志,它们各自有优点和缺点。

RDB(Redis DataBase)持久化策略:

  • RDB,Redis DataBase,是指将内存中某一时刻的数据快照全量写入到指定的 rdb 文件的 持久化技术。RDB 持久化默认是开启的。当 Redis 启动时会自动读取 RDB 快照文件,将数据 从硬盘载入到内存,以恢复 Redis 关机前的数据库状态。

优点:

  • 高性能:RDB是在一定时间间隔内对数据进行快照的方式,因此生成快照的时候不会对正常的Redis操作造成影响。
  • 数据压缩:RDB文件采用二进制格式,因此在磁盘上占用的空间通常比AOF文件更小。
  • 恢复速度快:在恢复数据时,由于RDB文件只是一个快照,因此加载速度通常比AOF日志更快。

缺点:

  • 数据丢失:由于RDB是在一定时间间隔内生成的快照,因此在两次生成快照之间的数据变化可能会丢失。
  • 不适用于追加操作:RDB不适合用于记录追加(append-only)的操作,因为它不会记录每次写操作的详细信息。

AOF(Append-Only File)持久化策略:

  • AOF,Append Only File,是指 Redis 将每一次的写操作都以日志的形式记录到一个 AOF文件中的持久化技术。当需要恢复内存数据时,将这些写操作重新执行一次,便会恢复到之 前的内存数据状态。

优点:

  • 数据完整性AOF记录了每次写操作的详细信息,因此可以保证在Redis重启时不会丢失数据。
  • 可读性:AOF日志文件是可读的,可以用于检查Redis操作历史。

缺点:

  • 性能:AOF日志需要记录每次写操作,因此相比RDB,AOF对性能有一定的影响。但可以通过将AOF文件定期重写来降低写入性能开销。
  • 文件体积:AOF日志文件通常比RDB文件占用更多的磁盘空间,尤其在文件重写的情况下。
  • 恢复速度:在Redis启动时,恢复数据可能会比RDB加载快照慢一些。

综合比较:

  • 对于需要数据完整性和不希望有数据丢失的场景,AOF更适合,尤其是金融、电商等对数据一致性要求很高的领域。

  • 对于需要高性能、可以容忍一定数据丢失的场景,RDB可能更适合,尤其是一些缓存应用。

  • 有些情况下,可以同时使用两种策略,RDB用于备份和快速恢复,AOF用于数据完整性。

4. 树、b树、b+树的区别

- 树(Tree):

  • 树是一种基本的数据结构,它包括一个根节点,每个节点可以有零个或多个子节点,子节点又可以有自己的子节点,以此类推。
  • 树的结构是多层的,通常包括根节点、内部节点和叶子节点。
  • 二叉树是树的一种特殊形式,其中每个节点最多有两个子节点。
  • 树的应用非常广泛,包括文件系统、XML解析、数据库索引等。

- B树(B-Tree):

  • B树是一种自平衡树,通常用于数据库和文件系统中的索引结构。
  • B树的特点是它的每个节点可以有多个子节点,通常用于处理大量数据的索引。
  • B树的平衡性保证了插入、删除和查找的时间复杂度都是O(log n),其中n是数据的数量。

- B+树(B+ Tree):

  • B+树也是一种自平衡树,类似于B树,但在某些方面有不同的特点。
  • B+树的所有数据都存储在叶子节点,而非叶子节点只包含索引信息。
  • B+树通常用于数据库索引,因为它的叶子节点形成一个有序链表,适合范围查询。
  • B+树的平衡性和范围查询性能使其在数据库系统中非常流行。

5. Java实现注解需要注意什么(需要哪些步骤)?

实现注解的步骤如下:

定义注解:首先定义一个注解类型,使用@interface关键字。注解类型通常包括注解的名称、元素(也就是注解的属性),以及默认值。

public @interface MyAnnotation {
    String value() default "default_value";
    int count() default 0;
}

使用注解:在需要使用注解的地方,使用**@注解名**来标记。你可以为注解的元素指定具体的值。

@MyAnnotation(value = "custom_value", count = 1)
public class MyClass {
    // ...
}

解析注解:要想在运行时获取注解信息,需要使用反射机制来解析注解。可以使用Class对象的getAnnotation方法或者通过反射获取方法、字段、类等上的注解信息。

Class<?> clazz = MyClass.class;
MyAnnotation annotation = clazz.getAnnotation(MyAnnotation.class);

处理注解:一旦获取了注解对象,可以根据注解信息来进行相应的处理。例如,可以根据注解值来调整程序的行为。

注意事项:

  • 注解元素不能有不确定的值,也就是不能使用null作为默认值。

  • 注解的生命周期(RetentionPolicy)可以是源码级别、类文件级别或运行时级别,具体取决于注解类型上的**@Retention**注解。

    • Retention:指定所修饰的 Annotation 的生命周期:SOURCE\CLASS(默认行为\RUNTIME
      在这里插入图片描述
    • 只有声明为RUNTIME生命周期的注解,才能通过反射获取。在这里插入图片描述
  • 注解可以用于类、方法、字段、参数等不同的地方,具体取决于注解类型上的@Target注解

  • 在这里插入图片描述

6. Java类加载的过程?

Java类加载是指将Java类从磁盘加载到内存中,并将其转换为字节码的过程。Java类加载分为以下三个阶段:

  • 加载(Loading):在这个阶段,类加载器从磁盘上加载类的字节码文件到内存中,并生成一个代表这个类的java.lang.Class对象。类加载器通过类的全限定名来查找类文件。
  • 连接(Linking):连接分为三个子阶段:
    • 验证(Verification):在这个阶段,类加载器验证字节码文件的格式,确保它符合Java虚拟机规范。这包括检查字节码的格式、语法和语义。
    • 准备(Preparation):在这个阶段,为类的静态变量分配内存,并初始化为默认值。这包括数值类型的默认值为0,对象引用的默认值为null。
    • 解析(Resolution):在这个阶段,解析符号引用,将它们替换为直接引用。符号引用包括类和接口的全限定名、字段和方法的名称。
  • 初始化(Initialization):在这个阶段,执行类的初始化代码,包括静态变量的赋值(准备阶段是默认值)、静态块的执行等。类初始化是在类首次主动使用时进行的,例如创建类的实例、访问静态字段、调用静态方法等。
  • 类加载过程是Java虚拟机的基础之一,它确保了类的安全性和正确性。类加载器通过双亲委派机制(Parent-Delegation Model)来管理类的加载,确保类加载的一致性和隔离性。
    • 符号引用(Symbolic Reference):在Java类的字节码中,一些符号用来表示引用其他类、方法、字段等。这些符号引用通常是以字符串形式表示的,比如类的全限定名、方法名、字段名等。符号引用是抽象的,它不包含具体的内存地址或偏移量信息。
    • 直接引用(Direct Reference):与符号引用相对,直接引用是具体的、可以直接定位到内存中的对象、方法、字段等。直接引用包括内存地址或偏移量,可以用于访问实际的数据。

7. Linux常用命令

  • 1.pwd 命令

    • 功能: 显示用户当前所在的目录
  • ls 命令

    • 功能:对于目录,该命令列出该目录下的所有子目录与文件。对于文件,将列出文件名以及其他信息
    • 格式:ls [选项][目录或文件]
    • 在这里插入图片描述
  • cd 命令

    • 功能:改变工作目录。将当前工作目录改变到指定的目录下
    • 格式:cd 目录名
    • 在这里插入图片描述
  • man 命令

    • Linux的命令有很多参数,我们不可能全记住,我们可以通过查看联机手册获取帮助。访问Linux手册页的命令是man
  • grep 命令

    • 功能:用于查找文件里符合条件的字符串
    • 格式:grep [选项] ‘查找字符串’ 文件名
    • 在这里插入图片描述
  • find 命令

    • 功能:用来在指定目录下查找文件
    • 格式:find [路径] [选项] 操作
    • 在这里插入图片描述
  • chmod 命令

    • 功能:控制用户对文件的权限的命令
    • 格式:chmod [选项] 文件名
    • 在这里插入图片描述
  • ps 命令

    • 功能:用来列出系统中当前正在运行的那些进程,类似于 windows 的任务管理器。
    • 在这里插入图片描述
  • kill 命令

    • 功能:用于删除执行中的程序或工作
    • 格式:kill [选项]/[信号] 进程号
    • 在这里插入图片描述
      信号:
      在这里插入图片描述
  • tail 命令

  • 功能:查看测试项目的日志

  • 说明:一般测试的项目里面,有个logs的目录文件,会存放日志文件,有个xxx.out的文件,可以用tail -f 动态实时查看后端日志

  • 格式:tail [选项] 文件名

  • 在这里插入图片描述

  • netstat 命令

    • 功能:查看端口
    • 格式:netstat -anp | grep 端口号
  • echo 打印 选项 -e

    • 打印常量 直接打印
    • 打印变量 变量前加$
    • 打印命令 用反引号把命令引起来
    • 终端间传递信息 echo 内容>/dev/pts/终端号
    • echo -e "要打印的东西 \c"
    • 以覆盖方式写入文件,写入语句会覆盖目标文件原有内容,保证文件保存的始终是最新内容。
    • echo "Hello World" > hello.txt
    • 以追加方式写入文件,写入语句不会覆盖目标文件原有内容,只会追加在文件末尾。追加方式适用于记录运行log,便于后期问题分析。
    • echo "Hello World" >> hello.txt
  • ping 地址 检测是否与主机连通

    • 格式:ping 地址
  • mkdir 命令

    • 功能:创建空目录
    • 格式:mkdir [选项] [路径] 文件名
    • 在这里插入图片描述
  • touch 命令

    • 功能:新建空文件
    • 格式:touch [路径] 文件名 (可以多个)
  • rm 命令

    • 功能:删除文件或目录
    • 格式:rm [选项] 文件名
      在这里插入图片描述
  • mv 命令

    • 功能:mv命令是move的缩写,可以用来移动文件或者将文件改名(move(rename)files),是Linux系统下常用的命令,经常用来备份文件或者目录
    • 格式:mv [选项] [路径] 旧文件名 [新路径][新文件名]
    • 在这里插入图片描述
  • cp 命令

    • 功能: 复制文件或目录
    • cp [选项] [路径] 旧文件名 [新路径][新文件名]
    • 在这里插入图片描述
  • cat 命令

    • 功能: 查看目标文件的内容
    • 格式:cat [选项] 文件名

8.java中IO、Socket的常用操作和方法。

I/O 操作:

文件读写:

  • 读取文件:可以使用 FileInputStream、BufferedReader 等类进行文件读取。
  • 写入文件:可以使用 FileOutputStream、BufferedWriter 等类进行文件写入。

标准输入输出:

  • 读取标准输入(键盘输入):使用 System.in 和 Scanner 或 BufferedReader。
  • 输出到标准输出(屏幕):使用 System.out 和 System.err 进行输出。

字节流和字符流:

  • 使用字节流:InputStream 和 OutputStream 类用于字节数据的读写。
  • 使用字符流:Reader 和 Writer 类用于字符数据的读写。可以使用 FileReader、FileWriter 等。

缓冲:

  • 可以使用 BufferedReader、BufferedWriter、BufferedInputStream 和 BufferedOutputStream 来提高I/O性能。

Socket 操作:

建立Socket连接:

  • 创建客户端Socket:Socket socket = new Socket(host, port);
  • 创建服务器Socket:ServerSocket serverSocket = new ServerSocket(port);

数据传输:

  • 从Socket读取数据:使用 InputStream 和 Reader。
  • 向Socket写入数据:使用 OutputStream 和 Writer。
  • 关闭Socket:使用 close() 方法关闭Socket连接。
  • 多线程通信:通常,服务器端使用多线程来处理多个客户端的连接。
  • 异常处理:捕获和处理 IOException 异常,以确保程序健壮性。
  • 网络通信协议:根据需要选择TCP或UDP协议。

服务器程序的工作过程包含以下四个基本的步骤:

调用 ServerSocket(int port) :创建一个服务器端套接字,并绑定到指定端口上。用于监听客户端的请求。

调用 **accept():**监听连接请求,如果客户端请求连接,则接受连接,返回通信套接字对象。

调用 该Socket类对象的 getOutputStream() 和 getInputStream ():获取输出流和输入流,开始网络数据的发送和接收。

关闭ServerSocket和Socket对象:客户端访问结束,关闭通信套接字。

客户端Socket的工作过程包含以下四个基本的步骤:

 创建 Socket:根据指定服务端的 IP 地址或端口号构造 Socket 类对象。若服务器端响应,则建立客户端到服务器的通信线路。若连接失败,会出现异常。

 打开连接到 Socket 的输入/出流: 使用 getInputStream()方法获得输入流,使用getOutputStream()方法获得输出流,进行数据传输

 按照一定的协议对 Socket 进行读/写操作:通过输入流读取服务器放入线路的信息(但不能读取自己放入线路的信息),通过输出流将信息写入线程。

 关闭 Socket:断开客户端到服务器的连接,释放线路

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值