4

いくつかのデータを含む2つのハッシュマップを含むクラスがあります。マップ内のデータを毎晩(Quartzジョブを使用して)更新/再読み込みし、データ更新プロセス中に他のすべてのスレッドが読み取れないようにロックしたいと思います。

 public class A {

    private Map<String, Object> someMap1 = new ConcurrentHashMap<String, Object>();
    private Map<String, Object> someMap2 = new ConcurrentHashMap<String, Object>();

    public void reloadData() {
        someMap1.clear();
        someMap2.clear();

        // read new data here and re-fill the maps
        ...
    }

    public Object getDataFromMap(String key) {
        // do some logic here and return data from map
        return someObj;
    }
 }

getDataFromMap()メソッドは、データの更新が進行中でない場合にブロックすることなく、すべての「リーダー」スレッドからアクセスできる必要があります。

一方、reloadData()メソッドは、すべての「リーダー」が完了するのを待ってから、マップによるデータの読み取りとリロードをブロックする必要があります。

reloadData()の「同期」修飾子は、getDataFromMap()ロジックで進行中の場合、すべてのクラスとすべての「リーダー」をブロックするため、解決策ではありません。

4

3 に答える 3

6

要件はReentrantReadWriteLockに完全に適合します

    private Map<String, Object> someMap1 = new ConcurrentHashMap<String, Object>();
    private Map<String, Object> someMap2 = new ConcurrentHashMap<String, Object>();
    private final ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();
    private final Lock r = rwl.readLock();
    private final Lock w = rwl.writeLock();

    public Object getDataFromMap(String key) {
        r.lock();
        try {
            // do some logic here and return data from map
            return someObj;
        } finally {
            r.unlock();
        }
    }

    public void reloadData() {
        w.lock();
        try {
            someMap1.clear();
            someMap2.clear();
            // read new data here and re-fill the maps
        } finally {
            w.unlock();
        }
    }
于 2012-10-11T17:31:10.613 に答える
5

Javaの並行パッケージでLockクラスを使用します。ReenterantReadWriteLockがあります。

于 2012-10-11T17:23:03.730 に答える
1

そのようにするのではなく、どうでしょうか。

public class A {
    private volatile Map<String, Object> someMap1 = new HashMap<String, Object>();
    private volatile Map<String, Object> someMap2 = new HashMap<String, Object>();

    public void reloadData() {
        Map<String, Object> newMap1 = new HashMap<String, Object>();
        Map<String, Object> newMap2 = new HashMap<String, Object>();

        // read new data here and fill the new maps

        someMap1 = newMap1;
        someMap2 = newMap2;
    }

    public Object getDataFromMap(String key) {
        // do some logic here and return data from map
        return someObj;
    }
}

そうすれば、リロード中にリーダーをブロックする必要はありません。欠点は、リロード中に、マップの古いコピーと新しいコピーが同時にメモリに保存されるため、最大メモリ消費量が増えることです。

上記の実装には、2つのマップがアトミックに更新されていないため、微妙な競合状態が含まれている可能性があります。そのため、読者はの古いバージョンを見ることができますsomeMap2が、新しいバージョンを見ることができますsomeMap1。それが問題である場合、それは多くの方法でかなり簡単に解決することができます。

于 2012-10-11T17:55:51.173 に答える