首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 更多程式語言 >> 程式設計疑難解答

多線程環境下多 Task 並發寫入同一 XML 文件的衝突解決方案

     編輯:程式設計疑難解答

問題本質:共享資源競態條件

多個股票監控 Task 同時調用「讀取 XML → 修改內存 DOM → 寫回文件」流程,屬於典型的非原子操作。若無同步控制,會發生:

  • **寫入覆蓋**:Task A 寫入時 Task B 也在寫,導致文件損壞或數據丟失。
  • **臟讀**:Task A 讀取時 Task B 正寫入一半,解析異常。

解決方案對比

方案一:Java 鎖同步(單進程內有效)

// 定義全局鎖對象
private static final Object xmlLock = new Object();

// 每個 Task 寫入時
synchronized (xmlLock) {
    // 1. 讀取/解析 XML
    // 2. 修改 DOM
    // 3. 寫回文件
}

✅ 簡單直接 | ❌ 僅限單 JVM 進程,分布式無效

方案二:文件鎖(跨進程可用)

FileChannel channel = new RandomAccessFile("trade.xml", "rw").getChannel();
FileLock lock = channel.lock(); // 阻塞直到獲取鎖
try {
    // 安全寫入 XML
} finally {
    lock.release();
    channel.close();
}

✅ 跨進程有效 | ❌ 性能一般,網絡文件系統 (NFS) 支持不穩定

方案三:生產者-消費者模式(推薦架構)

將「寫入請求」解耦為異步任務:

  1. 各 Task 只負責生成交易事件對象,放入 BlockingQueue<TradeEvent>。
  2. 啟動單獨寫入線程 消費隊列,順序寫入 XML。
// 生產者
queue.put(new TradeEvent(stockName, action, price, time));

// 消費者 (單線程循環)
while (running) {
    TradeEvent event = queue.take();
    appendToXml(event); // 串行寫入,無衝突
}

✅ 高吞吐、無鎖競爭、天然順序一致 | ❌ 需額外線程管理

方案四:換用數據庫(SQLite / H2 / Redis)

XML 非為高併發寫入設計。改用嵌入式數據庫:

  • 支持 ACID 事務、行級鎖、索引查詢。
  • 多線程寫入無需應用層加鎖。

最佳實踐建議

場景推薦方案
單進程、低併發、數據量小synchronized / ReentrantReadWriteLock
單進程、高併發、需高性能生產者-消費者隊列 + 單寫入線程
多進程/分布式數據庫 (SQLite/PostgreSQL) 或 分布式鎖

總結

XML 文件非線程安全存儲介質。核心原則:將「寫入」操作串行化。根據系統規模選擇進程內鎖、文件鎖、隊列串行化或遷移至數據庫。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved