TTL的CRR操作

简介: TTL的CRR操作

要有最朴素的梦想,即使明天天寒地冻,路远马亡。——海子

前段时间遇到的TTL(TransmittableThreadLocal)在异步编程中的上下文丢失问题,我是采用了直接更换线程池的方式

但今天抽空看了下官方文档,发现了:

所有TTL值的抓取、回放和恢复方法(即CRR操作)

CRRcapture(快照)replay(回放)restore(备份)

自己简单写了个测试用例,用于在CompletableFuture和并行流场景下解决ThreadLocal的上下文丢失问题

大伙一定要复制到本地跑一下,需要的GAV是这个:

<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>transmittable-thread-local</artifactId>
    <version>2.12.4</version>
</dependency>

代码:

import com.alibaba.ttl.TransmittableThreadLocal;
import lombok.SneakyThrows;
import org.junit.Ignore;
import org.junit.jupiter.api.Assertions;
import org.junit.Test;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Stream;
/**
 * TTL单元测试
 *
 * @author <achao1441470436@gmail.com>
 * @since 2022/1/24 18:41
 */
public class TtlTest {
    @Test
    @SneakyThrows
    public void testCompletableFuture() {
        ThreadLocal<Integer> threadLocal = new InheritableThreadLocal<>();
        Stream.iterate(0, i -> ++i).limit(2).forEach(i -> {
            threadLocal.set(i);
            CompletableFuture.runAsync(() -> Assertions.assertEquals(i, threadLocal.get())).join();
            threadLocal.remove();
        });
    }
    @Test
    @SneakyThrows
    public void testCompletableFutureReplayRestore() {
        ThreadLocal<Integer> threadLocal = new TransmittableThreadLocal<>();
        Stream.iterate(0, i -> ++i).limit(2).forEach(i -> {
            threadLocal.set(i);
            // (1) 抓取当前线程的所有TTL值
            final Object captured = TransmittableThreadLocal.Transmitter.capture();
            CompletableFuture.runAsync(() -> {
                // 异步
                // (2) 在线程 B中回放在capture方法中抓取的TTL值,并返回 回放前TTL值的备份
                final Object backup = TransmittableThreadLocal.Transmitter.replay(captured);
                try {
                    // 你的业务逻辑,这里你可以获取到外面设置的TTL值
                    Assertions.assertEquals(i, threadLocal.get());
                } finally {
                    // (3) 恢复线程 B执行replay方法之前的TTL值(即备份)
                    TransmittableThreadLocal.Transmitter.restore(backup);
                }
            }).join();
            threadLocal.remove();
        });
    }
    @Test
    @SneakyThrows
    public void testCompletableFutureTransmitter() {
        ThreadLocal<Integer> threadLocal = new TransmittableThreadLocal<>();
        Stream.iterate(0, i -> ++i).limit(2).forEach(i -> {
            threadLocal.set(i);
            // (1) 抓取当前线程的所有TTL值
            final Object captured = TransmittableThreadLocal.Transmitter.capture();
            CompletableFuture.runAsync(() ->
                    // 异步
                    TransmittableThreadLocal.Transmitter.runSupplierWithCaptured(captured, () -> {
                        // 你的业务逻辑,这里你可以获取到外面设置的TTL值
                        Assertions.assertEquals(i, threadLocal.get());
                        return null;
                    })).join();
            threadLocal.remove();
        });
    }
    @Test
    public void testParallelStream() {
        ThreadLocal<Integer> threadLocal = new TransmittableThreadLocal<>();
        Stream.iterate(0, i -> ++i).limit(1).peek(threadLocal::set)
                .flatMap(item -> Stream.of(item, item).parallel().peek(i -> Assertions.assertEquals(i, threadLocal.get())))
                .peek(t -> threadLocal.remove()).forEach(System.out::println);
    }
    @Test
    public void testParallelStreamReplayRestore() {
        ThreadLocal<Integer> threadLocal = new TransmittableThreadLocal<>();
        Stream.iterate(0, i -> ++i).limit(1).peek(threadLocal::set)
                .flatMap(item -> {
                    // (1) 抓取当前线程的所有TTL值
                    final Object captured = TransmittableThreadLocal.Transmitter.capture();
                    return Stream.of(item, item).parallel().peek(i -> {
                        // 异步
                        // (2) 在线程 B中回放在capture方法中抓取的TTL值,并返回 回放前TTL值的备份
                        final Object backup = TransmittableThreadLocal.Transmitter.replay(captured);
                        try {
                            // 你的业务逻辑,这里你可以获取到外面设置的TTL值
                            Assertions.assertEquals(i, threadLocal.get());
                        } finally {
                            // (3) 恢复线程 B执行replay方法之前的TTL值(即备份)
                            TransmittableThreadLocal.Transmitter.restore(backup);
                        }
                    });
                })
                .peek(t -> threadLocal.remove()).forEach(System.out::println);
    }
    @Test
    public void testParallelStreamTransmitter() {
        ThreadLocal<Integer> threadLocal = new TransmittableThreadLocal<>();
        Stream.iterate(0, i -> ++i).limit(1).peek(threadLocal::set)
                .flatMap(item -> {
                    // (1) 抓取当前线程的所有TTL值
                    final Object captured = TransmittableThreadLocal.Transmitter.capture();
                    return Stream.of(item, item).parallel().peek(i ->
                            // 异步
                            TransmittableThreadLocal.Transmitter.runSupplierWithCaptured(captured, () -> {
                                // 你的业务逻辑,这里你可以获取到外面设置的TTL值
                                Assertions.assertEquals(i, threadLocal.get());
                                return null;
                            }));
                })
                .peek(t -> threadLocal.remove()).forEach(System.out::println);
    }
}

