简体   繁体   中英

java - concurrent updates to multiple objects

I am new in Java concurrency, I have a class holding data (doubles in the sample code below) that should be accessed with a get (like a Map), but with data stored internally in a array for performance reasons.

This run in a multithreaded environment and this index must be updated sometimes.

public class ConcurrencySampleCode {

    private static Object lock = new Object();

    private Map<String, Integer> map = ...
    private double[] array = ...

    public Double get(String id) {
        synchronized (lock) {
            Integer i = map.get(id);
            if (i == null) {
                return null;
            }
            return array[i];
        }
    }

    public void update() {
        Map<String, Integer> tmpMap = updateMap(...);
        double[] tmpArray = updateArray(...);
        synchronized (lock) { // should be atomic
            map = tmpMap;
            array = tmpArray;
        }
    }

}

I am not sure whether this code is correct or not? Also, is the synchronized keyword needed in the get function ?

Is there a better way of doing this ?

Thanks for your help

There's nothing wrong with your code, but you will need to use the volatile keyword on the map and the array to ensure all threads see the updated values immediately, and I'm not sure you want the lock to be static.

As an alternative you may want to check out the java.util.concurrent.atomic package. It has some handy thread-safe variable. For example you could move your map and array into their own class, then use the AtomicReference to store the object.

public class ConcurrencySampleCode {

    private AtomicReference<DoubleMap> atomicMap = new AtomicReference(new DoubleMap());

    //Inner class used to hold the map and array pair
    public class DoubleMap {
        private Map<String, Integer> map = ...
        private double[] array = ...
    }

    public Double get(String id) {
        DoubleMap map = atomicMap.get();
            ...
    }

    public void update() {
        Map<String, Integer> tmpMap = updateMap(...);
        double[] tmpArray = updateArray(...);
        DoubleMap newMap = new DoubleMap(tmpMap, tmpArray);
        atomicMap.set(newMap);
    }

}

There is a lot going on in concurrent programming, but for instance your update() method is faulty. In the current state multiple Threads can call ConcurrencySampleCode.update() and every each one of them will initiate both update calls inside the body before the synchronization kicks in. This means that after the round-robin turnover the last Thread with the update call will not have the changes from the previous update calls in the newly update map and array.

Long story, try to use and understand the ConcurrentHashMap

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM