Get yourself familiar with concurrency programming
When I interview my candidates, I like to ask questions related to multi-threading. I found out that it is a good topic to differentiate out a hardcore programmer from application-oriented programmer. I am not saying I am looking for someone who could write the concurrency library as efficient as the one created by Doug Lea. In fact, I am looking for candidates who has solid understanding of this topic. Even that, I feel that I am asking for too much because I seldom see candidates who knows more than just how "synchronized" keyword means. Therefore I decide to write a series of articles to cover some areas of multi-threading that I feel important to understand. Of course, I would start from the basic first.
Introduction of Synchronization
Synchronization is a way to lock an object, so no 2 threads possibly running on the same code at the same time.
public class SynchronizedCounter {
private double c = 0;
public synchronized void increment() {
c++;
}
public synchronized void decrement() {
c--;
}
public synchronized int value() {
return c;
}
public void method2() {
...
}
}
If count is an instance of SynchronizedCounter, then making these methods synchronized has two effects:
- First, it is not possible for two invocations of synchronized methods on the same object to interleave. When one thread is executing a synchronized method for an object, all other threads that invoke synchronized methods for the same object block (suspend execution) until the first thread is done with the object.
- Second, when a synchronized method exits, it automatically establishes a happens-before relationship with any subsequent invocation of a synchronized method for the same object. This guarantees that changes to the state of the object are visible to all threads.
All in all, synchronized methods enable a simple strategy for preventing thread interference and memory consistency errors. Interference happens when two operations, running in different threads, but acting on the same data, interleave. This means that the two operations consist of multiple steps, and the sequences of steps overlap. This will result in unpredictable data lost (hard to fix). Memory consistency error occurs when complier and processor reorder statements for better performance.
Synchronization will serialize the method calls from different threads. At any given time, only one thread can execute the synchronized method and the other threads need to wait until the object lock releases. This will dramatically diminish the liveness of your application. To minimize the impact, you can try this:
- Reduce lock duration - Synchronized statements are useful for improving concurrency with fine-grained synchronization
- Reduce lock scope - Mutex variable in the synchronized lock may help you to avoid locking the whole object.
So far so good.? Great! lets me ask you 3 questions:
- Question 1: In the example above, if thread A is executing a synchronized method "increment", can another thread execute method2?
- Question 2: If thread A is in the synchronized method xyz , can it invoke another synchronized abc?
- Question 3: If I want to make the above class thread-safe without using synchronization because it will introduce overhead, is there any other possible way?
The answer of these 3 questions are:
- Yes. Because method2 is not synchronized, a thread doesn’t need obtain the object lock before executing it.
- Yes. Because thread A is holding the object lock, it can invoke other synchronized methods of the same object. Recall that a thread cannot acquire a lock owned by another thread. But a thread can acquire a lock that it already owns. Allowing a thread to acquire the same lock more than once enables reentrant synchronization.
- Use int, byte instead of double because updating int or byte is an atomic action. Atomic actions cannot be interleaved, so they can be used without fear of thread interference. However, this does not eliminate all need to synchronize atomic actions, because memory consistency errors are still possible. Using
volatilevariables reduces the risk of memory consistency errors, because any write to avolatilevariable establishes a happens-before relationship with subsequent reads of that same variable. So, if you can make your counter "volatile int" instead of double. You don’t need to use synchronized keyword.
Here is what specifies in the JVM spec:
The Java language specification gives compilers the flexibility on how operations on 64 bit values should be read and operated upon. Some implementations and compilers may find it easy to divide a 64 bit double and long values into two 32 bit and write them to adjacent locations. The Java memory model treats the two 32 bit writes as separate writes, so there is a possibility of a thread seeing a partial value when the virtual machine is mid-way during a write. To avoid the problem the variable can be declared as volatile or a reference to the variable can be used to do operation. Volatile long and volatile double values are always read as a single atomic unit. It is the same case with references, irrespective of whether they are declared as 32 bit or 64 bit values.
Try out java.util.concurrency package
Reads and writes of volatiles are atomic. Volatile writes and reads cannot be reordered by compilers. Effectively, volatiles must be accessed through acquire/release pairs. Volatiles are useful when writing non-blocking code. An alternative to volatile is java.util.concurrent.Atomic in Java 5. Below is an example rewritten using Atomic variable to avoid synchronization.
import java.util.concurrent.atomic.AtomicInteger;
class AtomicCounter {
private AtomicInteger c = new AtomicInteger(0);
public void increment() {
c.incrementAndGet();
}
public void decrement() {
c.decrementAndGet();
}
public int value() {
return c.get();
}
}
Java Memory Model
JMM is what causes concurrent programming way more complicated than it should be. Honestly, I am not good to write this part because I cannot understand it in full. All I can do is to provide you a video from Jeremy Manson in Google. Hear what the expert said:
If you still have questions, be sure come to his blog
http://jeremymanson.blogspot.com/
Reference
Below are some of the articles I use:
- Sun lesson on concurrency
- Fixing Java Memory Model - Brian Goetz - Part 1, Part 2
- Rox Java NIO Tutorial
- Blocking Queue






































(4.75 out of 5)
1 Comment Received
Pingback & Trackback
Sorry the comment area are closed for non registered users