This week's book giveaway is in the OO, Patterns, UML and Refactoring forum. We're giving away four copies of Refactoring for Software Design Smells: Managing Technical Debt and have Girish Suryanarayana, Ganesh Samarthyam & Tushar Sharma on-line! See this thread for details.
First, please use code tags when posting code samples. They make it much easier to read. I've added them for you here.
The class has methods for incrementing c1 and c2, and these are synchronized so that multiple threads could use the same MsLunch object and not corrupt the counters (i.e. c1 and c2). I think c++ is an atomic operation, so the synchronization may not be necessary, but think if it was c = c + 1. That could be implemented by the JVM as:
RETRIEVE C from memory
ADD 1 to C
STORE result back to memory
Remember a thread can be interrupted any time, even in the middle of an operation. Let's say two threads called it at the same time, and one was interrupted in this process.
T1: RETRIEVE C from memory
T2: RETRIEVE C from memory
T2: ADD 1 to C
T2: STORE result back to memory
T1: ADD 1 to C
T1: STORE result back to memory
The net result is C has been incremented by 1, but it should have been incremented by 2.
By synchronizing the code, we tell thread 1 to get the "monitor" of the object synchronizing the block of code (i.e., lock1 or lock2) before it can enter that block. It's only important to remember that every object has a monitor, and that only one thread at a time can have it. If thread 1 is interrupted before it completes the synchronized block, then it keeps the monitor while it waits for its next turn to execute. When thread 2 wants to enter the synchronized block, it tries to get the monitor, but can't since thread 1 already has it, so thread 2 has to wait. Eventually thread 1 gets some more execution time, finishes the synchronized block, and releases the monitor. The next time thread 2 can execute, it will be able to get the monitor and enter the block.
Joined: Jun 06, 2012
Thanks a lot greg for such a clear explaiantion.
First of all sorry for not using code tags as this was my first post on java ranch,i just joined.
I have one more doubt like how will thread 1 will acquire lock on objects lock1/lock2.
The objects lock1/lock2 aren't locked, despite their names. They just control access to the synchronized blocks of code. Imagine the monitor as a key to a door. Each object lock1 and lock2 has one of these keys. (The object you make by calling new MsLunch() also has one, though in this example nothing is asking for it.) OK, now think of synchronized blocks as rooms with locked doors, and threads as people who want to get through those doors. Mr. Thread1 comes to the locked door of the synchronized block in incl(), and sees that the key (monitor) belongs to lock1. He goes to the JVM, asks to borrow the key, uses it to open the door, goes into the room, and the door locks behind him. While he's in there, Ms. Thread2 goes to the same door, finds it locked, and goes to the JVM to ask for the key. The JVM says, sorry, someone's using it, you'll have to wait. Mr. Thread1 finishes his work in the block and returns the key. The next time Ms. Thread2 asks for the key, the JVM finds it's been returned and hands it over to her so she can get into the room.
Problems that Mr. Thread1 and Ms. Thread2 run into are exactly what you have to watch out for in synchronization. One problem is that after Thread1 returns the monitor, Thread3 may swoop in and grab it before Thread2 gets a chance. If that happens too often, then it's called starvation. The JVM tries to prevent thread starvation, but it can be a difficult problem. Another problem is deadlock, which is mostly up to the programer to prevent. Some tasks may require having two keys simultaneously to accomplish. If Thread1 has one key, but has to wait for the second, while at the same time Thread2 has the second and has to wait for the first, they will both have to wait forever.
Joined: Jun 06, 2012
Ok ,that clearified the concept more...
If I want to write the code for the two threads to approach the inc1 method will it be like below:
we are not explicitly using Object lock1 any where in the code which provides monitor for the sync method inc1()?
m not sure if this code will compile ,just wrote to expresss my approach in understanding synchronization...
There's no need to sleep to release a monitor. It will be automatically released when the thread finishes running the statements in the synchronized block. Also keep in mind that there is one monitor per instance. m2 and m11 in your example are two different instances of MsLunch, and each one has its own instances of lock1 and lock2. That makes four total monitors. Your main thread and Thread2 could both be inside the synchronized block of inc1() at the same time, but it doesn't matter because they are working on different fields. The main thread increments the c1 field of the m11 instance and Thread2 increments the c1 field of the m2 instance.