如何在不使用InheritableThreadLocal的情况下为每个顶级进程/线程创建共享上下文? [英] How to have a shared context per top-level process/thread without using InheritableThreadLocal?

查看:135
本文介绍了如何在不使用InheritableThreadLocal的情况下为每个顶级进程/线程创建共享上下文?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想看看是否有一个很好的模式,可以在不使用 InheritableThreadLocal 的情况下在顶级线程的所有类和子线程中共享上下文。

I'd like to see if there's a good pattern for sharing a context across all classes and subthreads of a top-level thread without using InheritableThreadLocal.

我有几个顶级进程,每个进程都在自己的线程中运行。这些顶级进程通常会产生临时子线程。

I've got several top-level processes that each run in their own thread. These top-level processes often spawn temporary subthreads.

我希望每个顶级进程拥有并管理它自己的数据库连接。

I want each top level process to have and manage it's own database connection.

not 想要传递从类到类以及从线程到子线程的数据库连接(我的同事称之为社区自行车模式)。这些是顶级的大流程,这意味着可能会编辑数百个方法签名来传递这个数据库连接。

I do not want to pass around the database connection from class to class and from thread to subthread (my associate calls this the "community bicycle" pattern). These are big top-level processes and it would mean editing probably hundreds of method signatures to pass around this database connection.

现在我调用单例来获取数据库连接管理器。单例使用 InheritableThreadLocal ,以便每个顶级进程都拥有它自己的版本。虽然我知道有些人遇到单身人士问题,但这意味着每当我需要正确管理的连接时,我只能说 DBConnector.getDBConnection(args)(以解释)。如果我能找到一个更好但仍然干净的解决方案,我就不会依赖这种方法。

Right now I call a singleton to get the database connection manager. The singleton uses InheritableThreadLocal so that each top-level process has it's own version of it. While I know some people have problems with singletons, it means I can just say DBConnector.getDBConnection(args) (to paraphrase) whenever I need the correctly managed connection. I am not tied to this method if I can find a better and yet still-clean solution.

出于各种原因 InheritableThreadLocal 被证明是棘手的。 (请参阅此问题。)

For various reasons InheritableThreadLocal is proving to be tricky. (See this question.)

有没有人建议处理这种不需要 InheritableThreadLocal 或者遍布某个上下文对象的东西?

Does anyone have a suggestion to handle this kind of thing that doesn't require either InheritableThreadLocal or passing around some context object all over the place?

感谢您的帮助!

更新:我已经设法解决了眼前的问题(参见相关问题),但我还是想听听其他可能的方法。下面的四十二个建议是好的,并且确实有效(谢谢!),但请参阅评论为什么它有问题。如果人们投票支持jtahlborn的答案,并告诉我,我因为想要避免绕过我的数据库连接而迷恋,那么我会放松,选择那个作为我的答案,并修改我的世界观。

Update: I've managed to solve the immediate problem (see the linked question) but I'd still like to hear about other possible approaches. forty-two's suggestion below is good and does work (thanks!), but see the comments for why it's problematic. If people vote for jtahlborn's answer and tell me that I'm being obsessive for wanting to avoid passing around my database connection then I will relent, select that as my answer, and revise my world-view.

推荐答案

我没有测试过这个,但想法是创建一个自定义的ThreadPoolExecutor,它知道如何获取上下文对象并使用#beforeExecute()来传输上下文对象到要执行任务的线程。要成为一个好公民,你还应该清除#afterEXecute()中的上下文对象,但我把它留作练习。

I haven't tested this, but the idea is to create a customized ThreadPoolExecutor that knows how to get the context object and use #beforeExecute() to transfer the context object to the thread that is going to execute the task. To be a nice citizen, you should also clear the context object in #afterEXecute(), but I leave that as an exercise.

public class XyzThreadPoolExecutor extends ThreadPoolExecutor  {

public XyzThreadPoolExecutor() {
    super(3, 3, 100, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>(), new MyThreadFactory());
}

@Override
public void execute(Runnable command) {
    /*
     * get the context object from the calling thread
     */
    Object context = null;
    super.execute(new MyRunnable(context, command));
}

@Override
protected void beforeExecute(Thread t, Runnable r) {
    ((MyRunnable)r).updateThreadLocal((MyThread) t);
    super.beforeExecute(t, r);
}

private static class MyThreadFactory implements ThreadFactory {
    @Override
    public Thread newThread(Runnable r) {
        return new MyThread(r);
    }

}

private class MyRunnable implements Runnable {
    private final Object context;
    private final Runnable delegate;

    public MyRunnable(Object context, Runnable delegate) {
        super();
        this.context = context;
        this.delegate = delegate;
    }

    void updateThreadLocal(MyThread thread) {
        thread.setContext(context);
    }

    @Override
    public void run() {
        delegate.run();

    }
}

private static class MyThread extends Thread {

    public MyThread(Runnable target) {
        super(target);
    }

    public void setContext(Object context) {
        // set the context object here using thread local
    }

}
}

这篇关于如何在不使用InheritableThreadLocal的情况下为每个顶级进程/线程创建共享上下文?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