java - Do Guice singletons honor thread-confinement? -
i have concern regarding guice , whether or not singletons obey thread confinement may try set up:
public class cachemodule extends abstractmodule { @override protected void configure() { // widgetcache.class located inside 3rd party jar // don't have ability modify. widgetcache widgetcache = new widgetcache(...lots of params); // guice reuse same widgetcache instance on , on across // multiple calls injector#getinstance(widgetcache.class); bind(widgetcache.class).toinstance(widgetcache); } } // cacheadaptor "root" of dependency tree. other objects // created 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. }
so can see, time create new instance of cacheadaptor
, cachemodule
used bootstrap entire dependency tree underneath it.
what happens if new cacheadaptor();
called inside multiple threads?
for example: thread #1 creates new cacheadaptor
via no-arg constructor, , thread #2 same thing. will guice provide same exact widgetcache
instance each thread's cacheadaptor
, or guice provide 2 different instances each thread? though toinstance(...)
supposed return same singleton instance, i'm hoping - since modules created inside 2 distinct threads - each cacheadaptor
receive different widgetcache
instance.
thanks in advance!
it's not guice will provide same singleton across threads same injector, guice can only provide same singleton across threads if use toinstance
. modules evaluated once per injector, , gave guice 1 instance , no way produce second one.
guice isn't magic. when trying provide instance of object, either needs (1) guice-friendly no-arg or @inject
-annotated constructor; (2) provider
or @provides
method, letting create instance yourself; or (3) instance you've created , bound toinstance
, guice reuses because doesn't know how create another. note option 2, provider
, doesn't need guarantee creates new instance every single time, , can exploit write provider
has threadlocal cache. this:
public class cachemodule extends abstractmodule { /** isn't needed anymore; @provides method below sufficient. */ @override protected void configure() {} /** keeps widgetcache per thread , knows how create new one. */ private threadlocal<widgetcache> threadwidgetcache = new threadlocal<>() { @override protected widgetcache initialvalue() { return new widgetcache(...lots of params); } }; /** provide single separate widgetcache each thread. */ @provides widgetcache providewidgetcache() { return threadwidgetcache.get(); } }
of course, if want more 1 object, you'd have write threadlocal every single key want cache, , create provider each. seems little excessive, , that's custom scopes come in.
creating own threadlocal scope
check out scope's meaningful method:
/** * scopes provider. returned provider returns objects scope. * if object not exist in scope, provider can use given * unscoped provider retrieve one. * * <p>scope implementations encouraged override * {@link object#tostring} in returned provider , include backing * provider's {@code tostring()} output. * * @param key binding key * @param unscoped locates instance when 1 doesn't exist in * scope. * @return new provider delegates given unscoped provider * when instance of requested object doesn't exist in * scope */ public <t> provider<t> scope(key<t> key, provider<t> unscoped);
as can see scope interface, scope decorator provider
, , scoping thread-local tantamount returning threadlocal
-cached copy if exists or caching , returning passed provider
if doesn't. can write scope same logic did manually above.
in fact, need create new fooobject per-thread (for value of fooobject) common request—too of "advanced feature" base library, common enough example how write custom scope. adjust simplescope example needs, can leave out scope.enter()
, scope.exit()
calls, keep threadlocal<map<key<?>, object>>
act thread-local cache of objects.
at point, assuming you've created own @threadscoped
annotation threadscope
implementation you've written, can adjust module this:
public class cachemodule extends abstractmodule { @override protected void configure() { bindscope(threadscoped.class, new threadscope()); } /** provide single separate widgetcache each thread. */ @provides @threadscoped widgetcache providewidgetcache() { return new widgetcache(...lots of params); } }
remember, singleton behavior doesn't depend on threads create modules in, rather injector you're asking. if created 5 unrelated injector
instances, each have own singleton. if you're merely trying run small algorithm in multi-threaded way, create own injector per thread, way you'd lose chance make singleton objects span threads.
Comments
Post a Comment