javaarraysmultithreadingthread-safetythread-synchronization

How do I make an array threadsafe in Java?


I am pretty new to multithreading and want to understand it better. I want to now how to make an array threadsafe in Java? Meaning I have several threads accessing and changing the data in the array and I want to prevent one thread from changing the data, while the other thread is reading it.

My approach was the following: I have a Data class containing an array and two methods updateData(Integer[] data) and getUpdate() for accessing and manipulating the array.

public class  Data <T extends Comparable> {
    private T[] data;

    public T[] getUpdate() {
        synchronized (this) {
            return data.clone();
        }
    }

    public void updateData(T[] data) {
        synchronized (this) {
            this.data = data.clone();
        }
    }
}

This data object is now used in two different threads, the main thread which updates the data and the swing EDT thread which reads the data and uses it.

public static void main(String[] args) {
    Data<Integer> data = new Data<>();
    data.updateData(new Integer[]{1,2,3,4,5,6,7,8,10});


    SwingUtilities.invokeLater(() -> {
        ColumnVisualizer visualizer = new ColumnVisualizer();

        new Timer(100, e -> {
            visualizer.setData(data.getUpdate());
        }).start();
    });
    
    while(condition) {
        data.updateData(createNewData());

    }
}

As I understand it if I access the array only through the updateData() and getUpdate() methods, which I made threadsafe with the synchronized keyword, the data itself is threadsafe. Since if a thread calls the getUpdate() method it sets a lock on the Data instance and when another thread wants to call updateData() it can not access the part where the old array is replaced with the new one, until the Data instance is not longer looked on.

Have I understand it correctly and is this a convenient approach to make the array threadsafe in Java?


Solution

  • Your understanding is correct. The Data instance will be blocked until the synchronized block is finished in either one of the methods (getUpdate/updateData).

    Though, based on your code I have some observations, that might be useful for you. Let's assume that at timestamp time1, a thread, let's call it th1, comes and and calls getUpdate and fetches a clone of the data. Assuming that one millisecond later (or sooner) another thread, let's call I th2, gets the cloned data from the same method getUpdate. At this point both th1 and th2 have the same entries in data table. Assuming that after 4 milliseconds process of th1 updates the data by using the updateData and after 1 millisecond, process th2 calls the same method.

    Let's see what happened with this 2 processes: Right after the call of of updateData of th2, the data table will have whatever th2 placed there, having completely ignored what the th1 placed there 1 milisecond ago (process th1 is like never happened). Is this what you want ? I'm not saying it is wrong, I'm just saying it is what will happen if 2 process will use the table at pretty much the same time (with 1ms or less difference).

    If what you want is at the end of th2 the data table to contain information of both th1 and th2 you will probably need different approach. Eg. lock the table for a process, or use methods class Data to add/remove entries in the table without giving the whole table to a process to update it....