garbagecollector
garbagecollector

Reputation: 3880

How to individually synchronize data members

I have been searching the web for this, but have been unable to find any article that comes close to this, and I'm quite surprised by that. Maybe the wisdom is hidden somewhere that I have yet to find.

Suppose I have a class with 10 members of various types (for the sake of simplicity, let's say they are mixed of ints and Strings), and each one of them has its own accessor methods. Now, I want to make this class thread-safe. But, some of these data members don't necessarily interact with each other. For example the class Person below, has age and name and other properties.

public class Person {
    private volatile int age;
    private String name;
    private volatile long blabla;
    // ... and so on

    public synchronized int getAge() {
        return age;
    }

    public synchronized void setAge(int age) {
        this.age = age;
    }

    // .. and so on for each data member
}

One thread may only need to read/write age, and other threads only need to modify name. Obviously, adding synchronized to each and every one of the accessor methods is a bad idea as it locks the entire instance of the object. A thread that's calling getAge() has to wait for another thread that's calling getName() even though age and name are two separate fields.

So, one obvious solution is to create a lock for each field (or add volatile to primitive types). However, this seems to be an overkill. If I have 10 data members, do I also need 10 locks? I'm wondering if there's another way of achieving this without excessive locking.

Upvotes: 0

Views: 1557

Answers (2)

Gray
Gray

Reputation: 116938

First off, if you are talking about primitives (or immutable objects like String) then all you should need is to mark each of the fields volatile. Locks won't be necessary if all you are doing is getting and setting field values.

However, if your get/set methods do multiple operations and synchronized blocks are need, having a synchronized blocks per field seems like premature optimization to me. I think that synchronized methods on a small object like your Person is a perfectly appropriate way to accomplish this. Unless you have real reasons (i.e. profiler output), I would not try to make it more complicated. Certainly a lock per field is overkill in just about any situation.

It would make a difference if the method takes a long time. Then you would not want to lock the entire object and block the other accessors. Then it is a good time to have multiple locks -- each for separate calculation. But if your object truly is just trying to protect get/set then a synchronized method is fine.

Couple of other comments:

  • If you can get away with just volatile fields then you don't need any synchronized blocks.
  • If you have synchronized methods then you do not need to make your fields volatile.
  • If the name field should probably be marked as final if it is not being written to.

Upvotes: 4

Jordan Denison
Jordan Denison

Reputation: 2737

If you are concerned about synchronizing primitive types, this is an excellent use case for AtomicInteger etc... They are very fast and ensure thread-safety. For more info:

http://docs.oracle.com/javase/tutorial/essential/concurrency/atomicvars.html

Upvotes: 4

Related Questions