dpsdce
dpsdce

Reputation: 5450

Java threading and outputstream printinng issue

I am trying to create 5 different threads and try to print a static object in their run method every time incrementing the count of static variable by one

Here is the sample output of the program

pool-1-thread-1 Static Value before update 19
Thread going to sleep pool-1-thread-1
pool-1-thread-4 Static Value before update 19
Thread going to sleep pool-1-thread-4
pool-1-thread-3 Static Value before update 19
Thread going to sleep pool-1-thread-3
pool-1-thread-2 Static Value before update 19
Thread going to sleep pool-1-thread-2
pool-1-thread-5 Static Value before update 19
Thread going to sleep pool-1-thread-5
Thread coming out of sleep pool-1-thread-3  StaticTest.sInt 19
Thread coming out of sleep pool-1-thread-4  StaticTest.sInt 19
Thread coming out of sleep pool-1-thread-1  StaticTest.sInt 19
Thread coming out of sleep pool-1-thread-5  StaticTest.sInt 19
Thread coming out of sleep pool-1-thread-2  StaticTest.sInt 19

**pool-1-thread-5  OLD value 22 Static Value after update 23**
pool-1-thread-1  OLD value 21 Static Value after update 22
pool-1-thread-4  OLD value 20 Static Value after update 21
pool-1-thread-3  OLD value 19 Static Value after update 20
pool-1-thread-2  OLD value 23 Static Value after update 24

Now my question is since Thread 3 came out of the sleep first it must have been printed first, however its thread 5 which is printed first and that too with value 22 i.e the static variable was incremented by three times before thread 5 gets hold of it, but why i see a random order while i am printing the incremented values to me it should have been printed in the same order the one they came out of sleep i.e thread 3/4/1/5/2

please pour in thoughts ? What I am missing why the random behaviour once the thread are back to running state after sleep

package com.test.concurrency;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

public class StaticTest {

    public static Integer sInt = new Integer(19);

    public static void main(String[] args) {

        ExecutorService es = Executors.newCachedThreadPool();
        for (int i = 0; i < 5; i++) {
            es.execute(new StaticTask());
        }

    }

}

class StaticTask implements Runnable {

    public void run() {

        String name = Thread.currentThread().getName();
        System.out.println(name + " Static Value before update "
                + StaticTest.sInt);
        try {
            System.out.println("Thread going to sleep " + name);
            Thread.sleep(10);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.println("Thread coming out of sleep " + name + "  StaticTest.sInt " + StaticTest.sInt);

        int local = StaticTest.sInt;
        StaticTest.sInt = new Integer(local + 1);

        System.out.println(name + "  OLD value " + local +" Static Value after update "
                + StaticTest.sInt);

    }
}

Upvotes: 1

Views: 1199

Answers (6)

Debojit Saikia
Debojit Saikia

Reputation: 10632

Now my question is since Thread 3 came out of the sleep first it must have been printed first, however its thread 5 which is printed first and that too with value 22

As there are 5 threads running concurrently, so the order in which the given set of statements are executed is not predictable. Even if the threads were come out in the order 3/4/1/5/2, it is not guaranteed that the same order will be preserved while executing the rest of the statements. That is why it is called Asynchronous execution.

It might have happened that threads 3, 4, 1 executed the statements

int local =StaticTest.sInt;
StaticTest.sInt = new Integer(local + 1);

one after another (in any order) and then thread 5 got the opportunity to execute the statements at one go:

int local =StaticTest.sInt;
StaticTest.sInt = new Integer(local + 1);
System.out.println(name + "  OLD value " + local +" Static Value after update "
                + StaticTest.sInt);

and you have got this printed on the console:

pool-1-thread-5  OLD value 22 Static Value after update 23

as the value of static variable StaticTest.sInt might have been already updated to 22 by threads 3, 4, 1.

And you should always use synchronized access to shared variables, so that changes made by one thread is visible to others and also with synchronized access, operations on shared variables are atomic:

public static synchronized Integer incrementSInt() {
    return StaticTest.sInt++;
}

Upvotes: 0

sanbhat
sanbhat

Reputation: 17622

From the output, its clear that thread-3 is the one which woke up first (Yes, you are right) and then incremented the static int

pool-1-thread-5  OLD value 22 Static Value after update 23
pool-1-thread-1  OLD value 21 Static Value after update 22
pool-1-thread-4  OLD value 20 Static Value after update 21
pool-1-thread-3  OLD value 19 Static Value after update 20  --> static counter incr. from 19 to 20
pool-1-thread-2  OLD value 23 Static Value after update 24

In the above print statements, it is clear from the values they are printing that, the thread which woke up first, is doing increment and printing the value.

What is unpredictable is the print sequence.

If you think at low level, System.out.print statements are Asynchronous, thus the output

Upvotes: 0

Dariusz
Dariusz

Reputation: 22241

Chapters 17.4.3-5 in Java Language Specification 7 deal with what kinds of actions are subject to the happen-before rule and, in general, what can be expected of a multithreaded application's execution order.

Once you read those chapters, you will realize that there is fairly few guarantees to the execution sequence. What we may consider natural and take for granted is often invalid in case of multithreaded applications.

Moreover, there is the memory model - you access the variable sInt without synchronization. That way, you have no guarantee that the different threads will ever notice that the object reference has been changed. You have to use a common lock between the objects/threads that modify the variable to make sure it's change is even visible.

You can do it with synchronized block and a static object lock:

// in class:
static Object lock = new Object();


// in run():
synchronized(lock) {
    int local =StaticTest.sInt;
    StaticTest.sInt = new Integer(local + 1);
    System.out.println(name + "  OLD value " + local +" Static Value after update "
        + StaticTest.sInt);
}

That way the prints in synchronized will be ordered properly.

Upvotes: 1

QYuan
QYuan

Reputation: 1

The thread which is scheduled is depend on operating system,these threads have time slice

Upvotes: 0

MadConan
MadConan

Reputation: 3767

You should read up on concurrency in Java. You should never expect threads to run in any specific order -- especially without synchronizing code around a shared resource. Might want to start here.

Upvotes: 0

Sadek Noureddine
Sadek Noureddine

Reputation: 577

You have no control or deterministic way of knowing which one will execute first, simply because you started the thread first doesn't mean that it will run first...

You are executing 5 threads in a loop, but no guarantee that the first will run first, 2nd run 2nd, and so on...

If you do want your threads to run in a specific order, you would have to do some join or wait/notify logic.

Upvotes: 1

Related Questions