Vijay
Vijay

Reputation: 21

incrementing a static variable thru' 100 different threads without synchronisation, yet getting the final result as 100

I'm incrementing a static variable thru' 100 different threads without synchronisation, yet getting the final result as 100. I've run this code several times and have got same result. Does my code then not require synchronisation? I'm using BlueJ IDE to run the code

    public class Main {
        private final static int MAX_THREADS = 100;
        public static void main(String[] args) {
            Thread[] threads = new Thread[MAX_THREADS];

            for(int i=0; i<MAX_THREADS; i++) {
                threads[i] = new Thread(new Job(), "Thread-" + i);
                threads[i].start();
                try{
                    Thread.sleep((int)(Math.random() * 1000));
                }catch(InterruptedException e) {
                    e.printStackTrace();
                }
            }

            for(int i=0; i<MAX_THREADS; i++) {
                try {
                    threads[i].join();
                }catch(InterruptedException e) {
                    e.printStackTrace();
                }
            }
            System.out.printf("Final Value: %d\n", Job.getSuccessCount());
        }

    }

    public class Job implements Runnable {
        private  static int successCount;

        public  static int getSuccessCount() {return successCount;}

        @Override
        public void run() {
            System.out.printf("%s: Incrementing successCount %d\n", Thread.currentThread().getName(), successCount);
            try{
                Thread.sleep((int)(Math.random() * 10000));
            }catch(InterruptedException e) {
                e.printStackTrace();
            }
            successCount++;
            System.out.printf("%s: Incrementing Complete %d\n", Thread.currentThread().getName(), successCount);
        }
    }

Upvotes: 0

Views: 317

Answers (4)

user207421
user207421

Reputation: 310883

If you do the sums you'll see that you have an average of ten threads running at the same time, all sleeping for an average of five seconds and then doing an increment. So on average the increments won't be closer together than half a second, and the fact their starting is also spaced out by an average of half a second makes that a full second on average. There is essentially no concurrency here at all.

Upvotes: 0

Dean Leitersdorf
Dean Leitersdorf

Reputation: 1341

Your code currently doesn't need synchronization, as no two treads access the same variable at the same time. In other words, only 1 thread in your application is incrementing the variable.

In this case, it is due to the fact that incrementing the variable takes less than Math.random() *1000. Why is it so? Let's observe the threads:

Main Thread:

  1. Launches and starts a thread
  2. Executes both Math.random() and Thread.sleep()
  3. Loops again

While the main thread is doing step 2, the new thread is:

  1. Incrementing variable
  2. Going to sleep

In this case, once the new thread goes to sleep, it just is killed right after, therefore, for our purpose we can regard it as if the thread terminates right after step 1, as it stops affecting the variable (it has no influence on the variable after step 1).

In order for a synchronization problem to occur, two new threads need to access the variable at once. For this to happen, main thread must launch a new thread before the first new thread finishes incrementing. For that to happen, main thread must be faster in: executing Math.random(), Thread.sleep(), and creating a new thread, all before the other thread finishes incrementing. This is obviously not the case, and thus no 2 threads will increment at once, and no synchronization error will occur.

Upvotes: 0

shazin
shazin

Reputation: 21883

Adding to Wombat's Answer. The final result will always be 100 because you do a Unary Operation after The Sleep in Job class. Basically the read-modify-write commands can run sequentially per Job if the Java Scheduler didn't change the status of the Thread while performing the following.

successCount++

But if you change the Job source code to read-sleep-modify-write then you will definitely see stale value as following.

public class Job implements Runnable {
    private  static int successCount;

    public  static int getSuccessCount() {return successCount;}

    @Override
    public void run() {
        System.out.printf("%s: Incrementing successCount %d\n", Thread.currentThread().getName(), successCount);
        int sc = successCount; // Read
        try{
            Thread.sleep((int)(Math.random() * 10000)); // Sleep
        }catch(InterruptedException e) {
            e.printStackTrace();
        }
        successCount = sc++; // Modify-Write
        System.out.printf("%s: Incrementing Complete %d\n", Thread.currentThread().getName(), successCount);
    }
}

With this 2 Threads can read and then sleep and then wake up and write the same value to successCount overwriting the original value.

Upvotes: 0

Scary Wombat
Scary Wombat

Reputation: 44834

Basically in you code, due to the sleep statements (both in the Thread and by the launcher), you are effectively kicking off the threads allowing for plenty of non busy time to update. That is why it is working. If you code was really multi-threaded, the you would face synchronization issues.

Upvotes: 2

Related Questions