javathread-safetyatomicreference

A thread-safe holder for arbitrary cloneable data


I have a class SomeMutableData with a public clone() method. I want to make sure, that no thread ever sees an inconsistent state (assuming the instances will be passed around using the holder only). I assume using synchronization is the safest possibility, right?

public final class ThreadSafeHolder {
    public ThreadSafeHolder(SomeMutableData data) {
        storeData(data);
    }

    public synchronized SomeMutableData cloneData() {
        return data.clone();
    }
    public synchronized void storeData(SomeMutableData data) {
        this.data = data.clone();
    }

    private SomeMutableData data;
}

Is the following as safe as the first approach?

public final class ThreadSafeHolder2 {
    public ThreadSafeHolder2(SomeMutableData data) {
        storeData(data);
    }

    public SomeMutableData cloneData() {
        return data.get().clone();
    }
    public void storeData(SomeMutableData data) {
        this.data.set(data.clone());
    }

    private final AtomicReference<SomeMutableData> data
        = new AtomicReference<SomeMutableData>();
}

Solution

  • Since clone() is much more expensive than synchronized, it hardly matters from a performance point of view.

    However the second example is as thread safe and marginally faster.

    the only differences is that the first example you can do this. (Whether you like this or not ;)

    synchronized(theHolder) {
        SomeMutableData smd = theHolder.cloneData();
        smd.updateIt();
        theHolder.storeData(smd);
    }
    

    BTW: I don't think the holder should extend the type it is wrapping.

    EDIT: A more GC friendly way is to use the following approach. you can write copyFrom() such that no objects are created either setting or getting the data.

    public final class ThreadSafeHolder {
        private final SomeMutableData data = new SomeMutableData();
    
        public ThreadSafeHolder(SomeMutableData data) {
            copyFrom(data);
        }
    
        public synchronized void copyTo(SomeMutableData data) {
            data.copyFrom(this.data);
        }
    
        public synchronized void copyFrom(SomeMutableData data) {
            this.data.copyFrom(data);
        }
    }