• Post Reply Bookmark Topic Watch Topic
  • New Topic
programming forums Java Mobile Certification Databases Caching Books Engineering Micro Controllers OS Languages Paradigms IDEs Build Tools Frameworks Application Servers Open Source This Site Careers Other Pie Elite all forums
this forum made possible by our volunteer staff, including ...
Marshals:
  • Campbell Ritchie
  • Jeanne Boyarsky
  • Ron McLeod
  • Paul Clapham
  • Liutauras Vilda
Sheriffs:
  • paul wheaton
  • Rob Spoor
  • Devaka Cooray
Saloon Keepers:
  • Stephan van Hulst
  • Tim Holloway
  • Carey Brown
  • Frits Walraven
  • Tim Moores
Bartenders:
  • Mikalai Zaikin

Synchronizing a block of code

 
Greenhorn
Posts: 13
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Attached is the code for Exercise 9-2 in Sierra and Bates' book. I do not understand why we have to use "letter" in synchronized(letter). I do not know why "this" would not work in this example. Further, on page 523 of the book, they mentioned to use some third-party object as the lock. I am totally confused. Thank you for your help.
// Sierra book - Ex 9-2

Edited by Corey McGlone: Added CODE tags
[ February 24, 2004: Message edited by: Corey McGlone ]
 
