I will try to explain the quetion by taking following 3 cases. CASE I: I was using shared lock for synchronization using something like this:
private static final String SHARED_LOCK = "shared_lock";
private static int i = 0;
private static int j = 0;
void increment() {
synchronized (SHARED_LOCK) {
i++;
j++;
}
}
And it is working fine.
CASE II: Now What I have changed here is instead of using shared lock I thought of using a local lock by doing something like this:
开发者_开发技巧 private static int i = 0;
private static int j = 0;
void increment() {
final String LOCAL_LOCK = "local_lock";
synchronized (LOCAL_LOCK) {
i++;
j++;
}
}
And I found that code was still working fine that is synchronization was still working.
CASE III: However when I changed the local locl to this:
final String LOCAL_LOCK = new String("local_lock");
then the synchronization went away. So it looks like that in CASE II the local lock was able to provide synchronization because of interning of String literals that Java does for us automatically but in CASE III as I was explicitly creating a new String everytime thus synchronization was not happening.
So coming back to my original question. Does anyone feels that CASE II is not the right way to achieve synchronization? If yes could you please also mention why?
Thanks in advance, SacTiw.
Locks are meant to provide synchronization between code running in separate threads. If you use local locks, each thread will have its own copy of the lock object (in the thread's stack) on which it will lock and hence there will be no synchronization.
It works in your case only because of String interning. If you used final Object LOCAL_LOCK = new Object();
it will not work.
So locks should be always shared between threads.
Synchronization only works correct if you synchronize on the same object between threads;
- The 1st case is obvious,
- In the second case the Java compiler interns the string constant which is why it works too (you get the same object from the string pool between calls),
- The 3rd case you force a new string object and therefore you are getting your own private lock per thread giving no synchronization at all.
What's very very important here is that using 'canonicalizable' objects -- like, say, String
s, which can be interned, or Integer
constants which may be shared -- is basically opening you up to using the same lock object as another class.
This is, as you'd imagine, a very bad idea. By using the same lock as another class, you can basically guarantee yourself a whole world of painful debugging later as you try and work out why your app deadlocks.
If you need a private lock in a class, make sure it is a completely unique object by obtaining it only via the new
operator.
(I believe one of the Java Puzzlers presentations might have covered this; some other example references are here and here)
Its because of string interning. All Strings created as in case 2 with equal values will 'share' the same instance. Strings created as in case 3 will be distinct instances.
It is this difference that accounts for the different synchronisation behaviour you're seeing.
精彩评论