diff --git a/hutool-core/src/main/java/cn/hutool/core/collection/RingIndexUtil.java b/hutool-core/src/main/java/cn/hutool/core/collection/RingIndexUtil.java new file mode 100644 index 000000000..31c9ebc7a --- /dev/null +++ b/hutool-core/src/main/java/cn/hutool/core/collection/RingIndexUtil.java @@ -0,0 +1,100 @@ +package cn.hutool.core.collection; + +import cn.hutool.core.lang.Assert; + +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicLong; + +/** + * 集合索引环形获取工具类 + * + * @author ZhouChuGang + * @since 5.7.15 + */ +public class RingIndexUtil { + + /** + * 通过cas操作 实现对指定值内的回环累加 + * + * @param object 集合 + * + * @param atomicLong 原子操作类 + * @return 索引位置 + */ + public static long ringNextLongByObj(Object object, AtomicLong atomicLong) { + Assert.notNull(object); + int modulo = CollUtil.size(object); + return ringNextLong(modulo, atomicLong); + } + + /** + * 通过cas操作 实现对指定值内的回环累加 + * + * @param object 集合 + * + * @param atomicInteger 原子操作类 + * @return 索引位置 + */ + public static int ringNextIntByObj(Object object, AtomicInteger atomicInteger) { + Assert.notNull(object); + int modulo = CollUtil.size(object); + return ringNextInt(modulo, atomicInteger); + } + + /** + * 通过cas操作 实现对指定值内的回环累加 + * + * @param modulo 回环周期值 + * @param atomicInteger 原子操作类 + * @return 索引位置 + */ + public static int ringNextInt(int modulo, AtomicInteger atomicInteger) { + Assert.notNull(atomicInteger); + Assert.isTrue(modulo > 0); + if (modulo == 1) { + return 0; + } + for (; ; ) { + int current = atomicInteger.get(); + int next = (current + 1) % modulo; + if (atomicInteger.compareAndSet(current, next)) { + return next; + } + } + } + + /** + * 通过cas操作 实现对指定值内的回环累加 + * + * @param modulo 回环周期值 + * @param atomicLong 原子操作类 + * @return 索引位置 + */ + public static long ringNextLong(long modulo, AtomicLong atomicLong) { + Assert.notNull(atomicLong); + Assert.isTrue(modulo > 0); + if (modulo == 1) { + return 0; + } + for (; ; ) { + long current = atomicLong.get(); + long next = (current + 1) % modulo; + if (atomicLong.compareAndSet(current, next)) { + return next; + } + } + } + +} diff --git a/hutool-core/src/test/java/cn/hutool/core/collection/RingIndexUtilTest.java b/hutool-core/src/test/java/cn/hutool/core/collection/RingIndexUtilTest.java new file mode 100644 index 000000000..7ea1df65e --- /dev/null +++ b/hutool-core/src/test/java/cn/hutool/core/collection/RingIndexUtilTest.java @@ -0,0 +1,51 @@ +package cn.hutool.core.collection; + +import cn.hutool.core.thread.ThreadUtil; +import org.junit.Test; + +import java.util.Arrays; +import java.util.List; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicLong; + +/** + * 集合索引环形获取工具类测试类 + * + * @author ZhouChuGang + * @version 1.0 + * @project hutool + * @date 2021/10/13 18:47 + */ +public class RingIndexUtilTest { + + private final List strList = Arrays.asList("0", "1", "2", "3", "4", "5", "6", "7", "8", "9"); + + /** + * 观察输出的打印为不重复的 + */ + @Test + public void ringNextLongByObjTest() { + final AtomicLong atomicLong = new AtomicLong(); + // 开启并发测试,每个线程获取到的元素都是唯一的 + ThreadUtil.concurrencyTest(strList.size(), () -> { + final long index = RingIndexUtil.ringNextLongByObj(strList, atomicLong); + final String s = strList.get((int) index); + System.out.println(s); + }); + } + + /** + * 观察输出的打印为不重复的 + */ + @Test + public void ringNextIntByObjTest() { + final AtomicInteger atomicInteger = new AtomicInteger(); + // 开启并发测试,每个线程获取到的元素都是唯一的 + ThreadUtil.concurrencyTest(strList.size(), () -> { + final int index = RingIndexUtil.ringNextIntByObj(strList, atomicInteger); + final String s = strList.get(index); + System.out.println(s); + }); + } + +}