2

I have a question about concurrency, I just wrote a program that runs 2 threads with the following instructions:

Thread 1: increment by 1 the variable "num" till 1'000'000 with loop
Thread 2: same thing but decrementing

at the end I receive an undesired result. And yeah I know that I could synchronize or try to use reentrant locks, but the problem is that I can't understand what's behind all this different undesired results.

I mean the operations I'm using are commutative and hence we don't care about the ordering, so if this doesn't matter we should still obtain 0 which is not the case!

Can someone explain to me what happens behind all the computing, so that I can get a feel and I can recognize this situations immediately?

EDIT: Since I was just interested in understanding the main concept I thought it wasn't necessary to put the code.

Code:

class MyThread implements Runnable {
int id;
volatile static long num = 0;


MyThread(int id) {
    this.id = id;

public void run() {
    if (id == 0) {
            for (int j = 0; j < 100000; ++j)
                num++;}
    } else {
            for (int j = 0; j < 100000; ++j)
                num--;}

After this I create the Threads and run them:

    MyThread p = new MyThread(0);
    MyThread q = new MyThread(1);
    Thread t = new Thread(p);
    Thread u = new Thread(q);
    t.start();
    u.start();
    try {
        t.join();
        u.join();
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
}

EDIT2: I understand the concept now, but I would also like to know why declaring the variable as volatile still gives me wrong results?

EDIT3: I thought about it, and I think it's because bad interleaving can still give problems!

DevX10
  • 483
  • 2
  • 6
  • 16
  • 4
    Where is the code? – Fran Montero Jul 13 '16 at 09:22
  • 1
    "an undesired result" Neither your desired nor undesired results are given in your question, so it is hard to understand your issue. – Andy Turner Jul 13 '16 at 09:24
  • This has been answered many times, but I would suggest you will learn much more if you can work it out for yourself. The answer is not complicated. Hint: break down what `--` and `++` really has to do. – Peter Lawrey Jul 13 '16 at 09:30
  • @AndyTurner the desired result ist written (0) and that means, that the undesired result is different from 0 (after every run it gives different results). But still I attached the code now! – DevX10 Jul 13 '16 at 09:33
  • @AndyTurner while not specified, this question has been asked so many times, it pretty safe to assume it's the same problem. ;) – Peter Lawrey Jul 13 '16 at 09:37
  • Further hint; There is no java byte code operation to increment a field. You can only increment local variables. – Peter Lawrey Jul 13 '16 at 09:38

2 Answers2

4

If the increment/decrement operation are not atomic, you can end up with this kind of behaviors.
An operation is considered atomic if it appears to the rest of the system to occur instantaneously. (cf wikipedia).

Consider the following case:

  1. Thread 1 reads the value n in the variable x.
  2. Thread 2 reads the value n in the variable x.
  3. Thread 1 increment the value and store it in the variable x, that now evaluate at n+1.
  4. Thread 2 decrements the value and store it in the variable x, that now evaluate at n-1.

But what you wanted was the variable x to still evaluate at n.

I do not know the specific of java primitive but it appears that you could use AtomicInteger or using a synchronized method could solve your issue here.

Thomas Moreau
  • 4,377
  • 1
  • 20
  • 32
  • From http://javamex.com/tutorials/synchronization_volatile.shtml, you can see that volatile just make sure that read and write are thread safe, but : "because accessing a volatile variable never holds a lock, it is not suitable for cases where we want to read-update-write as an atomic operation (unless we're prepared to "miss an update"); ". you must thus use some more complex class to make sure the increment/decrement are atomic as volatile does not. The easier is probably AtomicInteger from the java.util.concurrent.atomic package. – Thomas Moreau Jul 13 '16 at 11:12
  • Thanks for the answer – DevX10 Jul 13 '16 at 11:21
0

just mark this field as volatile. By this way you will reach safe access and you will be able to change it in a multi-thread application without using any other synchronization tools.

antongarakh
  • 570
  • 6
  • 16
  • This will make it a little less bad, but won't prevent an "undesirable" result. – Peter Lawrey Jul 13 '16 at 09:30
  • Oh in every article i read about concurrency authors were quite careful about results. They said something like a "The output of the program can be as following". So they are not sure about it. – antongarakh Jul 13 '16 at 09:33
  • The reason why you never know how fast are concurrent threads and which is faster. If you want to reach it, you have to use Locks or other synchronization tools, as you said. – antongarakh Jul 13 '16 at 09:35
  • @antongarakh no, the reason is that in/decrementing an `int` is not atomic, and the threads interleave. – Andy Turner Jul 13 '16 at 09:35
  • 1
    @antongarakh AtomicLong uses compare and set and an atomic adding operation. – Peter Lawrey Jul 13 '16 at 09:36
  • Oh really, sorry. This way your solution is `AtomicInteger`. Reading this would be useful http://stackoverflow.com/questions/25168062/why-is-i-not-atomic – antongarakh Jul 13 '16 at 09:40