54
51

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Java でオンメモリキャッシュを実装するときにスレッドについて気をつけるべきこと

Last updated at Posted at 2014-09-17

Java では常にスレッドについて意識する必要がある。
Map にキャッシュデータを入れたい場合、HashMap を使ってはいけない。HashMap はスレッドセーフではないからだ。

synchronized で保護してもいいが、いちいちするのも面倒だし、問題が起きがちなんで、

   Map m = Collections.synchronizedMap(new HashMap(...));

のように、Collections.synchronizedMap() でよしなにする方法がある。この方法でラップすると、メソッドアクセスの際に synchronized がかかるので安全になる。

ConcurrentHashMap と HashMap

HashMap をマルチスレッドからアクセスする場合、get メソッドを使った場合でも synchronized をかけざるをえず、パフォーマンスが出ない。

ConcurrentHashMap ならば、取得時にはロックがかからないので、キャッシュには ConcurrentHashMap を使うことが望ましい。

Java 8 以後における ConcurrentHashMap によるキャッシュ実装

Java 8 では ConcurrentHashMap に computeIfAbsent メソッドが追加されている。これを利用すれば簡単にキャッシュを更新することが可能となる。

指定されたキーがまだ値に関連付けられていない場合、指定されたマッピング関数を使用してその値の計算を試行し、nullでない場合はそれをこのマップに入力します。メソッドの呼出し全体は原子的に実行されるため、関数はキーごとに多くても1回しか適用されません。他のスレッドがこのマップに対して試行する更新オペレーションの一部は計算の進行中にブロックされる可能性があるため、計算は短く簡単にしてください。また、計算でこのマップの他のマッピングを更新しようとしないでください。

http://docs.oracle.com/javase/jp/8/api/java/util/concurrent/ConcurrentHashMap.html#computeIfAbsent-K-java.util.function.Function-
これを利用することにより、今まで記述が難しかったキャッシュ処理の記述が極めて簡単になっている。
import java.util.concurrent.ConcurrentHashMap;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

public class CachedMD5 {
    private final ConcurrentHashMap<byte[], byte[]> cache = new ConcurrentHashMap<>();
    private final MessageDigest md;

    public CachedMD5() throws NoSuchAlgorithmException{
        this.md = MessageDigest.getInstance("MD5");
    }

    public byte[] get(byte[] src) {
        return cache.computeIfAbsent(src, it -> {
            System.out.println("Calcurating...");
            return md.digest(it);
        });
    }

    public static void main(String[] args) throws Exception {
        CachedMD5 cached = new CachedMD5();
        byte[] bytesOfMessage = "hogehogefugafuga".getBytes("UTF-8");
        System.out.println(cached.get(bytesOfMessage));
        System.out.println(cached.get(bytesOfMessage));
    }
}
54
51
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
54
51

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?