1

I am just trying to understand... Will I achieve the same result using the below two approaches? I mostly see the first approach only. Is there anything wrong with the second approach? We can use AtomicInteger to achieve the same but just wanted to know. Can someone please clarify?

Approach#1

public class Counter {
   private int counter = 0;
   
   public int getCount() {
      synchronized(this) {
         return counter;
      }
   }

   public void increment() {
      synchronized(this) {
         counter++;
      }
   }
}

Approach#2

public class Counter {
   private volatile int counter = 0;
   
   public int getCount() {
      return counter;
   }

   public synchronized void increment() {
      counter++;
   }
}
itspr
  • 273
  • 1
  • 3
  • 6
  • 3
    Both are fine. The latter might be a fraction better, but I'd suspect it makes almost no difference. If you're that concerned, benchmark it. – Michael Mar 01 '23 at 10:56
  • Both are correct. The second one, from my point of view, may be slightly better for readers, especially in case of high contention on reader's side (a number of threads read the current value) and relatively rare write operations... For readers JVM doesn't need to deal with all that machinery around object locking (thin fat biased locks etcetc), just with memory barriers. In that meaning AtomicInteger may be even more effective, especially if you use lazySet in case of single writer (more optimal/effective mem barriers/a bit rarer cpu cache invalidation) – AnatolyG Jun 02 '23 at 11:53

2 Answers2

1

Michael's comment is correct. Both approaches are fine.

In terms of performance, it is difficult to say which one is better. It might even depend on the architecture (x86 vs ARM).

The second one might be better for gets, but worse for increments (because both the lock is taken, and a write memory barrier is issued, unless JIT can optimize that away...)

ciamej
  • 6,918
  • 2
  • 29
  • 39
1

You never need volatile if you're using synchronized. Both keywords establish a "happens before" relationship between events in different threads.

  • Whatever some thread A does before it writes a value to some volatile variable, v, is guaranteed to be visible to some other thread B after B subsequently reads the same variable, v.

  • Whatever some thread A does before it exits from a synchronized(o) block is guaranteed to be visible to thread B after B subsequently enters a block that is synchronized on the same object, o.

Solomon Slow
  • 25,130
  • 5
  • 37
  • 57