How Guice Introduces Singletones and Nonselectors in Multiple Streams

Say I have a class:

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() { ... } } 

And I have another class:

 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); } } 

So Guice injects MyTask using Fizz , and also introduces MyTaskDispatcher with ThreadFactory , which is then used to create and execute the MyTask instances that it passed. And, since it is a cached pool, it only creates a new thread when it is needed but not available.

I wonder how Guice behaves in a multi-threaded environment when we insert Fizz as single or non-single.

Let's start with the non-Singleton for-instance:

 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); } } 

Now let's say that the application has been running for some time, and 3 separate MyTask have been sent, and thus there are 3 running threads. Since we did not ask Guice to introduce Fizz es as a singleton, I assume that each thread has its own copy of the input of FizzImpl , and we do not need to add any synchronize type code to prevent 3 FizzImpl from colliding and causing problems with the stream.

But what happens when we make a FizzImpl Guice injection as a single ???? Now, in MyAppModule :

  @Provides @Singleton FizzImpl providesFizz() { return new FizzImpl(true, Buzz.ALWAYS, 35); } 

If Guice provides only one global singleton instance from FizzImpl , what are the subsequent branches of this FizzImpl โ€œcopyโ€ (if that's the right word for it) inside each of the 3 generated threads? What are the pitfalls to watch out for? What are the ways to deal with these pitfalls? Thanks in advance.

+3
source share
1 answer

No, Fizz will be created with an instance of MyTask, and it will be saved using multiple thread calls. If you want to have a copy of Fizz for each stream, you have to do it in a lazy way.

 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() { ... } } 

Be that as it may, if you set the Singleton flag to a Fizz binding, the provider will return the same instance when you call fizzProvider.get (), so all threads will have the same instance. You must keep it not alone.

Also your module is wrong, you should use a method or implicit binding, and not both. Also, you cannot provide an instance and enter its interface.

 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); } } 

or

 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); } } 

Hope this helps!

+1
source

All Articles