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

最后测试结果:

相关文章
|
7月前
|
数据采集
1-2 TTL电瓶特性
1-2 TTL电瓶特性
76 0
|
NoSQL MongoDB 数据库
MongoDB 自动删除集合中过期的数据——TTL索引
简介 ​ TTL (Time To Live, 有生命周期的) 索引是特殊单字段索引,MongoDB可以用来在一定时间后自动从集合中删除文档的特殊索引。 这对于某些类型的数据非常好,例如机器生成的事件数据,日志和会话信息,这些信息只需要在数据库中保留一段时间。 ​ 创建 TTL 索引,只需要在使用 db.collection.createIndex() 方法,对字段值为日期或者包含日期的数组设置 expireAfterSeconds 选项即可。 1、如果字段是一个数组,并有多个日期值时,MongoDB使用最低(即最早)日期值来计算失效阈值。 2、如果字段不是日期类型也不是一个包含日期的数组
1003 0
|
2月前
|
Linux 网络架构 Windows
TTL传输中过期原因,ttl传输中过期的解决办法(ttl传输中过期怎么解决)
A3: 实际上,TTL值需依据实际网络环境设定。过小的TTL值可能导致数据包过早丢弃,影响通信;反之,过大的TTL值则可能占用不必要的网络资源。因此,科学合理的TTL值设定是平衡通信效率与资源利用的关键。
747 0
|
存储 程序员 PHP
修改session的过期(生存)时间
以下我以php为例,万变不离其宗,希望对大家都有用吧。 session与cookie: 了解过两者的众所都知道,有些信息保存到cookie,有些出于安全问题就不能直接存到浏览器,这就要用到session了。然而对于浏览器,一般都是默认20-30分钟自动销毁或者关闭浏览器就会销毁。这显示是很头疼的事情,比如我们要实现用户登陆功能,关闭浏览器就要重新登陆,这搞什么鬼?所以我们要去试图改变它们。网上众说纷纭,你可以选择去修改默认配置文件,如php为例,修改php.ini的函数。但是染念却不喜欢修改修改默认,也在网上看到某些程序员是没有权限修改的,所以我们需要做到如何不修改默认文件达到这样的功能。
79 0
|
消息中间件
RabbmitMQ学习笔记-TTL消息详解
RabbmitMQ学习笔记-TTL消息详解
61 0
|
SQL
根据时间字段删除一定时间内的记录
根据时间字段删除一定时间内的记录
144 0
|
消息中间件
RabbitMQ高级特性-TTL(Time-To-Live 过期时间)
RabbitMQ高级特性-TTL(Time-To-Live 过期时间)
138 0
RabbitMQ高级特性-TTL(Time-To-Live 过期时间)
【TP5.1】根据时间条件的查询
【TP5.1】根据时间条件的查询
181 0
如何使用time_expire绝对超时时间-参数解读系列
说明:    time_expire,绝对超时时间,格式为yyyy-MM-dd HH:mm。注:1)以支付宝系统时间为准;2)如果和timeout_express参数同时传入,以time_expire为准。
2223 12