1

Why the synchronizing on the count does not make it safe?

class Increment implements Runnable{
    static Integer count = new Integer(0);

    public void run(){
        for (int i = 0; i< 1_000_000; i++){
            synchronized (count){
                count ++;
            }

        }
    }

    public static void main(String[] args) throws InterruptedException {

        Thread one = new Thread(new Increment());
        Thread two = new Thread(new Increment());

        one.start();
        two.start();
        one.join();
        two.join();

        System.out.print(count);

    }
}

1555622

I know if I would put there some dummy object o like this

class Increment implements Runnable{
    static Integer count = new Integer(0);

    static Object o = new Object();
    public void run(){
        for (int i = 0; i< 1_000_000; i++){
            synchronized (o){
                count ++;
            }
        }    }

    public static void main(String[] args) throws InterruptedException {

        Thread one = new Thread(new Increment());
        Thread two = new Thread(new Increment());

        one.start();
        two.start();
        one.join();
        two.join();

        System.out.print(count);

    }
}

2000000

it would be safe. But I do not understand why it doesn't work on count itself

boucekv
  • 1,220
  • 2
  • 20
  • 47
  • 1
    Because the object changes every time you increment it, so different threads synchronize on a different object. BTW: You really shouldn't use `Integer` here. Use `int` and lock on an object. Or if you want atomic thread-safe increments, use an `AtomicInteger`. – Mark Rotteveel Mar 04 '22 at 12:50
  • 2
    one reason for having such a field (used for synchronization) declared as `final` – user16320675 Mar 04 '22 at 13:02

1 Answers1

3

Because the lock isn't on the variable, it's on the object. Integer is immutable, when you increment it you get a new object, and this replaces the object you're locking on. Each time a thread tries to enter a synchronized block, it evaluates the parenthesized expression to find what it should lock on.

That creates a situation where one thread has a lock on the old object and incoming threads lock on the new object, and you can have two threads in your synchronized block.

Your fixed solution works because the threads all share the same lock and it doesn't change.

Nathan Hughes
  • 94,330
  • 19
  • 181
  • 276