Java案例怎么实现版本控制锁?

wen java案例 62

本文目录导读:

Java案例怎么实现版本控制锁?

  1. 乐观锁实现(CAS方式)
  2. 数据库级别的版本控制锁
  3. 分布式版本控制锁(使用Redis)
  4. 完整的版本控制锁框架示例
  5. 使用示例和测试
  6. 版本控制锁的最佳实践

我来详细解释Java中实现版本控制锁的几种常见方式。

乐观锁实现(CAS方式)

使用版本号的简单实现

import java.util.concurrent.atomic.AtomicInteger;
// 数据实体类
class OptimisticData {
    private String id;
    private String content;
    private volatile int version;  // 版本号
    public OptimisticData(String id, String content) {
        this.id = id;
        this.content = content;
        this.version = 0;
    }
    // getters and setters
    public String getId() { return id; }
    public String getContent() { return content; }
    public int getVersion() { return version; }
    public void setContent(String content) { this.content = content; }
    public void setVersion(int version) { this.version = version; }
}
// 乐观锁管理器
class OptimisticLockManager {
    /**
     * 更新数据(使用版本号检查)
     */
    public boolean updateData(OptimisticData data, String newContent, int expectedVersion) {
        // 模拟数据库操作
        synchronized (this) {
            // 检查版本号是否匹配
            if (data.getVersion() == expectedVersion) {
                data.setContent(newContent);
                data.setVersion(expectedVersion + 1);
                return true;
            }
            return false;
        }
    }
}

使用AtomicStampedReference防止ABA问题

import java.util.concurrent.atomic.AtomicStampedReference;
class VersionedResource {
    private AtomicStampedReference<String> resource;
    public VersionedResource(String initialValue) {
        // 初始版本号为0
        this.resource = new AtomicStampedReference<>(initialValue, 0);
    }
    /**
     * 更新资源(包含版本号检查)
     */
    public boolean update(String newValue, int expectedStamp) {
        String currentValue = resource.getReference();
        int currentStamp = resource.getStamp();
        // 检查版本号是否匹配
        if (currentStamp == expectedStamp) {
            return resource.compareAndSet(currentValue, newValue, currentStamp, currentStamp + 1);
        }
        return false;
    }
    // 测试ABA问题的演示
    public static void main(String[] args) {
        VersionedResource resource = new VersionedResource("初始值");
        // 正常更新
        boolean result1 = resource.update("新值", 0);
        System.out.println("更新结果1: " + result1); // true
        // 使用过期版本号更新
        boolean result2 = resource.update("另一个值", 0);
        System.out.println("更新结果2: " + result2); // false
    }
}

数据库级别的版本控制锁

