小菜鸟

java菜鸟号正在起航

Java AIO 详解:异步非阻塞 IO 的实现与实践

Java AIO(Asynchronous IO,异步 IO)是 JDK 1.7 引入的 IO 模型,基于 “异步非阻塞” 思想,通过 Proactor 模式实现,将 IO 操作的全过程(数据准备 + 内核到用户缓冲区的复制)交由操作系统完成,最终通过回调函数通知应用程序结果。相比 NIO 的 “同步非阻塞”,AIO 进一步解放了应用程序的 CPU 资源,适用于高并发、IO 密集型场景。

AIO 的核心概念与优势

核心思想:Proactor 模式

AIO 采用 Proactor 模式(与 NIO 的 Reactor 模式相对),核心特点是:

  • 应用程序:发起 IO 操作后立即返回,无需阻塞或轮询。
  • 操作系统:负责完成整个 IO 流程(包括数据从设备到内核缓冲区、再到用户缓冲区的复制)。
  • 通知机制:操作系统完成 IO 后,通过回调函数Future 对象通知应用程序处理结果。

与 NIO 的核心区别

维度 NIO(同步非阻塞) AIO(异步非阻塞)
操作方式 应用程序需主动轮询或处理事件队列 操作系统完成全流程后通知应用程序
核心模式 Reactor(反应器模式) Proactor(前摄器模式)
数据复制 应用程序主动调用 read/write 完成 操作系统自动完成,应用程序直接使用结果
性能开销 需遍历事件队列,存在一定 CPU 消耗 无轮询开销,CPU 利用率更高
适用场景 高并发网络通信(如服务器) IO 密集型场景(如大文件传输、异步通信)

AIO 的核心类与接口

AIO 的核心类位于 java.nio.channels 包中,主要包括:

类 / 接口 功能描述 典型方法
AsynchronousChannel 异步通道的根接口,定义异步关闭方法 close()
AsynchronousServerSocketChannel 异步服务器套接字通道,用于监听客户端连接 open()bind()accept()
AsynchronousSocketChannel 异步客户端套接字通道,用于数据传输 open()connect()read()write()
CompletionHandler 异步操作的回调接口,处理成功 / 失败结果 completed(V result, A attachment)failed(Throwable exc, A attachment)

AIO 编程实践

