Thursday, June 16, 2011

ReadWriteLock’s on Collections

Many people don’t realize that Collections.synchronized* causes an exclusive monitor lock to be held in every method called on the specified Collection object. For example:

final List<Integer> list = Collections.synchronizedList(new ArrayList<Integer>());

Thread th1 = new Thread(new Runnable() {
    public void run() {
        for(int i = 0; i < Integer.MAX_VALUE; i++) {
            list.add(Integer.valueOf(i));
        }
    }
});

Runnable reader = new Runnable() {
    public void run() {
        for(int i = 0; i < Integer.MAX_VALUE; i++) {
            list.get(i);
        }
    }
};

Thread th2 = new Thread(reader);
Thread th3 = new Thread(reader);
Thread th4 = new Thread(reader);
th1.start();
th2.start();
th3.start();
th4.start();

I am well aware that the code for reading is very bad, but it serves the point. Four Threads, one writing to a synchronized Collection, the others reading from it. This as such is not a problem: writing to a Collection should only ever be done by one thread at a time, while no other threads are reading. However, any number of threads can read from the Collection at the same time. Collections.synchronized* acquires an exclusive lock for both read and write methods, so: only one thread will be allowed to access the Collection at a time.

The Solution
Solution 1 : Use ReentrantReadWriteLock
Use a ReentrantReadWriteLock, which allows any number of Read locks at a time, but only one Write lock (and no Read locks while a Write lock is held).

There is an even more efficient way to make a Collection thread safe: use an inherently thread-safe collection. Just take a look in java.util.concurrent, and you’ll see that Java comes packed with plenty of them. You will need to decide which method is preferred for what you are doing. Take into account:
  • How many reads vs. how many writes
  • How large is the collection
  • How fast does the code need to execute
  • How often will the collection actually be accessed
Solution 2 : Use Concurrent datastructures
Use the concurrent datastructures provided by java.util.concurrent. They are extremely good and suffice for 95% of the time. So rather than using your locks use the already provided implementation and rock in the world of concurrency.

No comments:

Post a Comment

Chitika