0

要编写一个功能齐全的 Java 对象池,使用 READ/WRITE 锁并不是什么大问题。我看到的问题是 READ 操作必须等到存储监视器(或类似的东西,取决于模型)被释放,这真的减慢了它。

因此,应满足以下要求:

  1. READ(或 GET)操作应该是 INSTANT - 使用一些键,应该立即返回对象的最新版本,而不需要等待任何锁。

  2. WRITE (CREATE/UPDATE) - 可能被排队,合理地延迟时间,可能等待一些存储锁。

任何代码示例?


我没有找到直接针对该问题的问题。

它出现在一些讨论中,但我找不到一个完全致力于在 Java 中创建这样一个池的问题。

4

3 回答 3

0

在这种情况下,您可以简单地使用 volatile 变量来避免在读取器端锁定并使用synchronized方法保持写入独占。volatile几乎不会增加读取开销,但写入会有点慢。根据预期的吞吐量和读/写比率,这可能是一个很好的解决方案。

class Cache {
    private volatile Map<K, V> cache; //Assuming map is the right data structure

    public V get(K key) {
        return cache.get(key);
    }

    //synchronized writes for exclusive access
    public synchronized void put(K key, V value) {
        Map<K, V> copy = new HashMap<> (cache);
        V value = copy.put(key, value);
        //volatile guarantees that this will be visible from the getter
        cache = copy;
        return value;
    }
}
于 2013-04-01T09:51:35.310 回答
0

Here is a totally-lock-free Java object pool solution. FYI

http://daviddengcn.blogspot.com/2015/02/a-lock-free-java-object-pool.html

于 2015-02-24T16:00:55.747 回答
0

当对数据结构的修改花费太长时间(无论出于何种原因)时,简单地等待和写锁定结构将不会成功。您只是无法预见何时有足够的时间在不阻塞任何读取的情况下执行修改。

您唯一能做的(尝试做的)就是将写操作中的时间减少到最低限度。正如@assylias 所说, CopyOnWrite* 通过在写入操作时克隆数据结构来做到这一点,并在操作完成时自动激活修改后的结构。

这样,读锁将花费克隆操作的持续时间加上切换引用的时间。您可以将其缩小到数据结构的一小部分:如果仅对象中的状态发生更改,则可以修改该对象的副本,然后将更复杂的数据结构中的引用更改为该副本。

另一种方法是在读取操作之前或之前进行复制。无论如何,您通常都会通过数据结构的 API 返回对象的副本,因此只需“缓存”该副本并在修改期间让读者访问缓存的副本。这也是数据库缓存所做的。

这取决于您的型号,什么最适合您。如果您对可以轻松复制的数据的写入很少,则 CopyOnWrite 可能会执行得最好。如果您将有大量写入,您可能最好提供结构的单个“读取”/缓存状态并不时切换它。

AtomicReference<Some> datastructure = ...; 

//copy on write

synchronized /*one writer*/ void change(Object modification) 
throws CloneNotSupportedException {
   Object copy = datastructure.clone();
   apply(copy, modification);
   datastructure.set(copy);  
}

Object search(Object select) {
   return datastructure.get().search(select);
}

// copy for read

AtomicReference<Some> cached = new AtomicReference<Some>(datastructure.get().clone());

synchronized void change(Object modification) {
    apply(datastructure, modification);
    cached.set(datastructure);
}

Object search(Object select) {
    return cached.get().search(select);
}

对于这两种操作,读取时无需等待 .. 但需要切换参考。

于 2013-04-01T09:17:55.427 回答