AIO 操作通常通过两种方式获取结果:回调函数(CompletionHandlerFuture 对象。以下以网络通信为例,展示 AIO 的核心用法。

阅读全文 »

传输层网络协议:TCP 与 UDP 的深度解析

传输层是网络通信的核心枢纽,其中TCP(传输控制协议)UDP(用户数据报协议) 是两种最核心的协议。TCP 以可靠性著称,适用于需要精确数据传输的场景;UDP 以高效性为亮点,适合实时性要求高的应用。以下从协议细节、连接机制到核心特性进行全面解析。

TCP:面向连接的可靠传输协议

TCP(Transmission Control Protocol)是一种基于连接、可靠、有序的传输协议,通过复杂的控制机制确保数据准确无误地从发送方交付到接收方。

TCP 的核心标识:序号、确认号与标志位

TCP 报文通过序号、确认号标志位实现可靠传输,这些字段是理解 TCP 工作机制的关键:

  • 序号(seq)
    TCP 将传输的数据流视为字节序列,每个字节都有唯一序号。seq表示当前报文段第一个字节的序号(如发送 100 字节数据,seq=1000,则该报文包含 1000-1099 字节)。
  • 确认号(ack)
    接收方用于告知发送方 “已成功接收数据的截止位置”,值为期望接收的下一个字节序号。例如,若接收方已收到 1000-1099 字节,则 ack=1100,表示 “请发送从 1100 开始的数据”。
  • 标志位
    控制 TCP 连接与数据传输的关键标识,核心包括:
    • ACK:确认位。ACK=1时,确认号(ack)有效;ACK=0时,ack 无效(仅在第一次握手时使用)。
    • SYN:同步位。用于建立连接时同步序号,SYN=1表示 “请求建立连接”,此时报文不携带数据。
    • FIN:终止位。用于释放连接,FIN=1表示 “发送方已完成数据传输,请求关闭连接”。

TCP 连接建立:三次握手

TCP 是面向连接的协议,通信前必须通过 “三次握手” 建立连接,确保双方收发能力正常。

阅读全文 »

MySQL 全平台安装指南(Mac/Linux/Windows)

MySQL 是目前最流行的关系型数据库之一,其安装过程因操作系统而异。本文详细介绍 Mac、Linux、Windows 三大平台的安装步骤、配置方法及常用命令,帮助你快速搭建 MySQL 环境。

Mac 平台安装(Homebrew 方式)

Mac 推荐使用 Homebrew 安装,步骤简单且便于管理。

安装 MySQL

# 安装最新版本
brew install mysql

# 如需指定版本(如 8.0)
brew install mysql@8.0

启动 MySQL 服务

# 启动服务(后台运行)
mysql.server start

# 停止服务
mysql.server stop

# 重启服务
mysql.server restart

安全配置(首次安装必做)

阅读全文 »

Spark 全面解析:MapReduce 慢在哪,Spark 怎么改的,它到底怎么跑

MapReduce 能处理大数据,但它有两个硬伤:

  • 太慢:每轮 Map 结果都要写磁盘,Reduce 再读磁盘,一个复杂任务来回读写好几次
  • 太笨:每步都得排序,就算不需要排序也排;每个任务起一个 JVM,启动就得几秒

Spark 做了一件事:把中间结果放内存,用线程替代进程。

  • 内存计算 → 磁盘 IO 大幅减少
  • 线程复用 → 任务启动从秒级降到毫秒级
  • DAG 调度 → 多阶段任务不用重复读写

Spark 比 MapReduce 快在哪?

对比维度 MapReduce Spark
中间结果存储 磁盘(HDFS) 内存(优先),磁盘兜底
任务启动开销 每个任务起 JVM(秒级) 线程池复用(毫秒级)
排序策略 强制排序(不管需不需要) 按需排序(Hash 聚合不排)
多阶段任务 每阶段写一次磁盘 DAG 串联,内存流转
迭代计算 每次都重读 HDFS 内存缓存,迭代快速

典型场景: 机器学习训练要迭代 100 次,MapReduce 每次读磁盘,Spark 第一次读进去后面全在内存——速度差 10-100 倍。

核心概念:RDD 和 DStream

RDD(弹性分布式数据集):Spark 里一切数据的抽象。

  • 分布式:数据分片存在多台机器上
  • 不可变:创建后不能改,要改就生成新的 RDD
  • 惰性计算mapfilter 只是记下了”要做什么”,不会立刻算,等你要结果(collectcount)才真正执行
  • 容错:记录了”血缘关系”,某分区丢了可以从源头重算

DStream(离散流):Spark Streaming 里的数据流抽象。

本质是”按时间切成小块的 RDD 序列”——每 1 秒的微批,每个微批就是一个 RDD。

阅读全文 »

HDFS 安全模式:NameNode 启动时为什么要”关门”一会儿?

NameNode 重启的时候,你会发现 HDFS 有一段时间只能读不能写——创建不了文件、删除不了目录、上传数据报错。

这不是故障,是 安全模式(Safe Mode) 在起作用。

安全模式是 NameNode 启动时的”保护期”——在元数据恢复完成、数据块状态确认清楚之前,先关门谢客,不让写操作进来捣乱。

NameNode 启动时,为什么不能立刻对外服务?

NameNode 重启后要做两件事,这两件事做完之前,文件系统的状态是不完整的:

1. 恢复元数据

NameNode 的元数据存在磁盘上,分两部分:

  • fsimage:某个时刻的元数据快照
  • edits:快照之后的每次操作记录

启动时,先把 fsimage 读到内存,再把 edits 里的操作重放一遍,才能恢复到最新的元数据状态。

这个过程需要时间。如果恢复没完成就让客户端写数据,元数据会乱。

2. 确认数据块状态

DataNode 启动后会向 NameNode 汇报自己有哪些块。NameNode 需要等 DataNode 都报上来,才知道每个块有几个副本、副本都在哪。

如果不等 DataNode 汇报完就开始读写,NameNode 可能告诉客户端”块在 A 节点”,但 A 节点其实还没上线——数据读不到。

所以 NameNode 启动后先进入安全模式:元数据恢复完、块状态确认完之前,只读不写。

安全模式下能做什么、不能做什么

操作类型 安全模式下
读文件(hdfs dfs -cat / -get) 可以
查目录(hdfs dfs -ls) 可以
创建目录(hdfs dfs -mkdir) 不行
上传文件(hdfs dfs -put) 不行
删除文件(hdfs dfs -rm) 不行
修改权限(hdfs dfs -chmod) 不行
阅读全文 »
0%