You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Java线程正确实现疑问:离线缓存数据同步至数据库的难题

Hey there! Let's work through this third part of your timestamp project—synchronizing the buffer to the database while continuing to write new timestamps when the server is back online. It sounds like you've got the offline buffering and basic timestamp writing down, so let's focus on making the sync and new writes play nicely together without conflicts.

Key Fixes & Implementation Steps

1. Use a Thread-Safe Buffer First

The biggest risk here is race conditions when reading/writing the buffer from two separate threads. Ditch any plain List or non-thread-safe collection and use a built-in concurrent queue instead. This eliminates the need for manual locking (which is easy to mess up):

// Thread-safe buffer to hold timestamps when offline
private final ConcurrentLinkedQueue<Instant> timestampBuffer = new ConcurrentLinkedQueue<>();
// Thread-safe flag to track server online status
private final AtomicBoolean isServerOnline = new AtomicBoolean(false);

2. Split Logic Between Your Two Runnable Threads

Let's clarify the role of each thread to avoid overlap:

Thread 1: Timestamp Generator & Writer

This thread keeps doing its core job—generating a timestamp every second. It switches behavior based on the server status:

class TimestampWriterTask implements Runnable {
    @Override
    public void run() {
        while (!Thread.currentThread().isInterrupted()) {
            Instant currentTimestamp = Instant.now();
            
            if (isServerOnline.get()) {
                // Online: Write directly to database immediately
                try {
                    writeSingleTimestampToDb(currentTimestamp);
                } catch (SQLException e) {
                    // If write fails (server went offline mid-write), fall back to buffer
                    timestampBuffer.offer(currentTimestamp);
                    // Optional: Trigger a status check here to update isServerOnline
                }
            } else {
                // Offline: Buffer the timestamp as you already implemented
                timestampBuffer.offer(currentTimestamp);
            }

            // Enforce 1-second interval
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                // Handle graceful shutdown
                Thread.currentThread().interrupt();
                break;
            }
        }
    }
}

Thread 2: Buffer Sync Worker

This thread's sole job is to empty the buffer when the server is online. It runs in the background, checking periodically for buffer content to sync in batches (way more efficient than writing one at a time):

class BufferSyncTask implements Runnable {
    @Override
    public void run() {
        while (!Thread.currentThread().isInterrupted()) {
            if (isServerOnline.get() && !timestampBuffer.isEmpty()) {
                // Drain a batch of timestamps from the buffer (avoids repeated locks)
                List<Instant> batchToSync = new ArrayList<>();
                timestampBuffer.drainTo(batchToSync);

                if (!batchToSync.isEmpty()) {
                    try {
                        // Batch write to database to reduce overhead
                        batchWriteTimestampsToDb(batchToSync);
                    } catch (SQLException e) {
                        // If sync fails, put the batch back into the buffer
                        timestampBuffer.addAll(batchToSync);
                        // Optional: Mark server as offline again if needed
                    }
                }
            }

            // Don't check constantly—give the CPU a break (adjust interval as needed)
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
                break;
            }
        }
    }
}

3. Handle Server Status Transitions Cleanly

When your app detects the server is back online, just flip the atomic flag—both threads will automatically adjust their behavior:

// Call this when server connectivity is restored
public void markServerOnline() {
    isServerOnline.set(true);
}

// Call this when server goes offline
public void markServerOffline() {
    isServerOnline.set(false);
}

4. Critical Edge Cases to Handle

  • Failed Writes During Sync: If the server drops out mid-sync, make sure to put the unsent batch back into the buffer (like in the code examples above) so no data is lost.
  • Graceful Shutdown: Always handle InterruptedException properly to let threads exit cleanly without leaving data in limbo.
  • Batch Size Limits: If your buffer can get huge, add a max size to drainTo() (e.g., timestampBuffer.drainTo(batchToSync, 100)) to avoid overwhelming the database with massive writes.

内容的提问来源于stack exchange,提问作者Leonardo

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.25 07:43:41