Method vs Class Variables When Multithreading

I had to recently refresh my memory of basic computer science, so I'll note it here as well. While executing a method on a shared object across threads, we need not concern ourselves with races manipulating the variables declared within the method. All the method variables are created on a separate chunk of the stack for each invocation.

Class variables on the other hand are not pushed onto the stack for each method invocation on a shared object, so access to these do need to be synchronized.

Method variables within static methods do not offer any exceptions, they are still pushed onto the stack, hence isolated from other concurrent invocations. Static methods may only access class variables that are static as well, so it should be noted that these static class variables are shared even more widely -- across all instances of this class.

I used this test code to prove this behavior to myself:

import java.io.*;
import java.util.*;

public class Test implements Runnable {
    Test callback;
    String name;
    int sleep;
    String shared;

    public static void main(String[] args) {
        new Test();
    }

    public Test() {
        Runnable r1 = new Test(2000, "t1", this);
        Runnable r2 = new Test(2000, "t2", this);

        Thread t1 = new Thread(r1);
        Thread t2 = new Thread(r2);

        t1.start();
        try {
            Thread.sleep(1000);
        } catch (Exception ex) {
            ex.printStackTrace();
        }
        t2.start();
    }

    public Test(int s, String n, Test cb) {
        sleep = s;
        name = n;
        callback = cb;
    }

    public void doIt(int sleep, String value) {
        System.out.println(value + " started and set values to "
            + value);
        String ret = value;
        shared = value;
        try {
            Thread.sleep(sleep);
            System.out.println(value + " sleeping");
        } catch (Exception ex) {
            ex.printStackTrace();
        }
        System.out.println(value + "'s local ret: " + ret);
        System.out.println(value + "'s shared: " + shared);
    }

    public void run() {
        callback.doIt(sleep, name);
    }
}

The output is:

t1 started and set values to t1
t2 started and set values to t2
t1 sleeping
t1's local ret: t1
t1's shared: t2
t2 sleeping
t2's local ret: t2
t2's shared: t2


Filed Under: