9

Say I have a method:

public void run(){
  synchronized(this.foo){

 }
}

but sometimes when I run this method, I don't need to synchronize on anything.

What is a good pattern to conditionally synchronize on something? The only pattern I can think of is a callback, something like this:

public void conditionalSync(Runnable r){
   if(bar){
      r.run();
      return;
   }

  synchronized(this.foo){
     r.run();
  }
}

public void run(){
  this.conditionalSync(()->{


  });
}

is there another way to do it, without a callback?

xingbin
  • 27,410
  • 9
  • 53
  • 103

1 Answers1

7

Instead of synchronized keyword, maybe you can use ReentrantLock(which is more flexible and powerful).

Example:

ReentrantLock lock = ...;


public void run(){
    if (bar) {
        lock.lock();
    }

    try {
        // do something

    } finally {
        if (lock.isHeldByCurrentThread()) {
            lock.unlock();
        }
    }
}
xingbin
  • 27,410
  • 9
  • 53
  • 103
  • is there a way to "automate" the isHeldByCurrentThread check? is there some method that contains that check? Probably want to check for `bar` too in the finally block, if bar is false, then don't need to unlock. –  Feb 22 '19 at 01:49
  • 1
    @MrCholo I'm afraid of the answer is no. If you call unlock directly, while the thread does not hold the lock, `IllegalMonitorStateException` will be thrown. – xingbin Feb 22 '19 at 01:51
  • 2
    @MrCholo since the decision to synchronize or not shouldn’t change in-between, you can express this choice via class inheritance, e.g. create a base class providing the method doing work without synchronization and a subclass overriding the method to perform the super invocation in a synchronized block or while holding a lock. That’s how `StringBuffer` (synchronizing) and `StringBuilder` (not synchronizing) have been implemented. – Holger Feb 28 '19 at 10:55