Search code examples
javamultithreadingsynchronizationlockingreadwritelock

Should getters/setters of primitive types be locked with ReadWriteLock in a multithreading application?


I have a Java class that is used in a multithreading application. Concurrent access is very likely. Multiple concurrent read operations should not block so I'm using a ReadWrite lock.

class Example {
    private final ReadWriteLock lock = new ReentrantReadWriteLock();
    private int i;
    private boolean b;

    public int getI() {
      lock.readLock().lock();
      final int tmp = i;
      lock.readLock().unlock(),
      return tmp;
    }

    public void setI( final int i ) {
      lock.writeLock().lock();
      this.i = i;
      lock.writeLock().unlock();
    }

    public boolean getB() {
      lock.readLock().lock();
      final boolean tmp = b;
      lock.readLock().unlock(),
      return tmp;
    }

    public void setB( final boolean b ) {
      lock.writeLock().lock();
      this.b = b;
      lock.writeLock().unlock();
    }
}

For simplicity I left out the try...finally blocks around the locks in this example.

I'm wondering if it's necessary (or let's say recommended) to lock/synchronize getters and setters of primitive types? I know that assign and return operations in Java are atomic. However by using these locks don't I make sure that every accessor gets the latest value (equals to using volatile)?

What if the primitives were double or long?


Solution

  • It depends.

    Note, however, that usually you need to synchronize operations at more coarse-grained level, for example, this:

    Example e = ...;
    
    synchronized (e) {
        e.setI(e.getI() + 10);
    }
    

    For such scenarios your internal locks are redundant. Therefore perhaps it would be better to apply external synchronization where you use these objects, rather than internal synchronization.