Do I need to make an elementary variable mutable?

To experiment with multithreading concepts, I implement my own version of AtomicInteger, which uses pessimistic locking. It looks something like this:

public class ThreadSafeInt {
    public int i; // Should this be volatile?

    public ThreadSafeInt(int i) {
        this.i = i;
    }

    public synchronized int get() {
        return i;
    }

    public synchronized int getAndIncrement() {
        return this.i++;
    }
    // other synchronized methods for incrementAndGet(), etc...
}

I wrote a test that takes an instance of ThreadSafeInt, passes it to hundreds of threads, and each of these threads calls getAndIncrement 100,000 times. What I see is that all increments occur correctly, and the value of integers is equally accurate (number of threads) * (number of increments per thread), although I do not use volatile for a primitive instance variable i. I expected that if I had not done ivolatile, then I would have visibility problems, where, for example, stream 1 increases ifrom 0 to 1, but stream 2 still sees the value 0, and also only increases it 1, causing the final value, which is less than the correct value.

, , , , . , volatile - .

? - (, , ..), , volatile?

+4
1

volatile i. , , , , .

getAndIncrement() get() synchronized, , i, , . synchronized i volatile, .

, AtomicInteger , volatile int. AtomicInteger getAndIncrement() synchronized, , .

public final AtomicInteger i = new AtomicInteger();
...
// no need for synchronized here
public int get() {
    return i.get();
}
// nor here
public int getAndIncrement() {
    return i.getAndIncrement();
}

, , , 1 0 1, 2 0, 1, , , .

get() synchronized, , i. synchronized . synchronized , i++. AtomicInteger .

, synchronized, , , volatile. synchronized, , volatile. synchronized , , , .

+5

Source: https://habr.com/ru/post/1673192/


All Articles