Java Guice Singleton尊重线程限制吗?

Java Guice Singleton尊重线程限制吗?,java,dependency-injection,singleton,guice,Java,Dependency Injection,Singleton,Guice,我担心Guice以及它的单体是否会遵守线程限制,我可能会尝试设置: public class CacheModule extends AbstractModule { @Override protected void configure() { // WidgetCache.class is located inside a 3rd party JAR that I // don't have the ability to modify.

我担心Guice以及它的单体是否会遵守线程限制,我可能会尝试设置:

public class CacheModule extends AbstractModule {
    @Override
    protected void configure() {
        // WidgetCache.class is located inside a 3rd party JAR that I
        // don't have the ability to modify.
        WidgetCache widgetCache = new WidgetCache(...lots of params);

        // Guice will reuse the same WidgetCache instance over and over across
        // multiple calls to Injector#getInstance(WidgetCache.class);
        bind(WidgetCache.class).toInstance(widgetCache);
    }
}

// CacheAdaptor is the "root" of my dependency tree. All other objects
// are created from it.
public class CacheAdaptor {
    private CacheModule bootstrapper = new CacheModule();

    private WidgetCache widgetCache;

    public CacheAdaptor() {
        super();

        Injector injector = Guice.createInjector(bootstrapper);

        setWidgetCache(injector.getInstance(WidgetCache.class));
    }

    // ...etc.
}
如您所见,每当我们创建
cacheadapter
的新实例时,都会使用
CacheModule
来引导它下面的整个依赖关系树

如果
新建cacheadapter(),会发生什么情况是从多个线程内部调用的?

例如:线程1通过其无参数构造函数创建一个新的
cacheadapter
,而线程2做同样的事情Guice会为每个线程的
CacheAdapter
提供相同的
WidgetCache
实例,还是会为每个线程提供两个不同的实例?
即使
toInstance(…)
应该返回相同的单例实例,我希望-由于模块是在两个不同的线程中创建的-每个
cacheadapter
将接收不同的
WidgetCache
实例

提前谢谢

不仅Guice将为同一个注入器跨线程提供相同的单例,而且如果使用
toInstance
,Guice只能跨线程提供相同的单例。每个注入器对模块进行一次评估,您给Guice提供了一个实例,但无法生成第二个实例

Guice不是魔法。当试图提供一个对象的实例时,它需要(1)一个GUI友好的无参数或
@Inject
-注释的构造函数;(2)
提供者
@提供了
方法,允许您自己创建实例;或者(3)您已经创建并与
toInstance
绑定的实例,Guice重用该实例,因为它不知道如何创建另一个实例。请注意,使用
提供程序的选项2不需要保证每次都创建一个新实例,我们可以利用它来编写具有ThreadLocal缓存的
提供程序。它看起来像这样:

public class CacheModule extends AbstractModule {
    /** This isn't needed anymore; the @Provides method below is sufficient. */
    @Override protected void configure() {}

    /** This keeps a WidgetCache per thread and knows how to create a new one. */
    private ThreadLocal<WidgetCache> threadWidgetCache = new ThreadLocal<>() {
        @Override protected WidgetCache initialValue() {
            return new WidgetCache(...lots of params);
        }
    };

    /** Provide a single separate WidgetCache for each thread. */
    @Provides WidgetCache provideWidgetCache() {
        return threadWidgetCache.get();
    }
}
public class CacheModule extends AbstractModule {
    @Override
    protected void configure() {
        bindScope(ThreadScoped.class, new ThreadScope());
    }

    /** Provide a single separate WidgetCache for each thread. */
    @Provides @ThreadScoped WidgetCache provideWidgetCache() {
        return new WidgetCache(...lots of params);
    }
}

请记住,单例行为并不取决于您在哪个线程中创建模块,而是取决于您正在询问哪个注入器。如果您创建了五个不相关的
Injector
实例,那么它们都有自己的单例。如果您只是试图以多线程方式运行一个小算法,您可以为每个线程创建自己的注入器,但这样您就失去了创建跨线程的单例对象的机会。

您谈到了单例,但我看不到any@PhilippSander-
bind(WidgetCache.class).toInstance(WidgetCache)
创建一个singleton
WidgetCache
实例,然后不管客户端请求它多少次都重用它(通过
Injector\getInstance(WidgetCache.class)
。你刚刚回答了你的问题……再次感谢@PhilippSander-但你读过我的问题吗?这个问题涉及Guice跨多个线程的行为。我知道,对于单线程应用程序,
bind(WidgetCache.class)。toInstance(WidgetCache)
创建了一个单例-但是这个单例线程是否受限?非常可能的是,由thread#1中的模块获得的
WidgetCache
实例将不同于在thread#2中获得的实例。是的,我创建了-它实际上在上面以粗体显示,如下所示:“如果new CacheAdapter()“是从多个线程内部调用的?”。我一直很感谢@PhilippSander的所有输入,但如果您不知道这个问题的答案,我会请您继续问另一个问题。谢谢@Jeff Bowman(+1)-我想我开始透过树看到森林了。我有一个后续问题要问您:您的第二句话是“每个注入器对模块进行一次评估,你给了Guice一个实例,却没有办法生成第二个。”你能详细说明一下你的意思吗?我只给Guice一个实例什么?我如何生成“第二个”呢“当然可以。如果你能向我解释一下,我应该可以把所有的点都连接起来。再次感谢!@IAmYourFaja我最终重构了我的答案,包括一种在提供者方法中手动执行的方法。很抱歉,它太长了,但我想它会更好地解释Guice对象是如何创建和确定范围的。
public class CacheModule extends AbstractModule {
    @Override
    protected void configure() {
        bindScope(ThreadScoped.class, new ThreadScope());
    }

    /** Provide a single separate WidgetCache for each thread. */
    @Provides @ThreadScoped WidgetCache provideWidgetCache() {
        return new WidgetCache(...lots of params);
    }
}