4

In my class I have code like:

int counter1;
int counter2;

public void method1(){
 if (counter1>0) {
  ...........do something
   if (counter2>0) {
    ....do something else
    }
}

public void method2() {
  counter1=0;
  counter2=0;
}

I need that both counters set together. I am afraid that OS can to method1 can be invoked after setting counter1 only. Does it possible? Thanks.

user710818
  • 23,228
  • 58
  • 149
  • 207

3 Answers3

4

Either use the synchronized keyword as the other answer suggest or use the ReentrantReadWriteLock if you have more reads than writes to the counter, for better performance. You can read about the lock here http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/locks/ReentrantReadWriteLock.html

private int counter1;
private int counter2;
private final ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();
private final Lock r = rwl.readLock();
private final Lock w = rwl.writeLock();

public void method1(){
   r.lock();
   try { 
     if (counter1>0) {
        ...........do something
     if (counter2>0) {
        ....do something else
     }
   } finally { r.unlock(); }

}

public void method2() {
  w.lock();
  try { 
    counter1=0;
    counter2=0; 
  } finally { w.unlock(); }

}
Leonard Brünings
  • 12,408
  • 1
  • 46
  • 66
  • Ehm! And what about one counter changed and another not? You haven't blocked it! – Gangnus May 05 '19 at 14:42
  • I don't understand what you mean, the counters in the example are protected by a ReadWriteLock. – Leonard Brünings May 06 '19 at 00:01
  • They are protected from access of another thread. But not from an exception. So, you code does NOT block two operations in an atomic way. – Gangnus May 07 '19 at 05:27
  • @Gangnus what exception, setting something to `0` doesn't throw one? And there is no `atomic` way to update multiple variables in standard Java. The [STM](https://en.wikipedia.org/wiki/Software_transactional_memory)s are all research level, and not production ready AFAIK. – Leonard Brünings May 07 '19 at 12:56
  • 1. do something can throw exceptions. 2. But yes, it is possible in Java. We haven't the ready construction, but we can program it. The best (though not ideal) algorithm for that on SO is here: https://stackoverflow.com/a/16906229/715269 – Gangnus May 07 '19 at 17:47
3

Sure, just use the synchronized keyword:

private final Object LOCK = new Object();
int counter1;
int counter2;

public void method1() {
  synchronized(LOCK) {
     if (counter1>0) {
      ...........do something
       if (counter2>0) {
        ....do something else
       }
    }
}
public void method2() {
  synchronized(LOCK) {
    counter1=0;
    counter2=0;
  }
}

Some tips:

Use a private object for synchronization rather than marking a method synchronized. This prevents something external to you class from grabbing the lock and stalling things.

Make sure that you use the synchronized keyword everywhere, and make sure you always synchronize on the same object. If you forget to do either of those things, two processes can access the fields at the same time.

Beware of deadlocks. In a perfect world you'd write unit tests to ensure that locking is working the way you think it is.

Sean Reilly
  • 21,526
  • 4
  • 48
  • 62
  • Yes, it is. But it's possible. One way is to inject your locks, rather than use the synchronized keyword. – Sean Reilly Feb 10 '12 at 10:05
  • don't get it, what's the difference here between locking on the private and method? thread 1 can call method1, and thread 2 can call method1, one will be blocked - there is no difference either way (method vs. private variable); the only thing I can see is you want to allow different locks for different bits of data in the class (which is plausible, but you have to know what you are doing..) - and I would argue then that the data belongs to different classes – Nim Feb 10 '12 at 10:07
  • 4
    @Nim: The difference is that if you synchronize the method, the object the method belongs to is used as a lock. Anyone with a reference to the object can also use this object as a lock, which can break your synchronization pretty horribly. It's a defensive coding technique. – Sean Reilly Feb 10 '12 at 10:11
  • And what about one counter changed and another not? You haven't blocked it! – Gangnus May 05 '19 at 14:43
1

Use a synchronized block or method to wrap access to the two counters, remember to use the same object to lock on.

cdc
  • 2,511
  • 2
  • 17
  • 15