import java.sql.*;
import java.util.Date;
class DatabaseVersionLock {
    private static final String DB_URL = "jdbc:mysql://localhost:3306/test";
    private static final String USER = "root";
    private static final String PASS = "password";
    /**
     * 带版本控制的更新操作
     */
    public boolean updateWithVersion(String id, String newData, int expectedVersion) {
        String sql = "UPDATE data_table SET content = ?, version = version + 1, update_time = ? " +
                    "WHERE id = ? AND version = ?";
        try (Connection conn = DriverManager.getConnection(DB_URL, USER, PASS);
             PreparedStatement stmt = conn.prepareStatement(sql)) {
            stmt.setString(1, newData);
            stmt.setTimestamp(2, new Timestamp(new Date().getTime()));
            stmt.setString(3, id);
            stmt.setInt(4, expectedVersion);
            int rowsAffected = stmt.executeUpdate();
            return rowsAffected > 0;  // 返回true表示更新成功
        } catch (SQLException e) {
            e.printStackTrace();
            return false;
        }
    }
    /**
     * 创建数据表(示例)
     */
    public static void createTable() {
        String sql = "CREATE TABLE IF NOT EXISTS data_table (" +
                    "id VARCHAR(50) PRIMARY KEY, " +
                    "content TEXT, " +
                    "version INT DEFAULT 0, " +
                    "update_time TIMESTAMP" +
                    ")";
        try (Connection conn = DriverManager.getConnection(DB_URL, USER, PASS);
             Statement stmt = conn.createStatement()) {
            stmt.execute(sql);
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
}

分布式版本控制锁(使用Redis)

import redis.clients.jedis.Jedis;
import redis.clients.jedis.params.SetParams;
import java.util.UUID;
class RedisVersionLock {
    private Jedis jedis;
    public RedisVersionLock() {
        this.jedis = new Jedis("localhost", 6379);
    }
    /**
     * 获取分布式锁
     */
    public String acquireLock(String lockKey, long timeoutSeconds) {
        String lockValue = UUID.randomUUID().toString();
        String result = jedis.set(lockKey, lockValue, 
            SetParams.setParams().nx().ex(timeoutSeconds));
        if ("OK".equals(result)) {
            return lockValue;  // 返回锁的标识,用于释放锁
        }
        return null;  // 获取锁失败
    }
    /**
     * 释放分布式锁(使用Lua脚本保证原子性)
     */
    public boolean releaseLock(String lockKey, String lockValue) {
        String script = "if redis.call('get', KEYS[1]) == ARGV[1] then " +
                       "return redis.call('del', KEYS[1]) " +
                       "else return 0 end";
        Object result = jedis.eval(script, 1, lockKey, lockValue);
        return "1".equals(result.toString());
    }
    /**
     * 带版本控制的更新操作
     */
    public boolean updateWithVersionControl(String key, String newValue, int expectedVersion) {
        String versionKey = key + ":version";
        // 使用Lua脚本保证原子性
        String script = "local current_version = redis.call('get', KEYS[2]) " +
                       "if current_version and tonumber(current_version) == tonumber(ARGV[2]) then " +
                       "redis.call('set', KEYS[1], ARGV[1]) " +
                       "redis.call('incr', KEYS[2]) " +
                       "return 1 " +
                       "else return 0 end";
        Object result = jedis.eval(script, 2, key, versionKey, newValue, 
                                  String.valueOf(expectedVersion));
        return "1".equals(result.toString());
    }
}

完整的版本控制锁框架示例

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.locks.ReentrantLock;
class VersionLockFramework {
    private final Map<String, VersionedResource> resources = new ConcurrentHashMap<>();
    private final ReentrantLock lock = new ReentrantLock();
    static class VersionedResource {
        private Object data;
        private int version;
        private long lastModified;
        public VersionedResource(Object data) {
            this.data = data;
            this.version = 0;
            this.lastModified = System.currentTimeMillis();
        }
        public int getVersion() { return version; }
        public Object getData() { return data; }
        public long getLastModified() { return lastModified; }
    }
    /**
     * 版本控制更新操作
     */
    public boolean updateWithVersion(String resourceId, Object newData, int expectedVersion) {
        lock.lock();
        try {
            VersionedResource resource = resources.get(resourceId);
            if (resource == null) {
                throw new IllegalArgumentException("Resource not found: " + resourceId);
            }
            // 检查版本号
            if (resource.getVersion() != expectedVersion) {
                return false;  // 版本冲突
            }
            // 执行更新
            resource.data = newData;
            resource.version++;
            resource.lastModified = System.currentTimeMillis();
            return true;
        } finally {
            lock.unlock();
        }
    }
    /**
     * 创建资源
     */
    public VersionedResource createResource(String resourceId, Object initialData) {
        lock.lock();
        try {
            VersionedResource resource = new VersionedResource(initialData);
            resources.put(resourceId, resource);
            return resource;
        } finally {
            lock.unlock();
        }
    }
    /**
     * 获取当前版本号
     */
    public int getCurrentVersion(String resourceId) {
        VersionedResource resource = resources.get(resourceId);
        return resource != null ? resource.getVersion() : -1;
    }
}

使用示例和测试

public class VersionControlDemo {
    public static void main(String[] args) throws InterruptedException {
        // 测试基本版本控制
        VersionLockFramework framework = new VersionLockFramework();
        // 创建资源
        framework.createResource("doc1", "原始内容");
        int currentVersion = framework.getCurrentVersion("doc1");
        System.out.println("初始版本号: " + currentVersion);  // 0
        // 成功更新
        boolean success = framework.updateWithVersion("doc1", "修改内容1", currentVersion);
        System.out.println("更新成功: " + success);  // true
        System.out.println("当前版本号: " + framework.getCurrentVersion("doc1"));  // 1
        // 尝试使用过期版本号更新(模拟并发冲突)
        boolean failed = framework.updateWithVersion("doc1", "修改内容2", currentVersion);
        System.out.println("使用过期版本号更新: " + failed);  // false
        // 正确的版本号更新
        success = framework.updateWithVersion("doc1", "修改内容2", 1);
        System.out.println("使用正确版本号更新: " + success);  // true
    }
}

版本控制锁的最佳实践

  1. 选择合适的实现方式

    • 单机应用:使用乐观锁或synchronized
    • 分布式系统:使用Redis或ZooKeeper
  2. 注意ABA问题

    使用AtomicStampedReference或版本号递增

  3. 性能考虑

    • 乐观锁适合读多写少的场景
    • 悲观锁适合写操作频繁的场景
  4. 错误处理

    • 版本冲突时提供明确的错误信息
    • 实现重试机制

这些实现可以根据你的具体需求进行调整和组合使用。

抱歉,评论功能暂时关闭!