说我有课:
public class MyTask implements Runnable {
@Inject
private Fizz fizz;
// Getters and setters for 'fizz'.
@Override
public void run() {
if(fizz.alleviatesBuzz())
doA();
else
doB();
}
private void doA() { ... }
private void doB() { ... }
}
然后我又开了一个班:
public class MyTaskDispatcher {
@Inject
private ThreadFactory threadFactory;
private Executor executor;
// Getter and setter for 'threadFactory'.
public void dispatch(MyTask task) {
if(executor == null)
executor = Executors.newCachedThreadPool(threadFactory);
executor.submit(task);
}
}
因此,Guice为MyTask
注入Fizz
,并为MyTaskDispatcher
注入一个ThreadFactory
,然后用于创建和执行MyTask
个实例通过。而且,由于它是一个缓存池,它只在需要一个新线程时创建一个新线程但不可用。
我想知道当我们将Fizz
注入单身或非单身时,Guice如何在多线程环境中“行为”。
让我们从非单例实例开始:
public class MyAppModule extends AbstractModule {
@Override
public void configure() {
bind(Fizz.class).to(FizzImpl.class);
// I don't think the functionality of MyThreadFactory
// really matters for the sake of this question.
bind(ThreadFactory.class).to(MyThreadFactory.class);
}
@Provides
FizzImpl providesFizz() {
return new FizzImpl(true, Buzz.ALWAYS, 35);
}
// I *believe* we always want the ThreadFactory to be singleton,
// because all of the threads spawn from it and its executor.
@Provides @Singleton
ThreadFactory providesThreadFactory() {
return new MyThreadFactory(12);
}
}
现在假设该应用程序已运行一段时间,并且已提交了3个单独的MyTask
,因此存在3个正在运行的线程。由于我们没有要求Guice将Fizz
es作为单例注入,我假设每个线程都有自己的注入FizzImpl
副本,我们不必添加任何synchronize
- 类型代码,以防止3 FizzImpl
发生冲突并导致线程问题。
但是当我们让Guice将FizzImpl
注入单身时会发生什么?!?现在,在MyAppModule
中:
@Provides @Singleton
FizzImpl providesFizz() {
return new FizzImpl(true, Buzz.ALWAYS, 35);
}
如果Guice只提供1个FizzImpl
的全局单例实例,那么FizzImpl
“副本”的下游分支是什么(如果这是正确的话) 3个产生的线程?有哪些陷阱需要注意?有什么方法可以解决这些陷阱?提前谢谢。
答案 0 :(得分:1)
不,Fizz将使用MyTask实例创建,它将持续存在多个线程调用。如果你想为每个线程都有一个Fizz副本,你必须以懒惰的方式进行。
public class MyTask implements Runnable {
@Inject
private Provider<Fizz> fizzProvider;
// Getters and setters for 'fizz'.
@Override
public void run() {
Fizz fizz = fizzProvider.get();
if(fizz.alleviatesBuzz())
doA();
else
doB();
}
private void doA() { ... }
private void doB() { ... }
}
如果你将一个Singleton标志放到Fizz绑定中,当你调用fizzProvider.get()时,提供程序将返回相同的实例,因此所有线程都将具有相同的实例。你必须保持非单身。
你的模块也是错误的,你应该使用方法或隐式绑定,而不是两者。此外,您无法提供实例并注入其界面。
public class MyAppModule extends AbstractModule {
@Override
public void configure() {
bind(Fizz.class).to(FizzImpl.class);
//or bind(Fizz.class).toInstance(new FizzImpl(true, Buzz.ALWAYS, 35)); //Singleton!!
//or bind(Fizz.class).toProvider(new Provider<Fizz>() {
// @Override
// public Subject get() {
// return new FizzImpl(true, Buzz.ALWAYS, 35);
// }
// });
// I don't think the functionality of MyThreadFactory
// really matters for the sake of this question.
bind(ThreadFactory.class).to(MyThreadFactory.class);
}
}
或
public class MyAppModule extends AbstractModule {
@Override
public void configure() {
}
@Provides
Fizz providesFizz() {
return new FizzImpl(true, Buzz.ALWAYS, 35);
}
// I *believe* we always want the ThreadFactory to be singleton,
// because all of the threads spawn from it and its executor.
@Provides @Singleton
ThreadFactory providesThreadFactory() {
return new MyThreadFactory(12);
}
}
希望它会有所帮助!