Search code examples
javamultithreadingthread-safetyglobal-variables

Java : updates to variables before and after Thread.start()


I have two classes

classA {
    private ArrayList<String> list = new ArrayList();

    void addString(String s){
        list.add(s);
    }

    void start(){
        new ClassB(list).start();
    }
}

classB extends Thread{
    ArrayList<String> s;
    
    public ClassB(ArrayList<String> s) { this.s = s; }
    
    void run(){
        for (String s1 : s){
        // print s1
        }
    }
}

Now when I write code as

ClassA A = new ClassA();
A.addString("1");
A.addString("2");
A.addString("3");
A.start();

I want run() in classB to print all elements in list. i.e (1, 2, 3) in this case.

Is this always default or do we need to do apply multi threading concepts to make it happen?

What if list is non-volatile? Can new thread see all the elements (1,2,3)

What if I add another element after A.start() (say A.addString("4") ), then what should I do to make new thread print all 4 elements?


Solution

  • If you add all elements before starting the other thread (ClassB) it is safe. The JLS §17.4.4 says:

    An action that starts a thread synchronizes-with the first action in the thread it starts.

    And synchronizes-with is defined in §17.4.5.:

    If an action x synchronizes-with a following action y, then we also have hb(x, y).

    (hb(x, y) = x happens-before y)

    So this guarantees that adding the elements happens-before reading and printing the elements.

    However, with your current code, if you add elements from the main thread after you started the other thread, then you will have no thread-safety guarantees and the behavior is undefined. The other thread might see the added elements, but it could also not see them or possibly even throw an exception because it sees the data of the ArrayList in an inconsistent state.


    What if I add another element after A.start() (say A.addString("4") ), then what should I do to make new thread print all 4 elements?

    This is difficult to answer with your example code because it is not clear how the code should behave:

    • Should the other thread (ClassB) wait indefinitely for new elements? Then one solution could be using a BlockingQueue or using some sort of signaling and using a thread-safe collection (or synchronizing access to the ArrayList) is required.
    • Is the other thread (ClassB) allowed to miss the new elements in case it has finished printing the old elements before the new ones are added? Then only using a thread-safe collection (or synchronizing access to the ArrayList) is necessary.
    • ...