Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Thread and static variables

Trying to wrap my head around this code. When I run this - the output will be Roger. Isn't msg a static variable and at a class level thus should print Moore?

EDIT : I've allowed a sleep too allow the child thread to run its course. It also prints printing... Still No Change

public class Test2 {
    private static String msg = "Roger";

    static {
        new Thread(new Runnable() {
            public void run() {
                System.out.println("printing.."); 
                msg += "Moore";
            }
        }).start();
    }

    static {
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
        }
    }

    public static void main(String argv[]) {
        System.out.println(msg); 
    }
}
like image 275
user2796381 Avatar asked Dec 21 '25 05:12

user2796381


1 Answers

Trying to wrap my head around this code. When I run this - the output will be Roger. Isn't msg a static variable and at a class level thus should print Moore?

As others have pointed out, this is a race condition but it's more complicated then this simple answer.

EDIT : I've allowed a sleep too allow the child thread to run its course. It also prints printing... Still No Change

When a class is initialized, the static code is executed in the thread that accesses the class first – in this case the main thread. All other threads have to wait for this initialization to complete before they can access the class. This means that the background thread actually stops and waits for the class initialization to complete before it can execute msg += "Moore";. Then it is a race to see whether the msg is assigned to "Roger" and the background thread can append to it before main prints it. Even with the msg field being volatile, the race still exists. You can get a glimpse into the complexities of the process from the JLS section 12.4.2 on Detailed Initialization Procedure.

So what is happening is approximately:

  1. The main thread initializes the Test2 class.
  2. The msg is initialized first because it comes before the static blocks.
  3. First static block is executed which forks the background thread.
  4. Second static block is executed which does the sleep() blocking the initializing thread.
  5. Background thread starts to run (could be before the previous step). It goes to update msg but the class is locked since the main thread is sleeping and hasn't completed with the class initialization. The background thread has to wait.
  6. The main thread wakes up and finishes the initialization.
  7. This releases the block on the class which allows the background thread to continue.
  8. At the same time as the previous step, main is called and it is a race condition to see if the msg can be updated before it is printed out.

In general, forking background threads in static methods like this is extremely frowned upon. Putting a sleep in a static block is obviously not recommended as well.

like image 60
Gray Avatar answered Dec 23 '25 18:12

Gray



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!