Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

AtomicInteger doesn't increment concurrently

I am testing the use of the class AtomicInteger but increments doesn't seem to be applied under mutual exclusion control.

Here's my test:

static class AtomicIntegerRunnable implements Runnable
{
    private static AtomicInteger x;

    AtomicIntegerRunnable() {}

    AtomicIntegerRunnable(AtomicInteger x) 
    {
        this.x = x;
    }

    @Override
    public void run()
    {
        System.out.println(x.get());
        x.getAndIncrement();
    }
}

public static void main(String[] args) {
    ExecutorService e = Executors.newFixedThreadPool(n_whatever);
    AtomicInteger x = new AtomicInteger();
    int n = 10;
    for (int i=0; i<n; i++) {
        e.submit(new AtomicIntegerRunnable(x));
            }
    e.shutdown();
    while (!e.isTerminated());
}

In the print I am getting something like

0 0 1 1 1 5 4 3 2 6

instead of

0 1 2 3 4 5 6 7 8 9

. What's wrong?

EDIT for @Louis Wasserman

static class AtomicIntegerRunnable implements Runnable
{
    private AtomicInteger x;

    AtomicIntegerRunnable() {}

    AtomicIntegerRunnable(AtomicInteger x) 
    {
        this.x = x;
    }

    @Override
    public void run()
    {
        x.getAndIncrement();
    }
}

public static void main(String[] args) 
{
    ExecutorService e = Executors.newFixedThreadPool(n_whatever);
    AtomicIntegerRunnable x = new AtomicIntegerRunnable(new AtomicInteger());
    int n = 10;
    for (int i=0; i<n; i++) 
        e.submit(x);
    e.shutdown();
    while (!e.isTerminated());
}
like image 949
dabadaba Avatar asked Dec 19 '22 19:12

dabadaba


1 Answers

You are getting it and incrementing it in two separate actions. You are printing out the first, which makes your own code non-atomic.

Each AtomicInteger operation is atomic on its own, but you cannot use two in sequence and consider the combination atomic -- by defintion, two operations are not atomic.

To fix this:

@Override
public void run()
{
    System.out.println(x.getAndIncrement());
}

However, as pointed out in the comments, you have a third action, the printing. This is also not atomic with the increment action. So, you would need to synchronize the two in order to make your list print out in order.

You could call that method printAndIncrement.

Usually AtomicInteger is used more to ensure that multithreaded code never accidentally operates on the same integer, not to ensure that an external system (like an output buffer) sees those increments in order (because you still need something else to synchronize communication with that external system).

like image 124
Nicole Avatar answered Jan 01 '23 22:01

Nicole