在并发环境中更新高度读取的列表/映射

时间:2012-06-19 10:25:11

标签: java concurrency assignment-operator

以下类充当一个简单的缓存,它很快就会更新(例如每天两次),并且可以读取很多(每秒最多几次)。有两种不同的类型,ListMap。我的问题是关于在update方法中更新数据后的新分配。新数据应用的最佳(最安全)方式是什么?

我应该补充一点,读者没有必要看到绝对的最新价值。要求只是在任何给定时间获得旧值或新值。

public class Foo {

    private ThreadPoolExecutor _executor;
    private List<Object> _listObjects = new ArrayList<Object>(0);
    private Map<Integer, Object> _mapObjects = new HashMap<Integer, Object>();
    private Object _mutex = new Object();
    private boolean _updateInProgress;

    public void update() {

        synchronized (_mutex) {
            if (_updateInProgress) {
                return;
            } else {
                _updateInProgress = true;
            }
        }

        _executor.execute(new Runnable() {

            @Override
            public void run() {
                try {
                    List<Object> newObjects = loadListObjectsFromDatabase();
                    Map<Integer, Object> newMapObjects = loadMapObjectsFromDatabase();

                    /*
                     * this is the interesting part
                     */
                    _listObjects = newObjects;
                    _mapObjects = newMapObjects;

                } catch (final Exception ex) {
                    // error handling
                } finally {
                    synchronized (_mutex) {
                        _updateInProgress = false;
                    }
                }
            }
        });
    }

    public Object getObjectById(Integer id) {
        return _mapObjects.get(id);
    }

    public List<Object> getListObjects() {
        return new ArrayList<Object>(_listObjects);
    }


}

如您所见,目前不使用ConcurrentHashMapCopyOnWriteArrayList。唯一的同步是在update方法中完成的。

虽然对于我目前的问题不是必需的,但是对于读者总是获得绝对最新价值的情况知道最佳解决方案也是很好的。

2 个答案:

答案 0 :(得分:1)

除非您每秒阅读超过10,000次,否则您可以使用计划同步。

如果你想要并发访问,我会使用并发集合,如ConcurrentHashMap或CopyOnWriteArrayList。这些比同步集合更简单。 (即出于性能原因你不需要它们,为简单起见使用它们)

BTW:一个现代化的CPU可以在0.1秒内执行数十亿次操作,因此计算机每秒可以进行数次操作。

答案 1 :(得分:0)

我也看到了这个问题并想到了多种解决方案:

  1. 在两个代码上使用同步块,一个用于读取,另一个用于写入。
  2. 制作单独的删除列表,添加该列表中的所有可移动项目。在阅读完成后读取列表的同一个线程中删除。这样,读取和删除将按顺序发生,不会出现错误。