JVM 進程隔離導致數據共享依賴網絡/IPC(Socket、RMI、HTTP),延遲高、序列化開銷大。共享內存(Memory-Mapped File)提供進程間零拷貝、微秒級延遲的數據交換通道,適用于:
// 創建/打開映射文件
RandomAccessFile raf = new RandomAccessFile("shared.dat", "rw");
FileChannel channel = raf.getChannel();
MappedByteBuffer buffer = channel.map(FileChannel.MapMode.READ_WRITE, 0, 1024 * 1024); // 1MB
// 寫入數據(結構化建議使用 ByteBuffer putInt/putLong/putDouble)
buffer.putInt(0, 42); // offset 0 寫入 int
buffer.putLong(4, System.currentTimeMillis()); // offset 4 寫入 timestamp
buffer.force(); // 強制刷新到磁盤(可選,性能敏感場景可異步)
// 讀取數據
int value = buffer.getInt(0);
long ts = buffer.getLong(4);
多進程寫入需互斥,FileChannel.lock()/tryLock() 提供進程級獨占/共享鎖:
// 寫入前嘗試獲取獨占鎖(非阻塞)
FileLock lock = channel.tryLock();
if (lock != null) {
try {
// 關鍵區:更新數據 + 版本號/校驗和
buffer.putInt(VERSION_OFFSET, newVersion);
// ...
buffer.force();
} finally {
lock.release();
}
} else {
// 未獲取鎖,可選擇重試、降級讀取舊數據、或拋出異常
}
進程異常退出時,JVM 釋放文件鎖,避免死鎖。
// 文件頭部固定布局(偏移量常量化)
HEADER_MAGIC = 0; // 4 bytes: 0xCAFEBABE 識別有效性
HEADER_VERSION = 4; // 4 bytes: 數據結構版本
HEADER_LOCK_FLAG = 8; // 1 byte: 0=空閒 1=寫入中(軟協議,配合文件鎖)
HEADER_CHECKSUM = 9; // 8 bytes: CRC64/Adler32 校驗數據完整性
HEADER_TIMESTAMP = 17; // 8 bytes: 最後更新時間
DATA_START = 25; // 實際業務數據起始偏移
讀取時先校驗 Magic、Checksum、Version,失效則視為損壞重建。
raf.setLength(size)),動態擴容需重新映射,極易出錯MappedByteBuffer 無公共 close(),需反射調用 Cleaner.clean() 或依賴 GC(可能延遲),長期運行建議封裝生命周期管理器