2

I created my own simple, compact ReadWriteLock implementation. The first one uses spinlocks upon trying to acquire a read lock. If the lock bit is set, the second avoids spinlocks by momentarily acquiring the write lock before spinning. That way, it halts its execution until the write lock have been freed. Now my question is which is more efficient and optimized for common use? (both multi-core and non-multi-core machines)

Edit: It is going to be used for my Android app. So I have to keep it compact while providing the ReadWriteLock implementation I need. ReentrantReadWriteLock is heavy for my app. Also, can anyone suggest a better method?

Edit: The implementation details were taken from this link.

The first implementation is as follows:

import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.locks.ReentrantLock;

public class SpinSeqLock {

    private AtomicLong status = new AtomicLong();
    private ReentrantLock writeLock = new ReentrantLock();

    public long readLock() {
        long current;
        do
            current = status.get();
        while ((current & 1) != 0);
        return current;
    }

    public boolean tryReadUnlock(long previous) {
        return status.get() == previous;
    }

    public void writeLock() {
        writeLock.lock();
        status.incrementAndGet();
    }

    public void writeUnlock() {
        status.incrementAndGet();
        writeLock.unlock();
    }

    public void writeLockInterruptibly() throws InterruptedException {
        writeLock.lockInterruptibly(); // If we get interrupted, do not proceed below!

        // Increment only on successful uninterrupted lock
        status.incrementAndGet();
    }
}

The second implementation is as follows:

import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.locks.ReentrantLock;

public class SemiSeqLock {

    private AtomicLong status = new AtomicLong();
    private ReentrantLock writeLock = new ReentrantLock();

    public long readLock() {
        for (;;) {
            long current = status.get();
            if ((current & 1) == 0)
                return current;
            writeLock.lock(); // Avoids spin lock by halting until lock-acquisition.
            writeLock.unlock();
        }
    }

    ... // Same code as the first one
}

The expected usage would be:

Reader Thread:

for (;;) {
    final long status = seqLock.readLock();
    // ... some read operation ...
    // ... some read operation ...
    if (seqLock.tryReadUnlock(status)) break;
}

Writer Thread:

seqLock.writeLock();
try {
    // ... some write operation ...
    // ... some write operation ...
} finally {
    seqLock.writeUnlock();
}

Any corrections? Which one is better?

Jason Sparc
  • 702
  • 2
  • 7
  • 29

1 Answers1

-1

Are you sure that

  • you need it and
  • you can get it better than existing implementation?

Such things are pretty error-prone, much more than usual programs.

So really really try to use an existing lock.

There's at least one error in your lock: writeLockInterruptibly must use finally.

Performance-wise it might be wise to spin a few times before you go to sleep for a long long time via writeLock. Overall I'm not sure it will work... but it looks interesting.

Once again: First try some existing lock written by somebody pretty smart and experienced in this area.

maaartinus
  • 44,714
  • 32
  • 161
  • 320
  • "`writeLockInterruptibly` must use `finally`", doing so would allow the status number to get updated, if the lock was interrupted, then the status number shouldn't increment. Odd numbers locks the write lock. Therefore, the code is working just as intended, no `finally` blocks needed. – Jason Sparc Oct 30 '13 at 05:29
  • 'Once again: First try some existing lock...', I did, a lot. I have been doing some performance test. Afterwards, I found that they are slowing down my programs. Most of them have a catch, i.e. for ReadWriteLock, says java, "the underlying implementation is complex", that ReentrantLocks runs faster when running a test. – Jason Sparc Oct 30 '13 at 07:18
  • [The JVM might automatically use a spin-lock *when that is worthwhile* anyway](https://stackoverflow.com/questions/20689718/what-is-adaptive-spinning-w-r-t-lock-acquisition) – Raedwald Dec 20 '18 at 15:00