Java Guice Singleton尊重线程限制吗?
我担心Guice以及它的单体是否会遵守线程限制,我可能会尝试设置: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.
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)
创建一个singletonWidgetCache
实例,然后不管客户端请求它多少次都重用它(通过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);
}
}