简体   繁体   English

java-并发更新多个对象

[英]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. 我是Java并发的新手,我有一个类,该类包含一个数据(在下面的示例代码中为双精度),应该使用get(如Map)进行访问,但是出于性能方面的考虑,这些数据会内部存储在数组中。

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 ? 另外,在get函数中是否需要synced关键字?

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. 您的代码没有错,但是您将需要在地图和数组上使用volatile关键字,以确保所有线程都能立即看到更新后的值,而且我不确定您是否希望锁是静态的。

As an alternative you may want to check out the java.util.concurrent.atomic package. 或者,您可能需要检出java.util.concurrent.atomic软件包。 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. 例如,您可以将地图和数组移到它们自己的类中,然后使用AtomicReference来存储对象。

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. 并发编程中发生了很多事情,但是例如您的update()方法有问题。 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. 在当前状态下,多个Threads可以调用ConcurrencySampleCode.update()并且它们中的每个Threads都将在同步开始之前在体内启动两个update调用。这意味着在循环更新之后,具有更新调用的最后一个Thread将在新的更新映射和数组中没有与先前update调用的更改。

Long story, try to use and understand the ConcurrentHashMap 长话短说,尝试使用和了解ConcurrentHashMap

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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