Java method skipped sometimes by one of threads

bodich :

I have a trouble when using the same method by 2 threads.

The problem is: Looks like when one thread called method, and method is running, and in the same time another thread try to call the same method, Java just skip that call! So, when 2 threads are calling the same method, that method is being called only once. So, sometimes randomly programm is just skip method and code is not executed at all! How it's possible? Tried on different machines, it works definitely not like expected and for me looks like a terrible Java bug.

Please, if any expert will read this, can you describe what happens and if it's known issue, give me the link to explanation. Thank you!

PS: The code is fully working, you can just paste it even to online java like repl.it or similar. Right after a.updateCounter(inc); I check if incrementer worked (line 45).

class Main {
  public static void main(String[] args) {
    ThreadOne t1 = new ThreadOne(1000, 300, "Thread 1");
    ThreadOne t2 = new ThreadOne(1, 300, "Thread 2");
    Thread one = new Thread(t1);
    Thread two = new Thread(t2);
    one.start();
    two.start();
  }
}

class Accum {
  private static Accum a = new Accum();
  private int counter = 0;
  private Accum() {}
  public static Accum getAccum() {
    return a;
  }

  public void updateCounter(int add) {
    counter += add;
  }

  public int getCount() {
    return counter;
  }
}

class ThreadOne implements Runnable {
  Accum a = Accum.getAccum();
  int inc;
  int max;
  String threadName;

  ThreadOne(int i, int c, String name) {
    inc = i;
    max = c;
    threadName = name;
  }

  public void run() {
    for(int x = 0; x < max; x++) {
      int check = a.getCount();
      a.updateCounter(inc);
      if(check + inc != a.getCount()) System.out.println("\nupdateCounter was skipped at x " + x + "\nThread name: " + threadName);
      try {
        Thread.sleep(5);
      } catch(InterruptedException ex) {
        System.out.println("x: " + x + "\n ex: " + ex);
      }
    }
    System.out.println(threadName + ": " + a.getCount());
  }
}
Benoit :

First, Java does not skip the call. It's just the actual result that does not match your test.

Between int check = a.getCount(); and the test if(check + inc != a.getCount()), the counter is simply changed by the other thread. That's as simple as that.

UPDATE: The operation counter += add is not ATOMIC, i.e. you can view it as a sequence of 3 operations:

  • The value of counter is read
  • A new value is computed
  • This new value is assigned to counter

Now imagine 2 threads performing this sequence exactly in the same time, and you understand why the value does not get incremented.

Solution to make this call atomic: Simply use AtomicInteger as mentioned by @gudok:

import java.util.concurrent.atomic.AtomicInteger;

public class Accum {
    private static Accum a = new Accum();
    private AtomicInteger counter = new AtomicInteger(0);
    private Accum() {}
    public static Accum getAccum() {
        return a;
    }

    public void updateCounter(int add) {
        counter.addAndGet(add);
    }

    public int getCount() {
        return counter.intValue();
    }
}

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=128521&siteId=1