Is it always ok to use 'this' as a monitor lock?

For example, I have a class with 2 counters (in a multi-threaded environment):

public class MyClass {
  private int counter1;
  private int counter2;

  public synchronized void increment1() {
        counter1++;
  }

  public synchronized void increment2() {
        counter2++;
  }

}

      

Theres 2 increment operations are not related to each other . But I am using the same blocking object ( this

).

True, if clients simultaneously call methods increment1()

and increment2()

, then the call increment2

will block until the increment1()

monitor is released this

?

If this is true, does this mean that I need to provide different monitor locks for each operation (for performance reasons)?

+3


source to share


7 replies


Isn't it true that if clients call increment1 () and increment2 () at the same time, then increment2 will block until increment1 () releases this monitor?

If they are called in one instance, then yes.

If this is true, does this mean that I need to provide different monitor locks for each operation (for performance reasons)?

Only you can know this. We do not know your performance requirements. Is this actually a problem in your actual code? Are your current surgeries going to be long? Do they happen very often? Have you performed any diagnostics to assess the impact of this? Have you profiled your app to see how much time is spent looking at the monitor, let alone when you don't need it?



I would rather not sync on this

for completely different reasons. It's already hard enough to talk about streaming when you're in control, but when you don't know everything a monitor can buy, you hide out to nothing. When syncing to this

this means that any other code that has a reference to your object can also sync to the same monitor. For example, a client can use:

synchronized (myClass) {
    // Do something entirely different
}

      

This can lead to deadlocks, performance issues, etc.

If, instead, you use a field private final

in your class, with an object created just to be a monitor, then you know that the only code acquiring that monitor will be your code.

+12


source


1) yes, it is true that increment1 () blocks increment2 () and vice versa, because they both are implicitly synchronized on this

2) if you need better performance consider the java.util.concurrent.atomic.AtomicInteger class without blocking



  private AtomicInteger counter1 = new AtomicInteger();
  private AtomicInteger counter2 = new AtomicInteger();

  public void increment1() {
        counter1.getAndIncrement();
  }

  public void increment2() {
        counter2.getAndIncrement();
  }

      

+5


source


If you synchronize a method like what you did here, you will lock the entire object, so two threads accessing another variable from the same object will block each other anyway.

If you only want to synchronize the counter at a time, so the two threads won't block each other when accessing different variables, you need to add the two counters here in the two synchronized blocks and use the different variables as a "lock" of the two blocks.

+2


source


You are correct, it will be a performance bottleneck if you are using the same object. You can use different locks for a single counter or use java.util.concurrent.atomic.AtomicInteger

for a parallel counter.

how

public class Counter {
  private AtomicInteger count = new AtomicInteger(0);
  public void incrementCount() {
    count.incrementAndGet();
  }
  public int getCount() {
    return count.get();
  }
}

      

+2


source


Yes, if multiple threads try to call methods on your object, they will wait to try to acquire the lock (although the order of who acquires the lock is not guaranteed.) As with everything, there is no reason to optimize until you know it is the neck of the bottle in your code.

+1


source


Yes, this code is identical to the following:

  public void increment1() {
        synchronized(this) {
             counter1++;
        }
  }

  public oid increment2() {
        synchronized(this) {
             counter2++;
        }
  }

      

which means that only one method can be executed at a time. You must either provide different locks (and locking on this

is a bad idea to start with) or some other solution. The second is the one you really want here: AtomicInteger

+1


source


If you want the performance benefits that can come from the ability to call both operations at the same time, then yes, you shouldn't provide different monitor objects for different operations.

However, there is something to be said about premature optimization that you should make sure you need it before making your program more complex to host.

0


source







All Articles