初识Aerospike-Operate

64 阅读2分钟

operate是原子操作,这个操作会在aerospike执行里面代码的时候采用单线程处理

下面两个代码说明原子操作的安全性

案例1:不采用operate

    public static void main(String[] args) throws InterruptedException {
        // 创建Aerospike客户端(单例,多线程共享)
        AerospikeClient client = new AerospikeClient(HOST, PORT);
        // 线程数量(模拟10个并发请求)
        int threadCount = 10;
        CountDownLatch latch = new CountDownLatch(threadCount);
        System.out.println("开始执行" + threadCount + "个线程并发操作...");
        // 创建并启动多个线程
        for (int i = 0; i < threadCount; i++) {
            final int threadId = i;
            new Thread(() -> {
                try {
                    int currentValue;
                    if(client.exists(null, key)){
                        currentValue = 1;
                    }
                    else {
                        Bin bin = new Bin(BIN_NAME, "");
                        client.put(null, key, bin);
                        currentValue = 0;
                    }
                    System.out.println("线程" + threadId + " - currentValue: " + currentValue);
                } catch (Exception e) {
                    System.err.println("线程" + threadId + "执行失败: " + e.getMessage());
                } finally {
                    latch.countDown(); // 线程完成,计数器减1
                }
            }).start();
        }
        // 等待所有线程执行完成
        latch.await();
        System.out.println("所有线程执行完毕");
        // 关闭客户端
        client.close();
    }
}

结果如下图

image.png

这是因为非operate包装的操作,存在多线程并发问题,同时访问as去判断有没有这个key,就会存在线程1判断没有这个key然后往里put中,还未完全put完成,线程2~9也来了进行client.exists(null, key),而此时还未完全put完成,所以他们返回的结果都是0

案例2:采用operate操作

    public static void main(String[] args) throws InterruptedException {
        // 创建Aerospike客户端(单例,多线程共享)
        AerospikeClient client = new AerospikeClient(HOST, PORT);
        // 线程数量(模拟10个并发请求)
        int threadCount = 10;
        CountDownLatch latch = new CountDownLatch(threadCount);
        System.out.println("开始执行" + threadCount + "个线程并发操作...");
        // 创建并启动多个线程
        for (int i = 0; i < threadCount; i++) {
            final int threadId = i;
            new Thread(() -> {
                try {
                    // 每个线程执行operate操作
                    Key key = new Key(AS_NAMESPACE, SET_NAME, UNIQ_KEY);
                   Bin bin = new Bin(BIN_NAME, 1);

//                     执行原子操作:add+get
                   Record record = client.operate(null, key,
                           Operation.add(bin),
                           Operation.get(BIN_NAME));
//                     获取当前值并打印
                   int currentValue = record.getInt(BIN_NAME) == 1 ? 0 : 1;
                    System.out.println("线程" + threadId + " - currentValue: " + currentValue);
                } catch (Exception e) {
                    System.err.println("线程" + threadId + "执行失败: " + e.getMessage());
                } finally {
                    latch.countDown(); // 线程完成,计数器减1
                }
            }).start();
        }
        // 等待所有线程执行完成
        latch.await();
        System.out.println("所有线程执行完毕");
        // 关闭客户端
        client.close();
    }
}

结果如下图

image.png

而operate封装的方法会将add和get都用单线程按顺序去执行(原子操作),而其他的线程来了也要执行这个代码就会等待,这样,就解决了多线程并发问题