gg tty
gg tty

Reputation: 51

unexpected answers in multithreading in java

This is my code that sum variable 'res' by one 4*10^7 time using 4 threads:

class MathSin extends Thread {

    public double a;

    public MathSin(int degree) {
        a = degree;
    }

    @Override
    public void run() {

        for (int i = 0; i < Math.pow(10., 7); i++)
            MathThreads.res++;

    }
}

class MathThreads {
    public static double res = 0;

    public static void main(String args[]) {
        MathSin st = new MathSin(8);
        MathSin ct = new MathSin(8);
        MathSin tt = new MathSin(8);
        MathSin qt = new MathSin(8);
        st.start();
        ct.start();
        tt.start();
        qt.start();
        try { // wait for completion of all thread and then sum
            st.join();
            ct.join(); // wait for completion of MathCos object
            tt.join();
            qt.join();
            System.out.println(res);
        } catch (InterruptedException IntExp) {
        }
    }
}

and these are some of answers :

1.8499044E7

2.3446789E7
.
.
.

I expected get 3.0E7 but get another different answers.

how can fix this problem?

Upvotes: 0

Views: 100

Answers (1)

Jean Logeart
Jean Logeart

Reputation: 53819

What is the problem?

You are observing race conditions while updating the static variable res.

MathThreads.res++

is equivalent to:

double tmp = MathThreads.res;
MathThreads.res = tmp + 1;

Now what happened if two threads reads at the same time a value for tmp, and both update res with tmp + 1? Well, one increment has simply been forgotten: res ends being tmp + 1 instead of being tmp + 1 + 1!

So with 4 threads updating res concurrently, you simply end up with an undefined behavior : it is impossible to predict the final value of res because of those race conditions. Two executions of the same code will give you different answers.

How to solve this issue?

To make your code thread-safe, you need to use a thread-safe structure for res: a structure that can be concurrently updated and accessed.

In your case, an AtomicLong seems the perfect choice:

public static AtomicLong res = new AtomicLong(0);

And in the run method:

for (int i = 0; i < Math.pow(10., 7); i++) {
    MathThreads.res.incrementAndGet();
}

Upvotes: 5

Related Questions