Jai Pandit
Jai Pandit

Reputation: 530

Difference between two ways of defining a thread safe class

I am wondering what functional difference in there in the below two example classes. Which style should be preferred over another and why.

public class MyQueue {
    private Queue<Abc> q;

    public MyQueue() {
        q = Collections.synchronizedList(new LinkedList<Abc>());
    }

    public void put(Abc obj) {
        q.add(obj);
    }

    public Abc get() {
        return q.remove();
    }
}

OR

public class MyQueue {
    private Queue<Abc> q;

    public MyQueue() {
        q = new LinkedList<Abc>();
    }

    public synchronized void put(Abc obj) {
        q.add(obj);
    }

    public synchronized Abc get() {
        return q.remove();
    }
}

My take is - both will work perfectly fine as far as this much functionality in the class, just a matter of personal preference.

Please let me know if there is more difference to it.

Upvotes: 1

Views: 77

Answers (2)

Livia Moroianu
Livia Moroianu

Reputation: 976

In case of a list there should not be any difference in functionality between accessing it through the wrapper or guarding every access to it using the synchronized block.

But there is a case where it is better to use the synchronization mechanisms offered by the wrapper, as is the case with ConcurrentHashMap.

If you would take care of guarding yourself the accesses to a simple non-thread safe HashMap for example, you would lock the entire map(all the keys) for any read/ write and that would affect concurrency on the map. ConcurrentHashMap instead locks only key sets of the map so you get better performance using it for read/write concurrent operations.

Thanks!

Upvotes: 0

Andrew Lygin
Andrew Lygin

Reputation: 6197

The main architectural difference is that the second implementation exposes the synchronization monitor (the object itself) to the outside world. It means that everyone can potentially acquire the same lock you use for internal synchronization:

MyQueue myQueue = new MyQueue();  // a shared instance

synchronized(myQueue) {
    // No one else can call synchronized methods while you're here
}

It might bring benefits or cause problems depending on your class use cases.

The fact that the first implementation hides the details of synchronization gives you a bit more flexibility for adding new functionality in the future (for instance, you can add some not synchronized code into your put() and get() methods if you need), but comes with a minor penalty of having an additional layer around your list.

Otherwise, there's no difference given the presented functionality.

PS: Don't forget to add final to the q declaration. Otherwise your class doesn't guarantee so called safe publication and cannot be called fully thread-safe.

Upvotes: 2

Related Questions