Ranch Hand
Posts: 3271
  • Likes 1
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Kathy,
The first things that you should realize is that every object has a "lock." That means that you can lock on any object you create, whether that object be a StringBuffer, a Thread, a String, an ArrayList, or whatever. It's also essential to remember that every object has ONLY 1 lock.
Now, let's get back to the problem at hand, shall we?
In this case, we create one instance of a StringBuffer object, referenced originally by the variable sb. We then create 3 InSync objects and pass to each one a reference to the StringBuffer object.
Now, as each InSync method invokes its run method, it runs into the synchronized block. At this point, the thread is going to "request" the lock on whatever object you specify. If that lock is available, the thread acquires it and goes on through the block. If that lock is not available, the thread has to stop and wait until it is available.
So, what happens is we were to lock on "this" rather than on letter.
Well, the first InSync object enters its run method and requests its own lock (this referes to the object, itself). Of course, no other thread is using it, so it acquires the lock and enters the synchronized block.
Now, while that first thread is processing, the next InSync object enters its run method. It runs into the synchronized block and requests its own lock. Of course, no other thread is using it, so it acquires the lock and heads into the synchronized block. Oh no! That's not what we wanted at all! Now we have 2 threads executing the same synchronized block of code at the same time!
What happened was that we had each thread trying to acquire the lock on a different object (in this case, itself). Since there are 3 InSync objects, there are 3 locks available and all 3 threads can process the synchronized block at the same time. Basically, we've accomplished nothing - we might as well have left the synchronized statement out entirely.
So, what about synchronizing on the variable letter?
Well, the first InSync object enters its run method and hits the synchronized statement. It requests the lock on the StringBuffer referenced by letter and, as no other thread is using it, the InSync object acquires the lock and proceeds to execute the synchronized block.
Now, the second InSync object enters its run method and hits the synchronized block. Likewise, it requests the lock on the StringBuffer referenced by letter - now, however, that lock is already in use by the first InSync object so this thread has to wait. Ahhh, just what we wanted. Once the first thread is done executing that block and releases the lock, another thread can acquire it and advance.
The "key" (yup, pun intended ) to making this work is that we must have all 3 InSync objects trying to acquire the same lock. As all 3 objects refer to the same StringBuffer object, we can safely use the lock of that object to achieve our goal.
Now, what's this about a "third-party" object? Well, it sounds more complicated than it is. A "third-party" object is something that is somewhat removed from what we're doing. Rather than locking on one of the objects being used (such as one of the threads or the StringBuffer that they're operating on), you might want to create some other object solely for the purpose of creating a lock you can use. As every object has a lock, you could create an object like this:

and safely use it as a lock. Here is an example:

I hoep that helps,
Corey
 
Kathy Cai
Greenhorn
Posts: 13
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Corey,
Thank you very much for spending time in writing such clear explanation. I really appreciate it. Now I have much better understanding of this topic.
Regarding using a third-party object as lock, this object must be referenced by the Thread objects (i.e., InSync objects in this example)via a member variable. Do you agree?
Kathy
 
Ranch Hand
Posts: 42
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Hi,
Corey's explanation is marvellous!!! Thanks!
But I still have some lingering doubt in this topic. Appreciate if you could shed more light . Also, please correct me if I am wrong.
I thought

each InSync will have their own (StringBuffer letter)? Am I right? This is because StringBuffer is not defined as static or anything. Whenever an object (InSync) is created, they will have their own copy of letter. If this is the case, there is no necessity to use synchronise at all?
Please verify.
Thanks.
Cheers.
 
Ranch Hand
Posts: 31
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Originally posted by CH Lee:

...
each InSync will have their own (StringBuffer letter)? Am I right? This is because StringBuffer is not defined as static or anything. Whenever an object (InSync) is created, they will have their own copy of letter. If this is the case, there is no necessity to use synchronise at all?


Each InSync object will have its own reference variable, correct. But each of those variables refers to the same object cos we are passing the same reference into the constructors. And so there is a need to synchronise. Probably the terminology I used is incorrect, but I guess u shuld get the general idea.
I guess the best example to use synchronization would be the Producer-Consumer problem.... That will make it clear where such a situation would be useful. Look her for Jyoti's example :
Jyoti's Page
 
Corey McGlone
Ranch Hand
Posts: 3271
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Originally posted by Kathy Cai:
Regarding using a third-party object as lock, this object must be referenced by the Thread objects (i.e., InSync objects in this example)via a member variable. Do you agree?

Not necessarily. There are all sorts of tricks of the trade out there that you could use to accomplish your goal. One that comes to mind (which is probably overkill for the situation) is the use of a singleton pattern. A singleton pattern is a simple design which only allows the existence of 1 instance of a class (if you don't know what it is, you can read about it in this JavaRanch Newsletter article). I hope this doesn't confuse the issue for you, but let me try to show you what I'm talking about:

As you can see, this would still allow for successful synchronization as all of the threads would be locking on the same object. However, the object they are locking on is not referenced via a member variable contained within the InSync object.
I hope that helps without just confusing you,
Corey
[ February 25, 2004: Message edited by: Corey McGlone ]
 
Corey McGlone
Ranch Hand
Posts: 3271
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Originally posted by CH Lee:

each InSync will have their own (StringBuffer letter)? Am I right? This is because StringBuffer is not defined as static or anything. Whenever an object (InSync) is created, they will have their own copy of letter. If this is the case, there is no necessity to use synchronise at all?


Bijesh is absolutely correct. Although each InSync object has it's own reference variable named letter, every one of them will refer to the same StringBuffer object. Note that the lock that is required for synchronization belongs to the object, not to the variable that refers to that object. Therefore, no matter how many variables to refer to the object (in this case, there are 3), there is only 1 lock available because there is only 1 StringBuffer object.
I hope that helps,
Corey
 
CH Lee
Ranch Hand
Posts: 42
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Wow!!! Thanks for the great explanation!!! Have to admit that I am not that careful and specific as you guys in analysing the code!!! Now I understand this point crisp clear.
Just one last affirmation.
If I coded it like this:

The letter in each InSync will not need a synchronised lock, am I right?
Once again, thanks guys!!!
Cheers.
 
Corey McGlone
Ranch Hand
Posts: 3271
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

You need to be really careful about what you're doing here for a couple reasons.
First and foremost, this won't compile as is. The constructor for InSync is expecting a StingBuffer object, not a String object. Assuming that you modify the definition of the variable InSync.letter to be of type String, we have another issue to consider.
In Java, Strings are immutable. Because of this, there are some optimizations done on String literals. Normally, if you have code like this:

You will create 3 distinct Sting objects. However, when these objects are created, an entry is made in the String literal pool (a place to hold constants) which references each String. If I then, later in my code, had the following line:

I would not create 3 new Strings ("One", "Three", and "OneThree"), I would really only create 1 new String ("OneThree"). The reason for this is that, rather than making another identical String that contains "One", the system will simply give you a reference to the one that already exists.
So, to make a long story short, your example would work - you would successfully synchronize all 3 threads on the same object. However, the reason that it works is based on an optimization, not on good fundamental theory.
As far as the SCJP exam goes, you don't need to know a thing about the String literal pool, but I thought I'd try to explain what was going on.
Let me know if you have questions or if I've just confused you.
Corey
 
Today you are you, that is turer than true. There is no one alive who is youer than you! - Seuss. Tiny ad:
a bit of art, as a gift, that will fit in a stocking
https://gardener-gift.com
reply
    Bookmark Topic Watch Topic
  • New Topic