diff --git a/hutool-core/src/main/java/cn/hutool/v7/core/cache/impl/SieveCache.java b/hutool-core/src/main/java/cn/hutool/v7/core/cache/impl/SieveCache.java
new file mode 100644
index 000000000..9a73a9d55
--- /dev/null
+++ b/hutool-core/src/main/java/cn/hutool/v7/core/cache/impl/SieveCache.java
@@ -0,0 +1,282 @@
+/*
+ * Copyright (c) 2013-2025 Hutool Team and hutool.cn
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package cn.hutool.v7.core.cache.impl;
+
+import cn.hutool.v7.core.lang.mutable.Mutable;
+import cn.hutool.v7.core.lang.mutable.MutableObj;
+
+import java.io.Serial;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.concurrent.locks.ReentrantLock;
+
+/**
+ * SIEVE 缓存算法实现
+ *
+ * SIEVE 是一种比 LRU 更简单且通常更高效的缓存算法
+ * 它不需要在缓存命中时移动节点,仅需设置一个访问位
+ * 驱逐时使用一个指针(Hand)扫描队列,淘汰未被访问的节点
+ * 驱逐时遇到已访问的节点会设置为未访问,用于淘汰过期节点
+ *
+ *
+ * @param 键类型
+ * @param 值类型
+ * @author Lettuceleaves
+ */
+public class SieveCache extends LockedCache {
+ @Serial
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * 双向链表头节点
+ */
+ private SieveCacheObj head;
+ /**
+ * 双向链表尾节点
+ */
+ private SieveCacheObj tail;
+ /**
+ * 下一次扫描的起始位置
+ */
+ private SieveCacheObj hand;
+
+ /**
+ * 构造
+ * 默认无超时
+ *
+ * @param capacity 容量
+ */
+ public SieveCache(int capacity) {
+ this(capacity, 0);
+ }
+
+ /**
+ * 构造
+ *
+ * @param capacity 容量
+ * @param timeout 默认超时时间,单位:毫秒
+ */
+ public SieveCache(int capacity, long timeout) {
+ if (Integer.MAX_VALUE == capacity) {
+ capacity -= 1;
+ }
+
+ this.capacity = capacity;
+ this.timeout = timeout;
+
+ // 这里的设置 capacity + 1, 1.0f 避免触发扩容
+ this.cacheMap = new HashMap<>(capacity + 1, 1.0f);
+ this.lock = new ReentrantLock();
+ }
+
+
+ @Override
+ protected void putWithoutLock(K key, V object, long timeout) {
+ final Mutable keyObj = MutableObj.of(key);
+ SieveCacheObj co = (SieveCacheObj) cacheMap.get(keyObj);
+
+ if (co != null) {
+ final SieveCacheObj newCo = new SieveCacheObj<>(key, object, timeout);
+
+ // 新加入的节点,默认刚访问过,防止立刻被淘汰
+ newCo.visited = true;
+
+ // 替换旧节点
+ replaceNode(co, newCo);
+ cacheMap.put(keyObj, newCo);
+
+ } else {
+ if (isFull()) {
+ pruneCache();
+ }
+ co = new SieveCacheObj<>(key, object, timeout);
+ cacheMap.put(keyObj, co);
+ addToHead(co);
+ co.visited = false;
+ }
+ }
+
+ /**
+ * 在双向链表中用 newNode 替换 oldNode,保持链表结构不变
+ *
+ * @param oldNode 旧节点
+ * @param newNode 新节点
+ */
+ private void replaceNode(SieveCacheObj oldNode, SieveCacheObj newNode) {
+ newNode.prev = oldNode.prev;
+ newNode.next = oldNode.next;
+
+ // 更新前向指针
+ if (oldNode.prev != null) {
+ oldNode.prev.next = newNode;
+ } else {
+ head = newNode;
+ }
+
+ // 更新后向指针
+ if (oldNode.next != null) {
+ oldNode.next.prev = newNode;
+ } else {
+ tail = newNode;
+ }
+
+ oldNode.prev = null;
+ oldNode.next = null;
+ }
+
+ @Override
+ protected CacheObj getOrRemoveExpiredWithoutLock(K key) {
+ final Mutable keyObj = MutableObj.of(key);
+ final SieveCacheObj co = (SieveCacheObj) cacheMap.get(keyObj);
+
+ if (null != co) {
+ if (co.isExpired()) {
+ removeWithoutLock(key);
+ return null;
+ }
+
+ co.visited = true;
+ co.lastAccess = System.currentTimeMillis();
+ }
+ return co;
+ }
+
+ @Override
+ protected CacheObj removeWithoutLock(K key) {
+ final Mutable keyObj = MutableObj.of(key);
+ final SieveCacheObj co = (SieveCacheObj) cacheMap.remove(keyObj);
+ if (co != null) {
+ removeNode(co);
+ }
+ return co;
+ }
+
+
+ /**
+ * 优先清理过期对象,如果容量仍溢出,反向扫描visited为false的节点,设置true节点为false
+ */
+ @Override
+ protected int pruneCache() {
+ int count = 0;
+
+ if (isPruneExpiredActive()) {
+ final Iterator> values = cacheObjIter();
+ CacheObj co;
+ while (values.hasNext()) {
+ co = values.next();
+ if (co.isExpired()) {
+ values.remove();
+ removeNode((SieveCacheObj) co);
+ onRemove(co.key, co.obj);
+ count++;
+ }
+ }
+ }
+
+ while (isFull() && hand != null) {
+ if (!hand.visited) {
+ final SieveCacheObj victim = hand;
+ hand = hand.prev;
+ final Mutable keyObj = MutableObj.of(victim.key);
+ cacheMap.remove(keyObj);
+ removeNode(victim);
+ onRemove(victim.key, victim.obj);
+ count++;
+ } else {
+
+ // 近期被访问过,就先设置为false
+ hand.visited = false;
+ hand = hand.prev;
+ if (hand == null) {
+
+ // 没找到能淘汰的节点,重新扫描一边
+ hand = tail;
+ }
+ }
+ }
+ return count;
+ }
+
+
+ /**
+ * 将节点加入链表头部
+ *
+ * @param node 节点
+ */
+ private void addToHead(SieveCacheObj node) {
+ node.next = head;
+ node.prev = null;
+ if (head != null) {
+ head.prev = node;
+ }
+ head = node;
+ if (tail == null) {
+ tail = node;
+ }
+ }
+
+ /**
+ * 从链表中移除节点
+ *
+ * @param node 节点
+ */
+ private void removeNode(SieveCacheObj node) {
+ if (node == hand) {
+ hand = node.prev;
+ }
+
+ if (node.prev != null) {
+ node.prev.next = node.next;
+ } else {
+ head = node.next;
+ }
+
+ if (node.next != null) {
+ node.next.prev = node.prev;
+ } else {
+ tail = node.prev;
+ }
+
+ node.next = null;
+ node.prev = null;
+ }
+
+ /**
+ * 给节点添加visited属性,用于Sieve缓存淘汰策略
+ */
+ private static class SieveCacheObj extends CacheObj {
+ @Serial
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * 是否被访问过
+ */
+ boolean visited = false;
+ /**
+ * 前向节点
+ */
+ SieveCacheObj prev;
+ /**
+ * 后向节点
+ */
+ SieveCacheObj next;
+
+ protected SieveCacheObj(final K key, final V obj, final long ttl) {
+ super(key, obj, ttl);
+ }
+ }
+}