最后测试结果:

相关文章
|
4月前
|
数据采集
1-2 TTL电瓶特性
1-2 TTL电瓶特性
38 0
|
NoSQL MongoDB 数据库
MongoDB 自动删除集合中过期的数据——TTL索引
简介 ​ TTL (Time To Live, 有生命周期的) 索引是特殊单字段索引,MongoDB可以用来在一定时间后自动从集合中删除文档的特殊索引。 这对于某些类型的数据非常好,例如机器生成的事件数据,日志和会话信息,这些信息只需要在数据库中保留一段时间。 ​ 创建 TTL 索引,只需要在使用 db.collection.createIndex() 方法,对字段值为日期或者包含日期的数组设置 expireAfterSeconds 选项即可。 1、如果字段是一个数组,并有多个日期值时,MongoDB使用最低(即最早)日期值来计算失效阈值。 2、如果字段不是日期类型也不是一个包含日期的数组
952 0
|
27天前
|
存储 安全 搜索推荐
深入理解 Session-Expire 头字段的作用
【8月更文挑战第24天】
9 0
|
数据可视化 Java 分布式数据库
PolarDB-X 数据 TTL 过期删除(三)| 学习笔记
快速学习 PolarDB-X 数据 TTL 过期删除。
180 0
PolarDB-X 数据 TTL 过期删除(三)| 学习笔记
|
运维 分布式数据库 调度
PolarDB-X 数据 TTL 过期删除(二)| 学习笔记
快速学习 PolarDB-X 数据 TTL 过期删除。
284 0
PolarDB-X 数据 TTL 过期删除(二)| 学习笔记
|
存储 运维 关系型数据库
PolarDB-X 数据 TTL 过期删除(一)| 学习笔记
快速学习 PolarDB-X 数据 TTL 过期删除。
225 0
PolarDB-X 数据 TTL 过期删除(一)| 学习笔记
|
消息中间件
死信队列 和消息TTL过期代码
先从概念解释上搞清楚这个定义,死信,顾名思义就是无法被消费的消息,字面意思可以这样理解,一般来说,producer将消息投递到broker或者直接到queue里了,consumer从queue取出消息进行消费,但某些时候由于特定的原因导致queue中的某些消息无法被消费,这样的消息如果没有后续的处理,就变成了死信,有死信自然就有了死信队列。
死信队列 和消息TTL过期代码
|
消息中间件 NoSQL Java
定时轮询,DelayQueue,ZSet,TTL+DLX(建议收藏)
定时轮询,DelayQueue,ZSet,TTL+DLX(建议收藏)
293 0
定时轮询,DelayQueue,ZSet,TTL+DLX(建议收藏)
|
消息中间件
RabbitMQ高级特性-TTL(Time-To-Live 过期时间)
RabbitMQ高级特性-TTL(Time-To-Live 过期时间)
116 0
RabbitMQ高级特性-TTL(Time-To-Live 过期时间)