-1
package workouts;

public class synchro {

    private int count = 0;

    public void counting() {

        Thread T1 = new Thread(new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 10000; i++) {

                    count++;
                }
            }
        });

        Thread T2 = new Thread(new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 10000; i++) {

                    count++;
                }
            }
        });

        T1.start();
        T2.start();

        try {
            T1.join();
            T2.join();
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

        System.out.println("counting =" + count);
    }

    public static void main(String[] args) {

        synchro sync = new synchro();

        sync.counting();
    }
}

but when introduced a synchronised method and call it inside run method like below.. the output is 20000 for how many times if u run it..can someone explain the difference between the above and below code

public class synchro {

    private int count = 0;

    public synchronized void dosinglethread(){
        count++;
    }

    public void counting() {

        Thread T1 = new Thread(new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 10000; i++) {
                    dosinglethread();
                }
            }
        });

        Thread T2 = new Thread(new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 10000; i++) {

                    dosinglethread();
                }
            }
        });

        T1.start();
        T2.start();

        try {
            T1.join();
            T2.join();
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

        System.out.println("counting =" + count);
    }

    public static void main(String[] args) {
        synchro sync = new synchro();

        sync.counting();
    }
}
beresfordt
  • 5,088
  • 10
  • 35
  • 43
sritharan
  • 41
  • 1
  • 10
  • why volatile keyword didnt work on the variable ?? – sritharan Feb 20 '15 at 08:12
  • with such trivial threads, the first one would probably finish before the second one has started up. – Scary Wombat Feb 20 '15 at 08:19
  • @sritharan I don't really see where did you use `volatile` in your code... – Nir Alfasi Feb 20 '15 at 08:23
  • 1
    I assume he meant making the line "private volatile int count = 0;" in the op of the first example. This does not help ensure the proper count. The question is why? The answer is provided by DennisW -- the variable count may be volatile, the one needs the entire operation (fetch, increment, assign) to be synchronize, not just the variable. – Phil Freihofner Feb 20 '15 at 09:26
  • @alfasin i ment that if we use private volatile int count = 0; instead of using public synchronized void dosinglethread(){ count++; } – sritharan Feb 20 '15 at 12:00

1 Answers1

1

When you say count++, three things happen:

  1. The current value of count is retrieved by the VM
  2. The VM increments the value by 1
  3. The new value is put back into count

It's entirely possible that T1 and T2 both get the value of count, then increment it separately, and then but back the result, like so:

Timeslot    T1                    T2
1           count = 3             ----
2           ----                 count = 3
3           3 + 1 = 4            ----
4           ----                 3 + 1 = 4
5           store 4 in count     ----
6           ----                 store 4 in count

So now, count++ has been called twice, but the value has only increased by one. To prevent this, you have to make the increment atomic. Atomic means that either the entire sequence of operations is executed, or none of it is. Simply put, if two statements are synchronized on the same Object, they will not interleave.

In your second piece of code, dosinglethread() is declared synchronized. This is the equivalent of:

public void dosinglethread() {
    synchronized (this) {
        count++;
    }
}

This means that when one of the threads starts executing it, they acquire a lock on your synchro instance. When the second thread also tries to execute the method, it will see that another thread already owns the lock on this, so it has to wait. When the first thread completes the method, it will release the lock and the other thread can then take it.

So why didn't volatile work? volatile variables will not cause threads to wait until they are available. Instead, when count is volatile and you call count++, the following happens: (Code adapted from Javamex's Tutorial)

int temp;
synchronized (count) {
  temp = count;
}
temp = temp + 1;
synchronized (count) {
  count = temp;
}

Note that this code is for illustration only: synchronized can not be used on primitives.

It's clear, then, that the threads might still be paused at temp = temp + 1, giving the same problems as when you don't do any synchronization.

For more information, check the tutorial I mentioned.

DennisW
  • 1,057
  • 1
  • 8
  • 17