In previous part 2 of threading, we had seen information about keywords and flags used in java threads. Today we go forward in java threading part 3.
The synchronized – Putting It Together:
- The synchronized mechanism works only if all access to delicate data occurs within the synchronized blocks.
- You should mark delicate data protected by synchronized blocks as private. If you do not do this the delicate data can be accessed from code outside the class definition; such a situation would be able other programmers to bypass your protection and cause data corruption at run time.
- A method consisting entirely of code belonging in a block synchronized to this instance might put the synchronized keyword in its header.
- The following two codes are equivalent:
- public void push(char c)
- // the push method code
- public synchronized void push(char c)
- // the push method code
Why use one technique instead of the other?
- If you use synchronized as a method modifier, the whole method becomes a synchronized block. That can result in the flag being held longer than necessary.
- However, making a method in this way permits users of the method to know, from javadoc utility generated documentation, that synchronization taking place.
- This can be important when designing against deadlock. The javadoc documentation generator propagates the synchronized modifier into documentation files, but it cannot do the same for synchronized(this), which is found inside the method’s block.
- In programs where multiple threads are competing for access to multiple resources, a condition known as deadlock can occur.
- This occurs when one thread is waiting for a lock held by the another thread, but the other thread is waiting for a lock already held by the first thread.
- In this condition, neither can proceed until after the other has passed the end of its synchronized block. Because neither is able to proceed, neither can pass the end of its block.
- JAVA technology neither detects nor attempts to avoid this condition. It is responsibility of the programmer to ensure that a deadlock cannot arise.
- A general rule of thumb for avoiding a deadlock is: If you have multiple objects that you want to have synchronized access to, make a global decision about the order in which you will obtain those locks, and adhere to that order through out the program.
- Release the locks in the reverse order that you obtained them.
Thread Interaction – wait and notify:
Different threads are created specifically to perform unrelated tasks. However, sometimes the jobs they perform are related in some way and it may be necessary to program some interactions between them.
Consider yourself and a car driver as two threads. You need a cab to take you to a destination and the cab driver wants to take on a passenger to make a fare. So, each od you have a task.
- You except to get into a cab and rest comfortably until the cab driver notifies you that you have arrived at your destination.
- It would be annoying, for both you and the cab driver, to ask every 2 seconds, “Are we there yet?”Between fares, the cab driver wants to sleep in the cab until a passenger needs to be driven somewhere.
- The cab driver does not want to have to wake up from this nap every 5 minutes to see if a passenger has arrived at the cab stand.
- So, both threads would prefer to get their jobs done in as relaxed a manner as possible.
- You and the cab driver require some way of communicating your need to each other. While you are busy walking down the street towards the cab stand, the cab driver is sleeping peacefully in the cab.
- When you notify the cab driver that you want a ride, the driver wakes up and begins driving, and you get to relax.
- After you arrive at your destination, the cab driver notifies you to get out of the cab and go to work. The cab driver now gets to wait and nap again until the next fare comes along.
It describes how threads interact.
The wait and notify Methods:
- The java.lang.Object class provides two methods, wait and notify, for thread communication.
- If a thread issues a wait call on a rendezvous object x, that thread paused its execution until another thread issues a notify call on the same rendezvous object x.
- In the previous scenario, the cab driver waiting in the car translates to the cab driver thread executing a cab.wait() call, and your need to use the cab translate to the you thread executing a cab.notify() call.
- For a thread to call either wait or notify on an object, the thread must have the lock for that particular object.
- In other words, wait and notify are called only from within a synchronized block on the instance on which they are being called.
- For this example, you require a block starting with synchronized(cab) to permit either the cab.wait() or the cab.notify() call.
The Pool Story:
- When a thread executes a synchronized code that contains a wait call on a particular object, that thread is placed in the wait pool for that object.
- Additionally, the thread that calls wait releases that objects lock flag automatically. You can invoke different wait method.
- When a notify call is executed on particular object, an arbitrary thread is moved from that object’s wait pool to a lock pool, where threads stay until the objects lock flag becomes available.
- The notifyAll methods moves all threads waiting on that object out of the wait pool and into the lock pool.
- Only from the lock pool can a thread obtained that object’s lock flag, which enables the thread to continue running where it left off when it called wait.
- In many systems that implements the wait-notify mechanism, the thread that wakes up is the one that has waited the longest. However, JAVA technology does not graduates this.
- You can issue a notify call continue without regard to whether any threads are waiting. If the notify method is called on an object when no threads are blocked in the wait pool for that object’s lock flag, the call has no effect.
- Calls to notify are not stored.
Monitor Model for Synchronization:
- Coordination between two threads needing access to common data can get complex.
- You must ensure that no thread leaves shared data in an inconsistent state when there is the possible that any other thread can access that data.
- You also must ensure that your program does not deadlock, because threads cannot release the appropriate lock when other threads are waiting for that lock.
- In the cab example, the code relied on one rendezvous object, the cab, on which wait and notify were executed.
- If someone was excepting a bus, you would need a separate bus object on which to apply notify.Remember that all threads in the same wait pool must be satisfied by notification from that wait pool’s controlling object.
- Never design code that puts threads excepting to be notified for different conditions in the same wait pool.