Spring singleton beans, maps and multithreadingShould I mark object attributes as volatile if I init them in @PostConstruct in Spring Framework?How do I efficiently iterate over each entry in a Java Map?What is an efficient way to implement a singleton pattern in Java?Sort a Map<Key, Value> by valuesWhat exactly is Spring Framework for?How do servlets work? Instantiation, sessions, shared variables and multithreadingSome questions on java multithreading,What's the difference between @Component, @Repository & @Service annotations in Spring?Spring: @Component versus @BeanWhat in the world are Spring beans?How to configure port for a Spring Boot application
Will a paper be retracted if a flaw in released software code invalidates its central idea?
How do I explain to a team that the project they will work on for six months will 100% fail?
Is The Lion King live action film made in motion capture?
During the Space Shuttle Columbia Disaster of 2003, Why Did The Flight Director Say, "Lock the doors."?
Does this Foo machine halt?
Validation and verification of mathematical models
Ex-contractor published company source code and secrets online
Why is there a need to prevent a racist, sexist, or otherwise bigoted vendor from discriminating who they sell to?
Does the United States guarantee any unique freedoms?
Where to pee in London?
Does it make sense to occupy open space?
How does The Fools Guild make its money?
In Pokémon Go, why does one of my Pikachu have an option to evolve, but another one doesn't?
Decode a variable-length quantity
Generator for parity?
Word or idiom defining something barely functional
Arrange a list in ascending order by deleting list elements
Physics of Guitar frets and sound
How to display a duet in lyrics?
Could one become a successful researcher by writing some really good papers while being outside academia?
Can I call myself an assistant professor without a PhD
How to realistically deal with a shield user?
Why are the inside diameters of some pipe larger than the stated size?
Should I take out a personal loan to pay off credit card debt?
Spring singleton beans, maps and multithreading
Should I mark object attributes as volatile if I init them in @PostConstruct in Spring Framework?How do I efficiently iterate over each entry in a Java Map?What is an efficient way to implement a singleton pattern in Java?Sort a Map<Key, Value> by valuesWhat exactly is Spring Framework for?How do servlets work? Instantiation, sessions, shared variables and multithreadingSome questions on java multithreading,What's the difference between @Component, @Repository & @Service annotations in Spring?Spring: @Component versus @BeanWhat in the world are Spring beans?How to configure port for a Spring Boot application
.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty,.everyoneloves__bot-mid-leaderboard:empty margin-bottom:0;
Sometimes I used to do things like this:
@Component class MyBean
private Map<TypeKey, Processor> processors;
@Autowired void setProcessors(List<Processor> processors)
this.processors = processors.stream().....toMap(Processor::getTypeKey, x -> x);
//some more methods reading this.processors
But, strictly speaking, it's buggy code, isn't it?
1) this.processors is not final, nor is its creation synchronized on the same monitor as every access to it. Thus, every thread - and this singleton can be called from arbitrary thread processing user request - may be observing its own value of this.processors which might be null.
2) Even though no writes happen after the Map is initially populated, Javadoc offers no guarantees on which implementation will be used for the Map, so it might be an implementation not ensuring thread safety when the Map structure changes, or even if anything is modified, or at all. And initial population is changes, so it may break thread safety for who knows how long. Collectors even offer the specialized toConcurrentMap() method, to address that problem - so, at a bare minimum, I should have been using it instead.
But even if I use toConcurrentMap() in #2, I will not be able to make my field final, because then I'll not be able to initialize it in a setter. So here are my choices:
a) Initialize and populate the Map in an autowired constructor, which frankly I prefer. But so few teams do that, so what if we abstain from that solution? What other choices exist?
b) Initialize the Map to an empty final ConcurrentHashMap, then populate it in a setter. This is possible, but we'll have to list.forEach() then map.put(). This looks like it's still Java 6; or we could definitely do map.addAll(list....toMap()) but its useless duplication of the Map, even if temporary.
c) Use volatile on the field. Slightly degrades performance without any need, because after some point the field never gets changed.
d) Use synchronized to access the field and read its values. Clearly even worse than (c).
Also, any of those methods will make the reader think that the code actually wants some multithreading reads/writes to the Map, while actually, it's just multithreaded reading.
So, what does a reasonable guru do when they want something like that?
At this point, the best solution seems to be the one with a volatile field, assigned in a setter by using toConcurrentMap. Is there anything better? Or maybe I am just making up problems no one ever actually encountered?
java spring multithreading
|
show 7 more comments
Sometimes I used to do things like this:
@Component class MyBean
private Map<TypeKey, Processor> processors;
@Autowired void setProcessors(List<Processor> processors)
this.processors = processors.stream().....toMap(Processor::getTypeKey, x -> x);
//some more methods reading this.processors
But, strictly speaking, it's buggy code, isn't it?
1) this.processors is not final, nor is its creation synchronized on the same monitor as every access to it. Thus, every thread - and this singleton can be called from arbitrary thread processing user request - may be observing its own value of this.processors which might be null.
2) Even though no writes happen after the Map is initially populated, Javadoc offers no guarantees on which implementation will be used for the Map, so it might be an implementation not ensuring thread safety when the Map structure changes, or even if anything is modified, or at all. And initial population is changes, so it may break thread safety for who knows how long. Collectors even offer the specialized toConcurrentMap() method, to address that problem - so, at a bare minimum, I should have been using it instead.
But even if I use toConcurrentMap() in #2, I will not be able to make my field final, because then I'll not be able to initialize it in a setter. So here are my choices:
a) Initialize and populate the Map in an autowired constructor, which frankly I prefer. But so few teams do that, so what if we abstain from that solution? What other choices exist?
b) Initialize the Map to an empty final ConcurrentHashMap, then populate it in a setter. This is possible, but we'll have to list.forEach() then map.put(). This looks like it's still Java 6; or we could definitely do map.addAll(list....toMap()) but its useless duplication of the Map, even if temporary.
c) Use volatile on the field. Slightly degrades performance without any need, because after some point the field never gets changed.
d) Use synchronized to access the field and read its values. Clearly even worse than (c).
Also, any of those methods will make the reader think that the code actually wants some multithreading reads/writes to the Map, while actually, it's just multithreaded reading.
So, what does a reasonable guru do when they want something like that?
At this point, the best solution seems to be the one with a volatile field, assigned in a setter by using toConcurrentMap. Is there anything better? Or maybe I am just making up problems no one ever actually encountered?
java spring multithreading
So, what does reasonable guru do when they want something like that?-- and your answer is :synchronized. After a while and if there's time, someone will probably change that to some sort of efficient locking mechanism likeStampedLockor even manual, sequential, unsynchronized population of aConcurrentHashMap- which is classical and proven ... although maybe not as "beautiful" compared to stream population. Actual software engineers dont care about beauty all the time - readability, maintainability and stability are much more important
– specializt
Mar 27 at 7:12
3
AFAIR (but I can't find any reference), Spring makes sure there is a happens-before, i.e. the injection of the beans happens before their usage. There should be nothing to worry about. And I don't know of any map (and certainly not the HashMap used by Collectors.toMap()), that would by itself decide to change its internal structure when you only read from it. That said, I would indeed favor constructor injection to setter injection.
– JB Nizet
Mar 27 at 7:14
i completely missed the fact that the question is about setter injection and a spring singleton. Well in that case : Yes, it doesnt actually matter because injection happens only once per singleton bean
– specializt
Mar 27 at 7:17
"only once" - it's irrelevant, I don't care how many times it happens, I care about whether the results of that are observed by everyone. Even if something happened eons ago, it might be not yet observed by some thread without proper happens-before. JB Nizet's answer says Spring makes sure of that - I heard that as well and I'll try to find specifics on that.
– Maksim Gumerov
Mar 27 at 7:43
" by itself decide to change its internal structure when you only read from it." - no of course not that, I was trying to explain that while it's being populated it might and will change its structure, and since it's not thread safe, no one can be sure further reading from it will work well. Thread safety does not only mean "in concurrent accesses" but more general - accesses from concurrent threads. Thus volatile.
– Maksim Gumerov
Mar 27 at 7:46
|
show 7 more comments
Sometimes I used to do things like this:
@Component class MyBean
private Map<TypeKey, Processor> processors;
@Autowired void setProcessors(List<Processor> processors)
this.processors = processors.stream().....toMap(Processor::getTypeKey, x -> x);
//some more methods reading this.processors
But, strictly speaking, it's buggy code, isn't it?
1) this.processors is not final, nor is its creation synchronized on the same monitor as every access to it. Thus, every thread - and this singleton can be called from arbitrary thread processing user request - may be observing its own value of this.processors which might be null.
2) Even though no writes happen after the Map is initially populated, Javadoc offers no guarantees on which implementation will be used for the Map, so it might be an implementation not ensuring thread safety when the Map structure changes, or even if anything is modified, or at all. And initial population is changes, so it may break thread safety for who knows how long. Collectors even offer the specialized toConcurrentMap() method, to address that problem - so, at a bare minimum, I should have been using it instead.
But even if I use toConcurrentMap() in #2, I will not be able to make my field final, because then I'll not be able to initialize it in a setter. So here are my choices:
a) Initialize and populate the Map in an autowired constructor, which frankly I prefer. But so few teams do that, so what if we abstain from that solution? What other choices exist?
b) Initialize the Map to an empty final ConcurrentHashMap, then populate it in a setter. This is possible, but we'll have to list.forEach() then map.put(). This looks like it's still Java 6; or we could definitely do map.addAll(list....toMap()) but its useless duplication of the Map, even if temporary.
c) Use volatile on the field. Slightly degrades performance without any need, because after some point the field never gets changed.
d) Use synchronized to access the field and read its values. Clearly even worse than (c).
Also, any of those methods will make the reader think that the code actually wants some multithreading reads/writes to the Map, while actually, it's just multithreaded reading.
So, what does a reasonable guru do when they want something like that?
At this point, the best solution seems to be the one with a volatile field, assigned in a setter by using toConcurrentMap. Is there anything better? Or maybe I am just making up problems no one ever actually encountered?
java spring multithreading
Sometimes I used to do things like this:
@Component class MyBean
private Map<TypeKey, Processor> processors;
@Autowired void setProcessors(List<Processor> processors)
this.processors = processors.stream().....toMap(Processor::getTypeKey, x -> x);
//some more methods reading this.processors
But, strictly speaking, it's buggy code, isn't it?
1) this.processors is not final, nor is its creation synchronized on the same monitor as every access to it. Thus, every thread - and this singleton can be called from arbitrary thread processing user request - may be observing its own value of this.processors which might be null.
2) Even though no writes happen after the Map is initially populated, Javadoc offers no guarantees on which implementation will be used for the Map, so it might be an implementation not ensuring thread safety when the Map structure changes, or even if anything is modified, or at all. And initial population is changes, so it may break thread safety for who knows how long. Collectors even offer the specialized toConcurrentMap() method, to address that problem - so, at a bare minimum, I should have been using it instead.
But even if I use toConcurrentMap() in #2, I will not be able to make my field final, because then I'll not be able to initialize it in a setter. So here are my choices:
a) Initialize and populate the Map in an autowired constructor, which frankly I prefer. But so few teams do that, so what if we abstain from that solution? What other choices exist?
b) Initialize the Map to an empty final ConcurrentHashMap, then populate it in a setter. This is possible, but we'll have to list.forEach() then map.put(). This looks like it's still Java 6; or we could definitely do map.addAll(list....toMap()) but its useless duplication of the Map, even if temporary.
c) Use volatile on the field. Slightly degrades performance without any need, because after some point the field never gets changed.
d) Use synchronized to access the field and read its values. Clearly even worse than (c).
Also, any of those methods will make the reader think that the code actually wants some multithreading reads/writes to the Map, while actually, it's just multithreaded reading.
So, what does a reasonable guru do when they want something like that?
At this point, the best solution seems to be the one with a volatile field, assigned in a setter by using toConcurrentMap. Is there anything better? Or maybe I am just making up problems no one ever actually encountered?
java spring multithreading
java spring multithreading
edited Mar 27 at 7:22
skomisa
7,8064 gold badges26 silver badges48 bronze badges
7,8064 gold badges26 silver badges48 bronze badges
asked Mar 27 at 6:57
Maksim GumerovMaksim Gumerov
3722 silver badges19 bronze badges
3722 silver badges19 bronze badges
So, what does reasonable guru do when they want something like that?-- and your answer is :synchronized. After a while and if there's time, someone will probably change that to some sort of efficient locking mechanism likeStampedLockor even manual, sequential, unsynchronized population of aConcurrentHashMap- which is classical and proven ... although maybe not as "beautiful" compared to stream population. Actual software engineers dont care about beauty all the time - readability, maintainability and stability are much more important
– specializt
Mar 27 at 7:12
3
AFAIR (but I can't find any reference), Spring makes sure there is a happens-before, i.e. the injection of the beans happens before their usage. There should be nothing to worry about. And I don't know of any map (and certainly not the HashMap used by Collectors.toMap()), that would by itself decide to change its internal structure when you only read from it. That said, I would indeed favor constructor injection to setter injection.
– JB Nizet
Mar 27 at 7:14
i completely missed the fact that the question is about setter injection and a spring singleton. Well in that case : Yes, it doesnt actually matter because injection happens only once per singleton bean
– specializt
Mar 27 at 7:17
"only once" - it's irrelevant, I don't care how many times it happens, I care about whether the results of that are observed by everyone. Even if something happened eons ago, it might be not yet observed by some thread without proper happens-before. JB Nizet's answer says Spring makes sure of that - I heard that as well and I'll try to find specifics on that.
– Maksim Gumerov
Mar 27 at 7:43
" by itself decide to change its internal structure when you only read from it." - no of course not that, I was trying to explain that while it's being populated it might and will change its structure, and since it's not thread safe, no one can be sure further reading from it will work well. Thread safety does not only mean "in concurrent accesses" but more general - accesses from concurrent threads. Thus volatile.
– Maksim Gumerov
Mar 27 at 7:46
|
show 7 more comments
So, what does reasonable guru do when they want something like that?-- and your answer is :synchronized. After a while and if there's time, someone will probably change that to some sort of efficient locking mechanism likeStampedLockor even manual, sequential, unsynchronized population of aConcurrentHashMap- which is classical and proven ... although maybe not as "beautiful" compared to stream population. Actual software engineers dont care about beauty all the time - readability, maintainability and stability are much more important
– specializt
Mar 27 at 7:12
3
AFAIR (but I can't find any reference), Spring makes sure there is a happens-before, i.e. the injection of the beans happens before their usage. There should be nothing to worry about. And I don't know of any map (and certainly not the HashMap used by Collectors.toMap()), that would by itself decide to change its internal structure when you only read from it. That said, I would indeed favor constructor injection to setter injection.
– JB Nizet
Mar 27 at 7:14
i completely missed the fact that the question is about setter injection and a spring singleton. Well in that case : Yes, it doesnt actually matter because injection happens only once per singleton bean
– specializt
Mar 27 at 7:17
"only once" - it's irrelevant, I don't care how many times it happens, I care about whether the results of that are observed by everyone. Even if something happened eons ago, it might be not yet observed by some thread without proper happens-before. JB Nizet's answer says Spring makes sure of that - I heard that as well and I'll try to find specifics on that.
– Maksim Gumerov
Mar 27 at 7:43
" by itself decide to change its internal structure when you only read from it." - no of course not that, I was trying to explain that while it's being populated it might and will change its structure, and since it's not thread safe, no one can be sure further reading from it will work well. Thread safety does not only mean "in concurrent accesses" but more general - accesses from concurrent threads. Thus volatile.
– Maksim Gumerov
Mar 27 at 7:46
So, what does reasonable guru do when they want something like that? -- and your answer is : synchronized. After a while and if there's time, someone will probably change that to some sort of efficient locking mechanism like StampedLock or even manual, sequential, unsynchronized population of a ConcurrentHashMap - which is classical and proven ... although maybe not as "beautiful" compared to stream population. Actual software engineers dont care about beauty all the time - readability, maintainability and stability are much more important– specializt
Mar 27 at 7:12
So, what does reasonable guru do when they want something like that? -- and your answer is : synchronized. After a while and if there's time, someone will probably change that to some sort of efficient locking mechanism like StampedLock or even manual, sequential, unsynchronized population of a ConcurrentHashMap - which is classical and proven ... although maybe not as "beautiful" compared to stream population. Actual software engineers dont care about beauty all the time - readability, maintainability and stability are much more important– specializt
Mar 27 at 7:12
3
3
AFAIR (but I can't find any reference), Spring makes sure there is a happens-before, i.e. the injection of the beans happens before their usage. There should be nothing to worry about. And I don't know of any map (and certainly not the HashMap used by Collectors.toMap()), that would by itself decide to change its internal structure when you only read from it. That said, I would indeed favor constructor injection to setter injection.
– JB Nizet
Mar 27 at 7:14
AFAIR (but I can't find any reference), Spring makes sure there is a happens-before, i.e. the injection of the beans happens before their usage. There should be nothing to worry about. And I don't know of any map (and certainly not the HashMap used by Collectors.toMap()), that would by itself decide to change its internal structure when you only read from it. That said, I would indeed favor constructor injection to setter injection.
– JB Nizet
Mar 27 at 7:14
i completely missed the fact that the question is about setter injection and a spring singleton. Well in that case : Yes, it doesnt actually matter because injection happens only once per singleton bean
– specializt
Mar 27 at 7:17
i completely missed the fact that the question is about setter injection and a spring singleton. Well in that case : Yes, it doesnt actually matter because injection happens only once per singleton bean
– specializt
Mar 27 at 7:17
"only once" - it's irrelevant, I don't care how many times it happens, I care about whether the results of that are observed by everyone. Even if something happened eons ago, it might be not yet observed by some thread without proper happens-before. JB Nizet's answer says Spring makes sure of that - I heard that as well and I'll try to find specifics on that.
– Maksim Gumerov
Mar 27 at 7:43
"only once" - it's irrelevant, I don't care how many times it happens, I care about whether the results of that are observed by everyone. Even if something happened eons ago, it might be not yet observed by some thread without proper happens-before. JB Nizet's answer says Spring makes sure of that - I heard that as well and I'll try to find specifics on that.
– Maksim Gumerov
Mar 27 at 7:43
" by itself decide to change its internal structure when you only read from it." - no of course not that, I was trying to explain that while it's being populated it might and will change its structure, and since it's not thread safe, no one can be sure further reading from it will work well. Thread safety does not only mean "in concurrent accesses" but more general - accesses from concurrent threads. Thus volatile.
– Maksim Gumerov
Mar 27 at 7:46
" by itself decide to change its internal structure when you only read from it." - no of course not that, I was trying to explain that while it's being populated it might and will change its structure, and since it's not thread safe, no one can be sure further reading from it will work well. Thread safety does not only mean "in concurrent accesses" but more general - accesses from concurrent threads. Thus volatile.
– Maksim Gumerov
Mar 27 at 7:46
|
show 7 more comments
2 Answers
2
active
oldest
votes
Or maybe I am just making up problems no one ever actually encountered?
I think may be conflating your assignment with the problems historically seen from double-checked locking:
private Foo foo; // this is an instance variable
public Foo getFoo()
if (foo != null)
synchronized (this)
if (foo != null)
foo = new Foo();
return foo;
This code appears to be thread-safe: you do an initial, presumed quick, check to verify that the value has not been initialized yet, and if it hasn't you initialize in a synchronized block. The problem is that the new operation is distinct from the constructor call, and some implementations were assigning the reference returned by new to the variable before the constructor ran. The result was that another thread could see that value before the constructor completed.
In your case, however, you are assigning the variable based on the result of a function call. The Map created by the function call is not assigned to the variable until the function returns. The compiler (including Hotspot) is not permitted to re-order this operation because such a change would be visible to the thread that's executing the function, and would not therefore be sequentially consistent per JLS 17.4.3.
That out of the way, here are some additional comments:
Initialize and populate the Map in an autowired constructor, which frankly I prefer
As do the creators of the Guice dependency injection framework. One reason to prefer constructor injection is that you know that you'll never see the bean in an inconsistent state.
The reason that Spring encourages (or at least does not discourage) setter injection is because it makes circular references possible. You can decide for yourself whether circular references are a good idea.
Initialize the Map to an empty final ConcurrentHashMap, then populate it in a setter
This is a bad idea because it's likely that other threads will see a partially constructed map. It's far better to see either null or a fully-constructed map, because you can compensate for the first case.
Use volatile on the field. Slightly degrades performance without any need
Use synchronized to access the field and read its values. Clearly even worse than (c).
Don't let perceived performance impacts keep you from writing correct code. The only time that synchronization will significantly impact your performance is when concurrent threads access a synchronized variable/method within a tight loop. If you're not in a loop, then the memory barrier adds an irrelevant amount of time to your call (and even in a loop it's minimal unless you need to wait for a value to arrive in your core's cache).
In this case it doesn't matter, but I would guess that getProcessors() takes a tiny percentage of your total execution time, and that a far larger amount of time is taken by running the processor(s).
"Don't let perceived performance impacts keep you from writing correct code." - sure, I just would like to avoid that it there is a cleaner solution (or if for some reason there is no problem). And thanks for interesting insights regarding new+assignment. But I don't see actual answer: what do you propose me to do? "In your case, however" implies that you don't think there is a problem.
– Maksim Gumerov
Mar 29 at 3:47
Also, the code you cited at least contains synchronization. The initial code I shown does not. So, it's probably still buggy like I said. So, there is a problem and it needs a solution. What is the one you actually say is an answer?
– Maksim Gumerov
Mar 29 at 3:51
just use toConcurrentMap and get it over with. It is impossible for the map to be in an inconsistent state after that - you're trying to solve problems which do not exist and your time surely can be invested in a better way ... by reading up on spring CDI and@Required, for instance
– specializt
Mar 29 at 7:45
@MaksimGumerov - the example code I wrote is a case where multi-thread visibility is a problem. I wrote it to compare to the code that you wrote, in which multi-thread visibility is not a problem, due to the explanation and JLS reference that I gave you.
– guest
Mar 29 at 13:48
Sure thing, toConcurrentMap solves the map consistency problem. Where did I say it may become inconsistent after that? toConcurrentMap by definition creates a thread-safe map :) You are not adding anything to my initial question with 4 options. But yes, I promised to read up on how Spring guarantees happens-before on injections. Didn't do that yet.
– Maksim Gumerov
Apr 1 at 17:16
|
show 5 more comments
Thanks to hints of commenters here, after googling a bit I was able to find not a reference to Spring manual but at least a matter-of-fact guarantee, see Should I mark object attributes as volatile if I init them in @PostConstruct in Spring Framework? - the updated part of accepted answer. In essence it says that every lookup of a particular bean in a context, and hence, roughly, every injection of that bean, is preceded by locking on some monitor, and bean initialization also happens while locked on that same monitor, establishing happens-before relationship between bean initialization and bean injection. More specifially, everything done during bean initialization (like, assignment of processors in MyBean initialization) happens-before subsequent injections of that bean - and the bean is only used after it has been injected. So the author says no volatile is necessary, unless we are going to change the field after that.
That would be my accepted answer (in combination with toConcurrentMap) if not for 2 "buts".
1) This does not mean injection of non-initialized beans offers that same happens-before. And injection of non-initialized beans happens more often that some think. In case of circular dependencied, which are better kept rare but look valid sometimes. In case of lazy initialized beans. Some libraries (AFAIK even some of Spring projects) introduce circular dependencies, I saw that myself. And sometimes you introduce circular deps by accident, that is not treated as error by default. Of course, reasonable code does not use non-initialized beans, but since MyBean could be injected to some bean X before it's initialized, there will be no happens-before after it's initalized, annihilating our guarantees.
2) This is not even a documented feature. Still! But recently it has at least been put on a backlog. See https://github.com/spring-projects/spring-framework/issues/8986 - still, until they documented it we cannot assume it's not subject to changes. Bah, even when they do, it still may be changed in some next version, but at least that will be reflected in some changelist or whatnot.
So, taking those 2 notes into consideration, especially the 1st, I am inclined to say that volatile+toConcurrentMap is the way to go. Right?
add a comment |
Your Answer
StackExchange.ifUsing("editor", function ()
StackExchange.using("externalEditor", function ()
StackExchange.using("snippets", function ()
StackExchange.snippets.init();
);
);
, "code-snippets");
StackExchange.ready(function()
var channelOptions =
tags: "".split(" "),
id: "1"
;
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function()
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled)
StackExchange.using("snippets", function()
createEditor();
);
else
createEditor();
);
function createEditor()
StackExchange.prepareEditor(
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader:
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
,
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
);
);
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f55371418%2fspring-singleton-beans-maps-and-multithreading%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
2 Answers
2
active
oldest
votes
2 Answers
2
active
oldest
votes
active
oldest
votes
active
oldest
votes
Or maybe I am just making up problems no one ever actually encountered?
I think may be conflating your assignment with the problems historically seen from double-checked locking:
private Foo foo; // this is an instance variable
public Foo getFoo()
if (foo != null)
synchronized (this)
if (foo != null)
foo = new Foo();
return foo;
This code appears to be thread-safe: you do an initial, presumed quick, check to verify that the value has not been initialized yet, and if it hasn't you initialize in a synchronized block. The problem is that the new operation is distinct from the constructor call, and some implementations were assigning the reference returned by new to the variable before the constructor ran. The result was that another thread could see that value before the constructor completed.
In your case, however, you are assigning the variable based on the result of a function call. The Map created by the function call is not assigned to the variable until the function returns. The compiler (including Hotspot) is not permitted to re-order this operation because such a change would be visible to the thread that's executing the function, and would not therefore be sequentially consistent per JLS 17.4.3.
That out of the way, here are some additional comments:
Initialize and populate the Map in an autowired constructor, which frankly I prefer
As do the creators of the Guice dependency injection framework. One reason to prefer constructor injection is that you know that you'll never see the bean in an inconsistent state.
The reason that Spring encourages (or at least does not discourage) setter injection is because it makes circular references possible. You can decide for yourself whether circular references are a good idea.
Initialize the Map to an empty final ConcurrentHashMap, then populate it in a setter
This is a bad idea because it's likely that other threads will see a partially constructed map. It's far better to see either null or a fully-constructed map, because you can compensate for the first case.
Use volatile on the field. Slightly degrades performance without any need
Use synchronized to access the field and read its values. Clearly even worse than (c).
Don't let perceived performance impacts keep you from writing correct code. The only time that synchronization will significantly impact your performance is when concurrent threads access a synchronized variable/method within a tight loop. If you're not in a loop, then the memory barrier adds an irrelevant amount of time to your call (and even in a loop it's minimal unless you need to wait for a value to arrive in your core's cache).
In this case it doesn't matter, but I would guess that getProcessors() takes a tiny percentage of your total execution time, and that a far larger amount of time is taken by running the processor(s).
"Don't let perceived performance impacts keep you from writing correct code." - sure, I just would like to avoid that it there is a cleaner solution (or if for some reason there is no problem). And thanks for interesting insights regarding new+assignment. But I don't see actual answer: what do you propose me to do? "In your case, however" implies that you don't think there is a problem.
– Maksim Gumerov
Mar 29 at 3:47
Also, the code you cited at least contains synchronization. The initial code I shown does not. So, it's probably still buggy like I said. So, there is a problem and it needs a solution. What is the one you actually say is an answer?
– Maksim Gumerov
Mar 29 at 3:51
just use toConcurrentMap and get it over with. It is impossible for the map to be in an inconsistent state after that - you're trying to solve problems which do not exist and your time surely can be invested in a better way ... by reading up on spring CDI and@Required, for instance
– specializt
Mar 29 at 7:45
@MaksimGumerov - the example code I wrote is a case where multi-thread visibility is a problem. I wrote it to compare to the code that you wrote, in which multi-thread visibility is not a problem, due to the explanation and JLS reference that I gave you.
– guest
Mar 29 at 13:48
Sure thing, toConcurrentMap solves the map consistency problem. Where did I say it may become inconsistent after that? toConcurrentMap by definition creates a thread-safe map :) You are not adding anything to my initial question with 4 options. But yes, I promised to read up on how Spring guarantees happens-before on injections. Didn't do that yet.
– Maksim Gumerov
Apr 1 at 17:16
|
show 5 more comments
Or maybe I am just making up problems no one ever actually encountered?
I think may be conflating your assignment with the problems historically seen from double-checked locking:
private Foo foo; // this is an instance variable
public Foo getFoo()
if (foo != null)
synchronized (this)
if (foo != null)
foo = new Foo();
return foo;
This code appears to be thread-safe: you do an initial, presumed quick, check to verify that the value has not been initialized yet, and if it hasn't you initialize in a synchronized block. The problem is that the new operation is distinct from the constructor call, and some implementations were assigning the reference returned by new to the variable before the constructor ran. The result was that another thread could see that value before the constructor completed.
In your case, however, you are assigning the variable based on the result of a function call. The Map created by the function call is not assigned to the variable until the function returns. The compiler (including Hotspot) is not permitted to re-order this operation because such a change would be visible to the thread that's executing the function, and would not therefore be sequentially consistent per JLS 17.4.3.
That out of the way, here are some additional comments:
Initialize and populate the Map in an autowired constructor, which frankly I prefer
As do the creators of the Guice dependency injection framework. One reason to prefer constructor injection is that you know that you'll never see the bean in an inconsistent state.
The reason that Spring encourages (or at least does not discourage) setter injection is because it makes circular references possible. You can decide for yourself whether circular references are a good idea.
Initialize the Map to an empty final ConcurrentHashMap, then populate it in a setter
This is a bad idea because it's likely that other threads will see a partially constructed map. It's far better to see either null or a fully-constructed map, because you can compensate for the first case.
Use volatile on the field. Slightly degrades performance without any need
Use synchronized to access the field and read its values. Clearly even worse than (c).
Don't let perceived performance impacts keep you from writing correct code. The only time that synchronization will significantly impact your performance is when concurrent threads access a synchronized variable/method within a tight loop. If you're not in a loop, then the memory barrier adds an irrelevant amount of time to your call (and even in a loop it's minimal unless you need to wait for a value to arrive in your core's cache).
In this case it doesn't matter, but I would guess that getProcessors() takes a tiny percentage of your total execution time, and that a far larger amount of time is taken by running the processor(s).
"Don't let perceived performance impacts keep you from writing correct code." - sure, I just would like to avoid that it there is a cleaner solution (or if for some reason there is no problem). And thanks for interesting insights regarding new+assignment. But I don't see actual answer: what do you propose me to do? "In your case, however" implies that you don't think there is a problem.
– Maksim Gumerov
Mar 29 at 3:47
Also, the code you cited at least contains synchronization. The initial code I shown does not. So, it's probably still buggy like I said. So, there is a problem and it needs a solution. What is the one you actually say is an answer?
– Maksim Gumerov
Mar 29 at 3:51
just use toConcurrentMap and get it over with. It is impossible for the map to be in an inconsistent state after that - you're trying to solve problems which do not exist and your time surely can be invested in a better way ... by reading up on spring CDI and@Required, for instance
– specializt
Mar 29 at 7:45
@MaksimGumerov - the example code I wrote is a case where multi-thread visibility is a problem. I wrote it to compare to the code that you wrote, in which multi-thread visibility is not a problem, due to the explanation and JLS reference that I gave you.
– guest
Mar 29 at 13:48
Sure thing, toConcurrentMap solves the map consistency problem. Where did I say it may become inconsistent after that? toConcurrentMap by definition creates a thread-safe map :) You are not adding anything to my initial question with 4 options. But yes, I promised to read up on how Spring guarantees happens-before on injections. Didn't do that yet.
– Maksim Gumerov
Apr 1 at 17:16
|
show 5 more comments
Or maybe I am just making up problems no one ever actually encountered?
I think may be conflating your assignment with the problems historically seen from double-checked locking:
private Foo foo; // this is an instance variable
public Foo getFoo()
if (foo != null)
synchronized (this)
if (foo != null)
foo = new Foo();
return foo;
This code appears to be thread-safe: you do an initial, presumed quick, check to verify that the value has not been initialized yet, and if it hasn't you initialize in a synchronized block. The problem is that the new operation is distinct from the constructor call, and some implementations were assigning the reference returned by new to the variable before the constructor ran. The result was that another thread could see that value before the constructor completed.
In your case, however, you are assigning the variable based on the result of a function call. The Map created by the function call is not assigned to the variable until the function returns. The compiler (including Hotspot) is not permitted to re-order this operation because such a change would be visible to the thread that's executing the function, and would not therefore be sequentially consistent per JLS 17.4.3.
That out of the way, here are some additional comments:
Initialize and populate the Map in an autowired constructor, which frankly I prefer
As do the creators of the Guice dependency injection framework. One reason to prefer constructor injection is that you know that you'll never see the bean in an inconsistent state.
The reason that Spring encourages (or at least does not discourage) setter injection is because it makes circular references possible. You can decide for yourself whether circular references are a good idea.
Initialize the Map to an empty final ConcurrentHashMap, then populate it in a setter
This is a bad idea because it's likely that other threads will see a partially constructed map. It's far better to see either null or a fully-constructed map, because you can compensate for the first case.
Use volatile on the field. Slightly degrades performance without any need
Use synchronized to access the field and read its values. Clearly even worse than (c).
Don't let perceived performance impacts keep you from writing correct code. The only time that synchronization will significantly impact your performance is when concurrent threads access a synchronized variable/method within a tight loop. If you're not in a loop, then the memory barrier adds an irrelevant amount of time to your call (and even in a loop it's minimal unless you need to wait for a value to arrive in your core's cache).
In this case it doesn't matter, but I would guess that getProcessors() takes a tiny percentage of your total execution time, and that a far larger amount of time is taken by running the processor(s).
Or maybe I am just making up problems no one ever actually encountered?
I think may be conflating your assignment with the problems historically seen from double-checked locking:
private Foo foo; // this is an instance variable
public Foo getFoo()
if (foo != null)
synchronized (this)
if (foo != null)
foo = new Foo();
return foo;
This code appears to be thread-safe: you do an initial, presumed quick, check to verify that the value has not been initialized yet, and if it hasn't you initialize in a synchronized block. The problem is that the new operation is distinct from the constructor call, and some implementations were assigning the reference returned by new to the variable before the constructor ran. The result was that another thread could see that value before the constructor completed.
In your case, however, you are assigning the variable based on the result of a function call. The Map created by the function call is not assigned to the variable until the function returns. The compiler (including Hotspot) is not permitted to re-order this operation because such a change would be visible to the thread that's executing the function, and would not therefore be sequentially consistent per JLS 17.4.3.
That out of the way, here are some additional comments:
Initialize and populate the Map in an autowired constructor, which frankly I prefer
As do the creators of the Guice dependency injection framework. One reason to prefer constructor injection is that you know that you'll never see the bean in an inconsistent state.
The reason that Spring encourages (or at least does not discourage) setter injection is because it makes circular references possible. You can decide for yourself whether circular references are a good idea.
Initialize the Map to an empty final ConcurrentHashMap, then populate it in a setter
This is a bad idea because it's likely that other threads will see a partially constructed map. It's far better to see either null or a fully-constructed map, because you can compensate for the first case.
Use volatile on the field. Slightly degrades performance without any need
Use synchronized to access the field and read its values. Clearly even worse than (c).
Don't let perceived performance impacts keep you from writing correct code. The only time that synchronization will significantly impact your performance is when concurrent threads access a synchronized variable/method within a tight loop. If you're not in a loop, then the memory barrier adds an irrelevant amount of time to your call (and even in a loop it's minimal unless you need to wait for a value to arrive in your core's cache).
In this case it doesn't matter, but I would guess that getProcessors() takes a tiny percentage of your total execution time, and that a far larger amount of time is taken by running the processor(s).
answered Mar 28 at 14:55
guestguest
3513 bronze badges
3513 bronze badges
"Don't let perceived performance impacts keep you from writing correct code." - sure, I just would like to avoid that it there is a cleaner solution (or if for some reason there is no problem). And thanks for interesting insights regarding new+assignment. But I don't see actual answer: what do you propose me to do? "In your case, however" implies that you don't think there is a problem.
– Maksim Gumerov
Mar 29 at 3:47
Also, the code you cited at least contains synchronization. The initial code I shown does not. So, it's probably still buggy like I said. So, there is a problem and it needs a solution. What is the one you actually say is an answer?
– Maksim Gumerov
Mar 29 at 3:51
just use toConcurrentMap and get it over with. It is impossible for the map to be in an inconsistent state after that - you're trying to solve problems which do not exist and your time surely can be invested in a better way ... by reading up on spring CDI and@Required, for instance
– specializt
Mar 29 at 7:45
@MaksimGumerov - the example code I wrote is a case where multi-thread visibility is a problem. I wrote it to compare to the code that you wrote, in which multi-thread visibility is not a problem, due to the explanation and JLS reference that I gave you.
– guest
Mar 29 at 13:48
Sure thing, toConcurrentMap solves the map consistency problem. Where did I say it may become inconsistent after that? toConcurrentMap by definition creates a thread-safe map :) You are not adding anything to my initial question with 4 options. But yes, I promised to read up on how Spring guarantees happens-before on injections. Didn't do that yet.
– Maksim Gumerov
Apr 1 at 17:16
|
show 5 more comments
"Don't let perceived performance impacts keep you from writing correct code." - sure, I just would like to avoid that it there is a cleaner solution (or if for some reason there is no problem). And thanks for interesting insights regarding new+assignment. But I don't see actual answer: what do you propose me to do? "In your case, however" implies that you don't think there is a problem.
– Maksim Gumerov
Mar 29 at 3:47
Also, the code you cited at least contains synchronization. The initial code I shown does not. So, it's probably still buggy like I said. So, there is a problem and it needs a solution. What is the one you actually say is an answer?
– Maksim Gumerov
Mar 29 at 3:51
just use toConcurrentMap and get it over with. It is impossible for the map to be in an inconsistent state after that - you're trying to solve problems which do not exist and your time surely can be invested in a better way ... by reading up on spring CDI and@Required, for instance
– specializt
Mar 29 at 7:45
@MaksimGumerov - the example code I wrote is a case where multi-thread visibility is a problem. I wrote it to compare to the code that you wrote, in which multi-thread visibility is not a problem, due to the explanation and JLS reference that I gave you.
– guest
Mar 29 at 13:48
Sure thing, toConcurrentMap solves the map consistency problem. Where did I say it may become inconsistent after that? toConcurrentMap by definition creates a thread-safe map :) You are not adding anything to my initial question with 4 options. But yes, I promised to read up on how Spring guarantees happens-before on injections. Didn't do that yet.
– Maksim Gumerov
Apr 1 at 17:16
"Don't let perceived performance impacts keep you from writing correct code." - sure, I just would like to avoid that it there is a cleaner solution (or if for some reason there is no problem). And thanks for interesting insights regarding new+assignment. But I don't see actual answer: what do you propose me to do? "In your case, however" implies that you don't think there is a problem.
– Maksim Gumerov
Mar 29 at 3:47
"Don't let perceived performance impacts keep you from writing correct code." - sure, I just would like to avoid that it there is a cleaner solution (or if for some reason there is no problem). And thanks for interesting insights regarding new+assignment. But I don't see actual answer: what do you propose me to do? "In your case, however" implies that you don't think there is a problem.
– Maksim Gumerov
Mar 29 at 3:47
Also, the code you cited at least contains synchronization. The initial code I shown does not. So, it's probably still buggy like I said. So, there is a problem and it needs a solution. What is the one you actually say is an answer?
– Maksim Gumerov
Mar 29 at 3:51
Also, the code you cited at least contains synchronization. The initial code I shown does not. So, it's probably still buggy like I said. So, there is a problem and it needs a solution. What is the one you actually say is an answer?
– Maksim Gumerov
Mar 29 at 3:51
just use toConcurrentMap and get it over with. It is impossible for the map to be in an inconsistent state after that - you're trying to solve problems which do not exist and your time surely can be invested in a better way ... by reading up on spring CDI and
@Required, for instance– specializt
Mar 29 at 7:45
just use toConcurrentMap and get it over with. It is impossible for the map to be in an inconsistent state after that - you're trying to solve problems which do not exist and your time surely can be invested in a better way ... by reading up on spring CDI and
@Required, for instance– specializt
Mar 29 at 7:45
@MaksimGumerov - the example code I wrote is a case where multi-thread visibility is a problem. I wrote it to compare to the code that you wrote, in which multi-thread visibility is not a problem, due to the explanation and JLS reference that I gave you.
– guest
Mar 29 at 13:48
@MaksimGumerov - the example code I wrote is a case where multi-thread visibility is a problem. I wrote it to compare to the code that you wrote, in which multi-thread visibility is not a problem, due to the explanation and JLS reference that I gave you.
– guest
Mar 29 at 13:48
Sure thing, toConcurrentMap solves the map consistency problem. Where did I say it may become inconsistent after that? toConcurrentMap by definition creates a thread-safe map :) You are not adding anything to my initial question with 4 options. But yes, I promised to read up on how Spring guarantees happens-before on injections. Didn't do that yet.
– Maksim Gumerov
Apr 1 at 17:16
Sure thing, toConcurrentMap solves the map consistency problem. Where did I say it may become inconsistent after that? toConcurrentMap by definition creates a thread-safe map :) You are not adding anything to my initial question with 4 options. But yes, I promised to read up on how Spring guarantees happens-before on injections. Didn't do that yet.
– Maksim Gumerov
Apr 1 at 17:16
|
show 5 more comments
Thanks to hints of commenters here, after googling a bit I was able to find not a reference to Spring manual but at least a matter-of-fact guarantee, see Should I mark object attributes as volatile if I init them in @PostConstruct in Spring Framework? - the updated part of accepted answer. In essence it says that every lookup of a particular bean in a context, and hence, roughly, every injection of that bean, is preceded by locking on some monitor, and bean initialization also happens while locked on that same monitor, establishing happens-before relationship between bean initialization and bean injection. More specifially, everything done during bean initialization (like, assignment of processors in MyBean initialization) happens-before subsequent injections of that bean - and the bean is only used after it has been injected. So the author says no volatile is necessary, unless we are going to change the field after that.
That would be my accepted answer (in combination with toConcurrentMap) if not for 2 "buts".
1) This does not mean injection of non-initialized beans offers that same happens-before. And injection of non-initialized beans happens more often that some think. In case of circular dependencied, which are better kept rare but look valid sometimes. In case of lazy initialized beans. Some libraries (AFAIK even some of Spring projects) introduce circular dependencies, I saw that myself. And sometimes you introduce circular deps by accident, that is not treated as error by default. Of course, reasonable code does not use non-initialized beans, but since MyBean could be injected to some bean X before it's initialized, there will be no happens-before after it's initalized, annihilating our guarantees.
2) This is not even a documented feature. Still! But recently it has at least been put on a backlog. See https://github.com/spring-projects/spring-framework/issues/8986 - still, until they documented it we cannot assume it's not subject to changes. Bah, even when they do, it still may be changed in some next version, but at least that will be reflected in some changelist or whatnot.
So, taking those 2 notes into consideration, especially the 1st, I am inclined to say that volatile+toConcurrentMap is the way to go. Right?
add a comment |
Thanks to hints of commenters here, after googling a bit I was able to find not a reference to Spring manual but at least a matter-of-fact guarantee, see Should I mark object attributes as volatile if I init them in @PostConstruct in Spring Framework? - the updated part of accepted answer. In essence it says that every lookup of a particular bean in a context, and hence, roughly, every injection of that bean, is preceded by locking on some monitor, and bean initialization also happens while locked on that same monitor, establishing happens-before relationship between bean initialization and bean injection. More specifially, everything done during bean initialization (like, assignment of processors in MyBean initialization) happens-before subsequent injections of that bean - and the bean is only used after it has been injected. So the author says no volatile is necessary, unless we are going to change the field after that.
That would be my accepted answer (in combination with toConcurrentMap) if not for 2 "buts".
1) This does not mean injection of non-initialized beans offers that same happens-before. And injection of non-initialized beans happens more often that some think. In case of circular dependencied, which are better kept rare but look valid sometimes. In case of lazy initialized beans. Some libraries (AFAIK even some of Spring projects) introduce circular dependencies, I saw that myself. And sometimes you introduce circular deps by accident, that is not treated as error by default. Of course, reasonable code does not use non-initialized beans, but since MyBean could be injected to some bean X before it's initialized, there will be no happens-before after it's initalized, annihilating our guarantees.
2) This is not even a documented feature. Still! But recently it has at least been put on a backlog. See https://github.com/spring-projects/spring-framework/issues/8986 - still, until they documented it we cannot assume it's not subject to changes. Bah, even when they do, it still may be changed in some next version, but at least that will be reflected in some changelist or whatnot.
So, taking those 2 notes into consideration, especially the 1st, I am inclined to say that volatile+toConcurrentMap is the way to go. Right?
add a comment |
Thanks to hints of commenters here, after googling a bit I was able to find not a reference to Spring manual but at least a matter-of-fact guarantee, see Should I mark object attributes as volatile if I init them in @PostConstruct in Spring Framework? - the updated part of accepted answer. In essence it says that every lookup of a particular bean in a context, and hence, roughly, every injection of that bean, is preceded by locking on some monitor, and bean initialization also happens while locked on that same monitor, establishing happens-before relationship between bean initialization and bean injection. More specifially, everything done during bean initialization (like, assignment of processors in MyBean initialization) happens-before subsequent injections of that bean - and the bean is only used after it has been injected. So the author says no volatile is necessary, unless we are going to change the field after that.
That would be my accepted answer (in combination with toConcurrentMap) if not for 2 "buts".
1) This does not mean injection of non-initialized beans offers that same happens-before. And injection of non-initialized beans happens more often that some think. In case of circular dependencied, which are better kept rare but look valid sometimes. In case of lazy initialized beans. Some libraries (AFAIK even some of Spring projects) introduce circular dependencies, I saw that myself. And sometimes you introduce circular deps by accident, that is not treated as error by default. Of course, reasonable code does not use non-initialized beans, but since MyBean could be injected to some bean X before it's initialized, there will be no happens-before after it's initalized, annihilating our guarantees.
2) This is not even a documented feature. Still! But recently it has at least been put on a backlog. See https://github.com/spring-projects/spring-framework/issues/8986 - still, until they documented it we cannot assume it's not subject to changes. Bah, even when they do, it still may be changed in some next version, but at least that will be reflected in some changelist or whatnot.
So, taking those 2 notes into consideration, especially the 1st, I am inclined to say that volatile+toConcurrentMap is the way to go. Right?
Thanks to hints of commenters here, after googling a bit I was able to find not a reference to Spring manual but at least a matter-of-fact guarantee, see Should I mark object attributes as volatile if I init them in @PostConstruct in Spring Framework? - the updated part of accepted answer. In essence it says that every lookup of a particular bean in a context, and hence, roughly, every injection of that bean, is preceded by locking on some monitor, and bean initialization also happens while locked on that same monitor, establishing happens-before relationship between bean initialization and bean injection. More specifially, everything done during bean initialization (like, assignment of processors in MyBean initialization) happens-before subsequent injections of that bean - and the bean is only used after it has been injected. So the author says no volatile is necessary, unless we are going to change the field after that.
That would be my accepted answer (in combination with toConcurrentMap) if not for 2 "buts".
1) This does not mean injection of non-initialized beans offers that same happens-before. And injection of non-initialized beans happens more often that some think. In case of circular dependencied, which are better kept rare but look valid sometimes. In case of lazy initialized beans. Some libraries (AFAIK even some of Spring projects) introduce circular dependencies, I saw that myself. And sometimes you introduce circular deps by accident, that is not treated as error by default. Of course, reasonable code does not use non-initialized beans, but since MyBean could be injected to some bean X before it's initialized, there will be no happens-before after it's initalized, annihilating our guarantees.
2) This is not even a documented feature. Still! But recently it has at least been put on a backlog. See https://github.com/spring-projects/spring-framework/issues/8986 - still, until they documented it we cannot assume it's not subject to changes. Bah, even when they do, it still may be changed in some next version, but at least that will be reflected in some changelist or whatnot.
So, taking those 2 notes into consideration, especially the 1st, I am inclined to say that volatile+toConcurrentMap is the way to go. Right?
answered Apr 1 at 17:52
Maksim GumerovMaksim Gumerov
3722 silver badges19 bronze badges
3722 silver badges19 bronze badges
add a comment |
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f55371418%2fspring-singleton-beans-maps-and-multithreading%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
So, what does reasonable guru do when they want something like that?-- and your answer is :synchronized. After a while and if there's time, someone will probably change that to some sort of efficient locking mechanism likeStampedLockor even manual, sequential, unsynchronized population of aConcurrentHashMap- which is classical and proven ... although maybe not as "beautiful" compared to stream population. Actual software engineers dont care about beauty all the time - readability, maintainability and stability are much more important– specializt
Mar 27 at 7:12
3
AFAIR (but I can't find any reference), Spring makes sure there is a happens-before, i.e. the injection of the beans happens before their usage. There should be nothing to worry about. And I don't know of any map (and certainly not the HashMap used by Collectors.toMap()), that would by itself decide to change its internal structure when you only read from it. That said, I would indeed favor constructor injection to setter injection.
– JB Nizet
Mar 27 at 7:14
i completely missed the fact that the question is about setter injection and a spring singleton. Well in that case : Yes, it doesnt actually matter because injection happens only once per singleton bean
– specializt
Mar 27 at 7:17
"only once" - it's irrelevant, I don't care how many times it happens, I care about whether the results of that are observed by everyone. Even if something happened eons ago, it might be not yet observed by some thread without proper happens-before. JB Nizet's answer says Spring makes sure of that - I heard that as well and I'll try to find specifics on that.
– Maksim Gumerov
Mar 27 at 7:43
" by itself decide to change its internal structure when you only read from it." - no of course not that, I was trying to explain that while it's being populated it might and will change its structure, and since it's not thread safe, no one can be sure further reading from it will work well. Thread safety does not only mean "in concurrent accesses" but more general - accesses from concurrent threads. Thus volatile.
– Maksim Gumerov
Mar 27 at 7:46