投機実行のやつでReadWriteLockを使ってみる

投機的実行をやってみたやつで、synchronizedを使ってたのだけど、ReadWriteLockを使ったほうが並列可能性が高くなるかもね、と思ってちょっと修正してみた。


ところで、最後のロックを次のように、ReadLockの中でWriteLock取得しようと思ったんだけど、デッドロックしてしまったようだ。
こういう再入はできないらしい。

Lock rlock = lock.readLock();
try{
    rlock.lock();
    if(modified.get()){
        if(version != readVer.get()){
            //変更されている
            continue;
        }
        Lock wlock = lock.writeLock();
        try{
            wlock.lock();
            value = myValue.get();
            version++;
        }finally{
            wlock.unlock();
        }
    }
}finally{
    rlock.unlock();
}


ということで、こんな感じ

public static class TransactionalInteger{
    static ReadWriteLock lock = new ReentrantReadWriteLock();
    int value;
    final ThreadLocal<Integer> myValue = new ThreadLocal<Integer>();
    final ThreadLocal<Integer> readVer = new ThreadLocal<Integer>();
    final ThreadLocal<Boolean> modified = new ThreadLocal<Boolean>();
    int version = 0;

    public TransactionalInteger() {
    }

    public TransactionalInteger(int value) {
        this.value = value;
    }

    int get() {
        return myValue.get();
    }

    void set(int o) {
        myValue.set(o);
        modified.set(true);
    }

    void flush(){
        Lock rlock = lock.readLock();
        try{
            rlock.lock();
            myValue.set(value);
            readVer.set(version);
            modified.set(false);
        }finally{
            rlock.unlock();
        }
    }

    void with(final Runnable runner) {
        for(;;) {
            flush();
            runner.run();
            Lock wlock = lock.writeLock();
            try{
                wlock.lock();
                if(modified.get()){
                    if(version != readVer.get()){
                        //変更されている
                        continue;
                    }
                    value = myValue.get();
                    version++;
                }
            }finally{
                wlock.unlock();
            }
            break;
        }
    }
}