Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

在CompletableFuture中使用TTL,主线程执行完成,但CompletableFuture未完成,是否可以可以释放上下文,主线程释放上下文后,CompletableFuture是否还能拿到TTL的值 #510

Closed
kginglam opened this issue May 31, 2023 · 1 comment
Assignees
Labels
🔰 first nice issue 👍 ❓question Further information is requested

Comments

@kginglam
Copy link

1.这是我包装的Executor

public class CustomThreadPoolTaskExecutor extends ThreadPoolTaskExecutor {



    @Override
    public void execute(Runnable runnable) {
        Runnable ttlRunnable = TtlRunnable.get(runnable);
        super.execute(ttlRunnable);
    }

    @Override
    public <T> Future<T> submit(Callable<T> task) {
        Callable ttlCallable = TtlCallable.get(task);
        return super.submit(ttlCallable);
    }

    @Override
    public Future<?> submit(Runnable task) {
        Runnable ttlRunnable = TtlRunnable.get(task);
        return super.submit(ttlRunnable);
    }

    @Override
    public ListenableFuture<?> submitListenable(Runnable task) {
        Runnable ttlRunnable = TtlRunnable.get(task);
        return super.submitListenable(ttlRunnable);
    }

    @Override
    public <T> ListenableFuture<T> submitListenable(Callable<T> task) {
        Callable ttlCallable = TtlCallable.get(task);
        return super.submitListenable(ttlCallable);
    }
}

2.这是我的TTL使用案例

@Service
public class Service{

    public Result useTtl(){
        try{
            // 1.主线程执行....


            // 2.使用 CompletableFuture
            CompletableFuture<Void> function_1 = CompletableFuture..runAsync(() -> todo, customThreadPoolTaskExecutor);
            CompletableFuture<Void> function_2 = CompletableFuture..runAsync(() -> todo, customThreadPoolTaskExecutor);
       
            // 3.等待 function_1 和 function_1 执行完成
            CompletableFuture.allOf(function_1,function_2).join();
        } finally{
            // remove ttl context
            TTL.remove();
        }
    }
}

以上代码,第3.等待 function_1 和 function_1 执行完成 的目的是为了让主线程等待,让子线程执行完成后再释放 TTL.remove();,但其实function_1function_2的代码,是可以让后台线程执行,主线程无需等待得知结果。如果不加CompletableFuture.allOf(function_1,function_2).join();的代码,子线程未执行完成,但主线程已经执行了TTL.remove();,那么function_1function_2还能拿到TTL的上下文吗?

@oldratlee
Copy link
Member

oldratlee commented May 31, 2023

1.这是我包装的Executor

你提到的ThreadPoolTaskExecutorSpring的实现类吧?

可以考虑使用SpringThreadPoolTaskExecutor#setTaskDecorator()方法 完成统一修饰,避免繁琐易错地去override不同方法,也会更安全可靠: @kginglam

ThreadPoolTaskExecutor threadPoolTaskExecutor = ...
threadPoolTaskExecutor.setTaskDecorator(TtlRunnable::get);

如果不加CompletableFuture.allOf(function_1,function_2).join();的代码,子线程未执行完成,但主线程已经执行了TTL.remove();,那么function_1function_2还能拿到TTL的上下文吗?

简单地说,可以的。 @kginglam

注意: ❗️
我这里「Remove之后可以」的前提是 异步执行。 @kginglam
同步执行在当前线程,Remove之后自然是没了。

CompletableFuture的任务执行不一定是异步的,可能/可以在当前线程中同步执行,可能需要了解影响,当然这些注意点与具体业务的使用逻辑是否正确相关。这些相关内容请具体请了解/调研 CompletableFutureCompletableFuture以及并发 都是复杂主题,本身有挺多内容要了解、理解、注意。 💕

PS:CompletableFuture的使用与理解好挺复杂的,会有要注意的地方;自己最近也在学习CompletableFuture 😄 整理实现的CompletableFuture辅助库 🦝 cffu
PPS: 对于功能问题或Bug的反馈,推荐给一个 极简 可运行 复现问题 的Demo代码工程(比如一个GitHub repo工程)。 @kginglam

@oldratlee oldratlee self-assigned this May 31, 2023
@oldratlee oldratlee added ❓question Further information is requested 🔰 first nice issue 👍 labels May 31, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
🔰 first nice issue 👍 ❓question Further information is requested
Projects
None yet
Development

No branches or pull requests

2 participants