Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there a read write lock with listeners for java?

Is there a java library that implements something that behaves like a ReadWriteLock but uses listeners or CompletableFuture/CompletionStage instead of blocking?

Ideally I'd like to write:

lock = ...

CompletionStage stage = lock.lockRead();
stage.thenAccept(r -> { doSomething(); r.release(); });

And also important:

CompletionStage stage = lock.tryLockWrite(10, TimeUnit.SECONDS);
stage.handle(callback);

I'm looking to know if something like this exists and if it does how is it called.

I'm not looking to implement this myself, but rather use a library to simplify some framework code.

like image 272
Daniel Sperry Avatar asked Oct 31 '22 07:10

Daniel Sperry


1 Answers

I think writing it yourself shouldn't be hard enough. Chances are it would take less time than looking for a library. It's pretty simple overall:

static const int STATE_UNLOCKED = 0;
static const int STATE_READING = 1;
static const int STATE_WRITING = 2;
int state = STATE_UNLOCKED;
int readers = 0;
Queue<CompletableFuture<Void>> queueWriters = new LinkedList<CompletableFuture<Void>>();
Queue<CompletableFuture<Void>> queueReaders = new LinkedList<CompletableFuture<Void>>();

public synchronized CompletionStage<Void> lockWriter() {
    CompletableFuture<Void> l = new CompletableFuture<Void>();
    if (state == STATE_UNLOCKED) {
        state = STATE_WRITING;
        l.complete(null);
        return l;
    }
    queueWriters.offer(l);
    return l;
}

public synchronized CompletionStage<Void> lockReader() {
    CompletableFuture<Void> l = new CompletableFuture<Void>();
    if (state != STATE_WRITING) {
        state = STATE_READING;
        readers++;
        l.complete(null);
        return l;
    }
    queueReaders.offer(l);
    return l;
}

public void unlock() {
    CompletableFuture<Void> l = null;
    synchronized(this) {
        if (state == STATE_READING) {
            readers--;
            if (readers > 0) {
                return;
            }
        }
        l = queueReaders.poll();
        if (l != null) {
            state = STATE_READING;
            readers++;
        }
        else {
            l = queueWriters.poll();
            if (l != null) {
                state = STATE_WRITING;
            }
            else {
                state = STATE_UNLOCKED;
                return;
            }
        }
    }
    l.complete(null);
    while (true) {
        synchronized (this) {
            if (state != STATE_READING) {
                return;
            }
            l = queueReaders.poll();
            if (l == null) {
                return;
            }
            readers++;
        }
        l.complete(null);
    }
}

Adding timed locking (By using some sort of "expiring queue" or writer-starvation prevention (By preventing additional readers from being executed if queueWriters is not empty) to the above shouldn't be that much more difficult either.

like image 198
SlugFiller Avatar answered Nov 15 '22 03:11

SlugFiller