Jörg Vollmer
Jörg Vollmer

Reputation: 198

Are local variables thread safe?

there have been already similar questions, but it doesn't answer the following problem. It's well known that values of fields are not necessarily immediately synchronized between threads. But is this also the case with local variables? Can the IllegalStateException be thrown?

public static void main(String[] args) {
    final Thread mainThread = Thread.currentThread();
    final Integer[] shared = new Integer[1];

    new Thread(new Runnable() {
        @Override
        public void run() {
            shared[0] = 1;
            mainThread.interrupt();
        }
    }).start();

    try {
        Thread.sleep(1000);
    } catch (InterruptedException e) {
        if (shared[0] == null) throw new IllegalStateException("Is this possible?");
    }
}

Upvotes: 0

Views: 1681

Answers (6)

Maouven
Maouven

Reputation: 350

The local variables are stored in the stack and not in the heap, so they are thread safe

Upvotes: 0

meriton
meriton

Reputation: 70584

Indeed, the value of shared will be the same for all threads. But the value of shared[0] also involves reading an array element, and that array element, like a field, may be subject to a data race.

Are you sure about shared being safe?

Yes, the Java Language Specification writes:

Local variables (§14.4), formal method parameters (§8.4.1), and exception handler parameters (§14.20) are never shared between threads and are unaffected by the memory model.

At the JVM level, each thread has its own local variables. If an anonymous class accesses a local variable of an enclosing method, the compiler rewrites this code to pass the value of the variable as a constructor parameter to the inner class, which will store it in a final field (this rewriting is why the compiler requires such a variable to be effectively final and definitely assigned), and replaces all accesses to this variable by an access to the final field. Due to the special guarantees the Java Memory Model gives for final fields, this access is safe even if it the object reference is published through a data race, provided that such publication only occurs after the object has completed construction.

Upvotes: 6

Durandal
Durandal

Reputation: 20069

Local variables are perfectly thread safe, because there is no way to share them with another thread in the first place.

Your example code is a wholly different beast, because you are actually asking about the value of a shared array referred to by a local variable. Thats two different things. The variable is perfectly safe (cannot change anyway, since its final), the contents of the array it refers to is not synchronized in any way, so its also not safe.

Edit: To elaborate a bit about your variable named "shared" When you declare a local variable as final, java allows you to refer to that variable in the scope of an anonymous class defined within the visibility scope of said variable (Put simpler: from within the block where the variable was defined).

What looks like one variable, are actually two variables. The one you declared exists in the main thread. The moment the anonymous "new Runnable()" is created, a copy of the variable contents is made (it actually becomes a hidden final field in the anonymous class). So when you refer to "shared" within the run()-method you do not access the local variable "shared" in the main thread.

You can verify this by looking at the class files your example creates (there are two, one for the class, and one for the anonymous class) and use javap -v for both to have a look at the byte code generated.

Upvotes: 3

JJF
JJF

Reputation: 2777

shared is thread safe, its the state of the object it refers to thats not safe.

It's possible your main thread could throw that exception but highly unlikely.

Telling the anonymous thread start() does not necessarily mean the VM/OS will actually start your thread before the next part of the program executes. So your main thread could enter the sleep before the other thread even starts. If it got interrupted from an external event inside that sleep before the thread set the value you could end up with null.

The sleep on the main thread almost positively ensures the anon thread will run before the test of shared.

Think about what would happen if you removed the sleep and checked for null immediately after starting the new thread. On my system shared[0] was null about 50% of the times I ran your program modified to have the sleep removed.

public static void main(String[] args) {
        final Thread mainThread = Thread.currentThread();
        final Integer[] shared = new Integer[1];

        new Thread(new Runnable() {
            public void run() {
                shared[0] = 1;
                mainThread.interrupt();
            }
        }).start();

        if (shared[0] == null)
            System.out.println("ouch");

    }

Upvotes: 0

Avi
Avi

Reputation: 567

Yes, local variables are thread safe because the are allocated in the stack. Threads, however, don't share the stack. They are unique for each variable.

Upvotes: 0

markspace
markspace

Reputation: 11030

Local variables that are visible to more than one thread are not thread safe. They have to be accessed through the regular mechanisms (synchronized, volatile, immutable, etc.).

Normally, you create a local variable and use it within one thread. When you are ready, you must Safely Publish that variable. After that point, all the normal thread safe mechanisms must apply.

Upvotes: 0

Related Questions