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);
    }
}

最后测试结果:

目录
打赏
0
0
0
0
29
分享
相关文章
|
10月前
|
1-2 TTL电瓶特性
1-2 TTL电瓶特性
111 0
MongoDB 自动删除集合中过期的数据——TTL索引
简介 ​ TTL (Time To Live, 有生命周期的) 索引是特殊单字段索引,MongoDB可以用来在一定时间后自动从集合中删除文档的特殊索引。 这对于某些类型的数据非常好,例如机器生成的事件数据,日志和会话信息,这些信息只需要在数据库中保留一段时间。 ​ 创建 TTL 索引,只需要在使用 db.collection.createIndex() 方法,对字段值为日期或者包含日期的数组设置 expireAfterSeconds 选项即可。 1、如果字段是一个数组,并有多个日期值时,MongoDB使用最低(即最早)日期值来计算失效阈值。 2、如果字段不是日期类型也不是一个包含日期的数组
1020 0
TTL传输中过期原因,ttl传输中过期的解决办法(ttl传输中过期怎么解决)
A3: 实际上,TTL值需依据实际网络环境设定。过小的TTL值可能导致数据包过早丢弃,影响通信;反之,过大的TTL值则可能占用不必要的网络资源。因此,科学合理的TTL值设定是平衡通信效率与资源利用的关键。
1240 0
RabbitMQ高级特性-TTL(Time-To-Live 过期时间)
RabbitMQ高级特性-TTL(Time-To-Live 过期时间)
153 0
RabbitMQ高级特性-TTL(Time-To-Live 过期时间)
Redis系列:设置/移除键的过期时间
云栖号资讯:【点击查看更多行业资讯】在这里您可以找到不同行业的第一手的上云资讯,还在等什么,快来! 1. 数据库数量 默认情况下,Redis服务器有16个数据库,分别为db0~db15,如下图所示: 该数量是由配置文件中的databases选项决定的,默认值为16: 2.
Redis系列:设置/移除键的过期时间
AI助理

你好,我是AI助理

可以解答问题、推荐解决方案等