RamPrakash
RamPrakash

Reputation: 3322

Java Concurrency - Read Write Lock Performance

I am trying to understand ReadWriteLock. [ This code will just work in your IDE. Copy & paste. Try to do this yourself ]

class ReadWrite {

    private static final ReadWriteLock LOCK = new ReentrantReadWriteLock();
    private static final Lock READ_LOCK = LOCK.readLock();
    private static final Lock WRITE_LOCK = LOCK.writeLock();
    private static final int[] ARR = new int[1];
    int i = 0;

    Integer read(){
        Integer value = null;
        try{
            READ_LOCK.lock();
            value = ARR[0];
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            READ_LOCK.unlock();
        }
        return value;
    }


    void write(){
        try{
            WRITE_LOCK.lock();
            ARR[0] = i++;
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            WRITE_LOCK.unlock();
        }
    }

}

I was trying to do a performance test.

        AtomicInteger atomicInteger = new AtomicInteger(0);
        ReadWrite rw = new ReadWrite();
        // read 10 millions times
    Runnable r1 = () -> IntStream.rangeClosed(1, 10_000_000).forEach(i -> {
        if(rw.read() > 0)
            atomicInteger.incrementAndGet();
    });
        Runnable r2 = rw::write;

        ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(1);
        Thread[] threads = new Thread[10];

        long before = System.currentTimeMillis();
        scheduledExecutorService.scheduleAtFixedRate(r2, 1, 1, TimeUnit.MICROSECONDS);
        for (int i = 0; i < 10; i++) {
            threads[i] = new Thread(r1);
            threads[i].start();
        }
        for (int i = 0; i < 10; i++) {
            threads[i].join();
        }
        System.out.println("Time Taken :: " + (System.currentTimeMillis() - before));
       System.out.println("No fo reads :: " + atomicInteger.get());

Ran this test few times.

Case 1:

When i use READ_LOCK for reading it takes 12 seconds to complete. no of reads is 100000000.

Case 2:

When I use WRITE_LOCK for both reading & writing (READ_LOCK not used in this case), it the test takes only 2.5 seconds. no of reads is 100000000.

I was thinking having separate locks should improve performance.

What is going on here? What is the mistake I do?

Upvotes: 2

Views: 1212

Answers (2)

acelent
acelent

Reputation: 8135

The documentation of ReadWriteLock mentions this:

Further, if the read operations are too short the overhead of the read-write lock implementation (which is inherently more complex than a mutual exclusion lock) can dominate the execution cost, particularly as many read-write lock implementations still serialize all threads through a small section of code. Ultimately, only profiling and measurement will establish whether the use of a read-write lock is suitable for your application.

Your reads are indeed very fast, so you're observing the overhead that a read-write lock has over a simple lock.

What's involved in the implementation of a read-write lock? To start, there are actually two locks. The read lock may be taken by multiple threads, making it different from a simple reentrant lock, and it must check that the write lock is not locked when trying to lock. The writer lock must check that there are no locked readers when trying to lock, but it's otherwise similar to a single-threaded reentrant lock.

For fine-grained accesses such as in your example, a read-write lock is not worth it. The overhead might become negligible when accessing a bunch of data, such as a "page" of data, e.g. hundreds or thousands of cached database rows.

Upvotes: 0

Rotem ben
Rotem ben

Reputation: 176

You are running read() for 10 millions times (* 10 threads). and run write() only once .. The write took 2.5 sec because it was able to take the write lock only when there was no thread with the read lock.

Also, as @Burak was mentioned, you did not measured the right thing here.

You should run same method once with read lock and once with write lock. Run this method with 10 threads for example. The method will iterate 1-10 million for example.

In addition, you are calculating the time of creating a thread inside your test (which is not part of the locks mechanism. You should create the threads before)

Then you will see that the write lock method is slower than the read lock. Why? because when a thread takes the write lock, only this thread will be able to execute the method code. In case of the read lock, all the 10 threads will run the method in parallel

Upvotes: 1

Related Questions