# Using fair or unfair ReentrantReadWriteLock aquisition order ?

Ronald Wouters

Ranch Hand

Posts: 190

posted 11 years ago

Hi all,

for my physical locking, meaning read/writes to my db file (URLyBird 1.3.3), I am using the JDK 5.0 ReentrantReadWriteLock stuff.

What I am not sure about is whether or not I should use a "fair" or "unfair" lock aquisition order.

I therefore did some "benchmarks" using both fair and unfair. Each test has 10 threads which each do a read/write/read of a shared resource (a private int instance variable).

Based on my own benchmarks (see below) I am inclined to use the "fair" aquisition order because the "write"s come mostly in one bundled "burst". This means that all following reads will have a more "up to date" result than when using the unfair aquisition order.

I would love to hear anyones opinions on this.

Thanks in advance.

Regards,

Ronald Wouters

Here are the results of my benchmarks:

Legend

------

RW-nn name of thread

QR Queued Reader Threads

QW Queued Writer Threads

[readLocks 4] after obtaining the read lock, the current number of read locks is 4

[writeLock RW-07] the writeLock is held by thread RW-07

examples

--------

QR 4 means that four reader threads are queued for obtaining the read lock

QW 2 means that two writer threads are queued for obtaining the write lock

results for UNFAIR aquisition order

-----------------------------------

RW-00 getSharedResource [readLocks = 1] [writeLock ] [QR 0 ] [QW 0 ]

RW-00 setSharedResource [readLocks = 0] [writeLock RW-00] [QR 0 ] [QW 0 ]

RW-08 getSharedResource [readLocks = 2] [writeLock ] [QR 8 ] [QW 0 ]

RW-00 getSharedResource [readLocks = 1] [writeLock ] [QR 9 ] [QW 0 ]

RW-06 getSharedResource [readLocks = 1] [writeLock ] [QR 6 ] [QW 1 ]

RW-09 getSharedResource [readLocks = 2] [writeLock ] [QR 6 ] [QW 1 ]

RW-07 getSharedResource [readLocks = 3] [writeLock ] [QR 5 ] [QW 1 ]

RW-01 getSharedResource [readLocks = 4] [writeLock ] [QR 4 ] [QW 1 ]

RW-02 getSharedResource [readLocks = 5] [writeLock ] [QR 3 ] [QW 1 ]

RW-03 getSharedResource [readLocks = 7] [writeLock ] [QR 0 ] [QW 2 ]

RW-04 getSharedResource [readLocks = 5] [writeLock ] [QR 0 ] [QW 2 ]

RW-05 getSharedResource [readLocks = 6] [writeLock ] [QR 0 ] [QW 3 ]

RW-03 setSharedResource [readLocks = 0] [writeLock RW-03] [QR 0 ] [QW 8 ]

RW-08 setSharedResource [readLocks = 0] [writeLock RW-08] [QR 0 ] [QW 7 ]

RW-08 getSharedResource [readLocks = 1] [writeLock ] [QR 1 ] [QW 7 ]

RW-06 setSharedResource [readLocks = 0] [writeLock RW-06] [QR 1 ] [QW 6 ]

RW-06 getSharedResource [readLocks = 1] [writeLock ] [QR 1 ] [QW 6 ]

RW-09 setSharedResource [readLocks = 0] [writeLock RW-09] [QR 1 ] [QW 5 ]

RW-09 getSharedResource [readLocks = 1] [writeLock ] [QR 1 ] [QW 5 ]

RW-07 setSharedResource [readLocks = 0] [writeLock RW-07] [QR 1 ] [QW 4 ]

RW-07 getSharedResource [readLocks = 1] [writeLock ] [QR 1 ] [QW 4 ]

RW-01 setSharedResource [readLocks = 0] [writeLock RW-01] [QR 1 ] [QW 3 ]

RW-01 getSharedResource [readLocks = 1] [writeLock ] [QR 1 ] [QW 3 ]

RW-02 setSharedResource [readLocks = 0] [writeLock RW-02] [QR 1 ] [QW 2 ]

RW-02 getSharedResource [readLocks = 1] [writeLock ] [QR 1 ] [QW 2 ]

RW-05 setSharedResource [readLocks = 0] [writeLock RW-05] [QR 1 ] [QW 1 ]

RW-05 getSharedResource [readLocks = 1] [writeLock ] [QR 1 ] [QW 1 ]

RW-04 setSharedResource [readLocks = 0] [writeLock RW-04] [QR 1 ] [QW 0 ]

RW-04 getSharedResource [readLocks = 1] [writeLock ] [QR 0 ] [QW 0 ]

RW-03 getSharedResource [readLocks = 2] [writeLock ] [QR 0 ] [QW 0 ]

results for FAIR aquisition order

---------------------------------

RW-03 getSharedResource [readLocks = 3] [writeLock ] [QR 0 ] [QW 0 ]

RW-06 getSharedResource [readLocks = 6] [writeLock ] [QR 0 ] [QW 0 ]

RW-02 getSharedResource [readLocks = 4] [writeLock ] [QR 0 ] [QW 0 ]

RW-00 getSharedResource [readLocks = 2] [writeLock ] [QR 0 ] [QW 0 ]

RW-01 getSharedResource [readLocks = 2] [writeLock ] [QR 0 ] [QW 0 ]

RW-07 getSharedResource [readLocks = 7] [writeLock ] [QR 0 ] [QW 0 ]

RW-08 getSharedResource [readLocks = 9] [writeLock ] [QR 0 ] [QW 0 ]

RW-09 getSharedResource [readLocks = 10] [writeLock ] [QR 0 ] [QW 0 ]

RW-05 getSharedResource [readLocks = 8] [writeLock ] [QR 0 ] [QW 0 ]

RW-04 getSharedResource [readLocks = 5] [writeLock ] [QR 0 ] [QW 0 ]

RW-03 setSharedResource [readLocks = 0] [writeLock RW-03] [QR 0 ] [QW 8 ]

RW-06 setSharedResource [readLocks = 0] [writeLock RW-06] [QR 1 ] [QW 8 ]

RW-02 setSharedResource [readLocks = 0] [writeLock RW-02] [QR 2 ] [QW 7 ]

RW-01 setSharedResource [readLocks = 0] [writeLock RW-01] [QR 3 ] [QW 6 ]

RW-07 setSharedResource [readLocks = 0] [writeLock RW-07] [QR 4 ] [QW 5 ]

RW-00 setSharedResource [readLocks = 0] [writeLock RW-00] [QR 5 ] [QW 4 ]

RW-09 setSharedResource [readLocks = 0] [writeLock RW-09] [QR 6 ] [QW 3 ]

RW-05 setSharedResource [readLocks = 0] [writeLock RW-05] [QR 7 ] [QW 2 ]

RW-08 setSharedResource [readLocks = 0] [writeLock RW-08] [QR 8 ] [QW 1 ]

RW-04 setSharedResource [readLocks = 0] [writeLock RW-04] [QR 9 ] [QW 0 ]

RW-03 getSharedResource [readLocks = 1] [writeLock ] [QR 8 ] [QW 0 ]

RW-06 getSharedResource [readLocks = 2] [writeLock ] [QR 8 ] [QW 0 ]

RW-02 getSharedResource [readLocks = 3] [writeLock ] [QR 7 ] [QW 0 ]

RW-01 getSharedResource [readLocks = 3] [writeLock ] [QR 6 ] [QW 0 ]

RW-09 getSharedResource [readLocks = 4] [writeLock ] [QR 3 ] [QW 0 ]

RW-05 getSharedResource [readLocks = 5] [writeLock ] [QR 2 ] [QW 0 ]

RW-00 getSharedResource [readLocks = 4] [writeLock ] [QR 3 ] [QW 0 ]

RW-08 getSharedResource [readLocks = 4] [writeLock ] [QR 1 ] [QW 0 ]

RW-07 getSharedResource [readLocks = 4] [writeLock ] [QR 1 ] [QW 0 ]

RW-04 getSharedResource [readLocks = 3] [writeLock ] [QR 0 ] [QW 0 ]

for my physical locking, meaning read/writes to my db file (URLyBird 1.3.3), I am using the JDK 5.0 ReentrantReadWriteLock stuff.

What I am not sure about is whether or not I should use a "fair" or "unfair" lock aquisition order.

I therefore did some "benchmarks" using both fair and unfair. Each test has 10 threads which each do a read/write/read of a shared resource (a private int instance variable).

Based on my own benchmarks (see below) I am inclined to use the "fair" aquisition order because the "write"s come mostly in one bundled "burst". This means that all following reads will have a more "up to date" result than when using the unfair aquisition order.

I would love to hear anyones opinions on this.

Thanks in advance.

Regards,

Ronald Wouters

Here are the results of my benchmarks:

Legend

------

RW-nn name of thread

QR Queued Reader Threads

QW Queued Writer Threads

[readLocks 4] after obtaining the read lock, the current number of read locks is 4

[writeLock RW-07] the writeLock is held by thread RW-07

examples

--------

QR 4 means that four reader threads are queued for obtaining the read lock

QW 2 means that two writer threads are queued for obtaining the write lock

results for UNFAIR aquisition order

-----------------------------------

RW-00 getSharedResource [readLocks = 1] [writeLock ] [QR 0 ] [QW 0 ]

RW-00 setSharedResource [readLocks = 0] [writeLock RW-00] [QR 0 ] [QW 0 ]

RW-08 getSharedResource [readLocks = 2] [writeLock ] [QR 8 ] [QW 0 ]

RW-00 getSharedResource [readLocks = 1] [writeLock ] [QR 9 ] [QW 0 ]

RW-06 getSharedResource [readLocks = 1] [writeLock ] [QR 6 ] [QW 1 ]

RW-09 getSharedResource [readLocks = 2] [writeLock ] [QR 6 ] [QW 1 ]

RW-07 getSharedResource [readLocks = 3] [writeLock ] [QR 5 ] [QW 1 ]

RW-01 getSharedResource [readLocks = 4] [writeLock ] [QR 4 ] [QW 1 ]

RW-02 getSharedResource [readLocks = 5] [writeLock ] [QR 3 ] [QW 1 ]

RW-03 getSharedResource [readLocks = 7] [writeLock ] [QR 0 ] [QW 2 ]

RW-04 getSharedResource [readLocks = 5] [writeLock ] [QR 0 ] [QW 2 ]

RW-05 getSharedResource [readLocks = 6] [writeLock ] [QR 0 ] [QW 3 ]

RW-03 setSharedResource [readLocks = 0] [writeLock RW-03] [QR 0 ] [QW 8 ]

RW-08 setSharedResource [readLocks = 0] [writeLock RW-08] [QR 0 ] [QW 7 ]

RW-08 getSharedResource [readLocks = 1] [writeLock ] [QR 1 ] [QW 7 ]

RW-06 setSharedResource [readLocks = 0] [writeLock RW-06] [QR 1 ] [QW 6 ]

RW-06 getSharedResource [readLocks = 1] [writeLock ] [QR 1 ] [QW 6 ]

RW-09 setSharedResource [readLocks = 0] [writeLock RW-09] [QR 1 ] [QW 5 ]

RW-09 getSharedResource [readLocks = 1] [writeLock ] [QR 1 ] [QW 5 ]

RW-07 setSharedResource [readLocks = 0] [writeLock RW-07] [QR 1 ] [QW 4 ]

RW-07 getSharedResource [readLocks = 1] [writeLock ] [QR 1 ] [QW 4 ]

RW-01 setSharedResource [readLocks = 0] [writeLock RW-01] [QR 1 ] [QW 3 ]

RW-01 getSharedResource [readLocks = 1] [writeLock ] [QR 1 ] [QW 3 ]

RW-02 setSharedResource [readLocks = 0] [writeLock RW-02] [QR 1 ] [QW 2 ]

RW-02 getSharedResource [readLocks = 1] [writeLock ] [QR 1 ] [QW 2 ]

RW-05 setSharedResource [readLocks = 0] [writeLock RW-05] [QR 1 ] [QW 1 ]

RW-05 getSharedResource [readLocks = 1] [writeLock ] [QR 1 ] [QW 1 ]

RW-04 setSharedResource [readLocks = 0] [writeLock RW-04] [QR 1 ] [QW 0 ]

RW-04 getSharedResource [readLocks = 1] [writeLock ] [QR 0 ] [QW 0 ]

RW-03 getSharedResource [readLocks = 2] [writeLock ] [QR 0 ] [QW 0 ]

results for FAIR aquisition order

---------------------------------

RW-03 getSharedResource [readLocks = 3] [writeLock ] [QR 0 ] [QW 0 ]

RW-06 getSharedResource [readLocks = 6] [writeLock ] [QR 0 ] [QW 0 ]

RW-02 getSharedResource [readLocks = 4] [writeLock ] [QR 0 ] [QW 0 ]

RW-00 getSharedResource [readLocks = 2] [writeLock ] [QR 0 ] [QW 0 ]

RW-01 getSharedResource [readLocks = 2] [writeLock ] [QR 0 ] [QW 0 ]

RW-07 getSharedResource [readLocks = 7] [writeLock ] [QR 0 ] [QW 0 ]

RW-08 getSharedResource [readLocks = 9] [writeLock ] [QR 0 ] [QW 0 ]

RW-09 getSharedResource [readLocks = 10] [writeLock ] [QR 0 ] [QW 0 ]

RW-05 getSharedResource [readLocks = 8] [writeLock ] [QR 0 ] [QW 0 ]

RW-04 getSharedResource [readLocks = 5] [writeLock ] [QR 0 ] [QW 0 ]

RW-03 setSharedResource [readLocks = 0] [writeLock RW-03] [QR 0 ] [QW 8 ]

RW-06 setSharedResource [readLocks = 0] [writeLock RW-06] [QR 1 ] [QW 8 ]

RW-02 setSharedResource [readLocks = 0] [writeLock RW-02] [QR 2 ] [QW 7 ]

RW-01 setSharedResource [readLocks = 0] [writeLock RW-01] [QR 3 ] [QW 6 ]

RW-07 setSharedResource [readLocks = 0] [writeLock RW-07] [QR 4 ] [QW 5 ]

RW-00 setSharedResource [readLocks = 0] [writeLock RW-00] [QR 5 ] [QW 4 ]

RW-09 setSharedResource [readLocks = 0] [writeLock RW-09] [QR 6 ] [QW 3 ]

RW-05 setSharedResource [readLocks = 0] [writeLock RW-05] [QR 7 ] [QW 2 ]

RW-08 setSharedResource [readLocks = 0] [writeLock RW-08] [QR 8 ] [QW 1 ]

RW-04 setSharedResource [readLocks = 0] [writeLock RW-04] [QR 9 ] [QW 0 ]

RW-03 getSharedResource [readLocks = 1] [writeLock ] [QR 8 ] [QW 0 ]

RW-06 getSharedResource [readLocks = 2] [writeLock ] [QR 8 ] [QW 0 ]

RW-02 getSharedResource [readLocks = 3] [writeLock ] [QR 7 ] [QW 0 ]

RW-01 getSharedResource [readLocks = 3] [writeLock ] [QR 6 ] [QW 0 ]

RW-09 getSharedResource [readLocks = 4] [writeLock ] [QR 3 ] [QW 0 ]

RW-05 getSharedResource [readLocks = 5] [writeLock ] [QR 2 ] [QW 0 ]

RW-00 getSharedResource [readLocks = 4] [writeLock ] [QR 3 ] [QW 0 ]

RW-08 getSharedResource [readLocks = 4] [writeLock ] [QR 1 ] [QW 0 ]

RW-07 getSharedResource [readLocks = 4] [writeLock ] [QR 1 ] [QW 0 ]

RW-04 getSharedResource [readLocks = 3] [writeLock ] [QR 0 ] [QW 0 ]

*
Sun Certified Developer for the Java 2 Platform
Sun Certified Enterprise Architect for the Java Platform, Enterprise Edition 5
*

posted 11 years ago

Hi Ronald,

I'm not sure what your reference to benchmarking was for - you did not show benchmark statistics. This

More to the point - what impact do you think this has for the application? What are the most common operations? Are writes likely to be grouped around particular timeframes, or are they likely to be spread equally across the entire server lifetime? Would having a fair or unfair aquisition order make a difference if all you have is many outstanding reads?

Regards, Andrew

I'm not sure what your reference to benchmarking was for - you did not show benchmark statistics. This

*might*have an impact on your choice, as having a fair aquistion order might make your code slower.Do you mean that your test case is sending writes in bursts, or that using the "fair" aquistion order is bundling them?I am inclined to use the "fair" aquisition order because the "write"s come mostly in one bundled "burst".

More to the point - what impact do you think this has for the application? What are the most common operations? Are writes likely to be grouped around particular timeframes, or are they likely to be spread equally across the entire server lifetime? Would having a fair or unfair aquisition order make a difference if all you have is many outstanding reads?

Regards, Andrew

The Sun Certified Java Developer Exam with J2SE 5: paper version from Amazon, PDF from Apress, Online reference: Books 24x7 Personal blog

Ronald Wouters

Ranch Hand

Posts: 190

posted 11 years ago

I agree, maybe "benchmark" was too strong a word...

It is the fair aquistion order that is bundling the writes !!

My test case simply consist of a simple app that starts 10 threads (RW-00 thru RW-09). Each thread executes the sequence read/write/read.

In my test results reads correspond to "getSharedResource", writes to "setSharedResource".

The only impact I can think of is, that all the reads that come after a burst of writes would return more up to date information to the user, at least temporarily until the next set of writes comes along.

When the writes are more mingled with the reads, I think the degree of stale information returned to the client would be greater.

As far as performance is concerned, I think the difference between using fair or unfair aquisition order will be minimal.

It is just the degree of "staleness" of returned info I was thinking about.

One thing that still has me worried:

I originally thought that using the ReadWriteLock stuff would solve my physical locking. The more tests I do and think about this, the more I think this may not be the case.

As I understand it, the ReadLock doesn't really lock anything. It is just a fancy queue mechanism to coordinate with the WriteLock.

When concurrent reads are going on, multiple threads will still be accessing my

Obviously synchronizing on the raf during a write is not needed because the WriteLock takes care of that.

I would appreciate any thoughts you may have on this.

Thanks in advance.

Regards,

Ronald Wouters.

you did not show benchmark statistics

I agree, maybe "benchmark" was too strong a word...

Do you mean that your test case is sending writes in bursts, or that using the "fair" aquistion order is bundling them?

It is the fair aquistion order that is bundling the writes !!

My test case simply consist of a simple app that starts 10 threads (RW-00 thru RW-09). Each thread executes the sequence read/write/read.

In my test results reads correspond to "getSharedResource", writes to "setSharedResource".

what impact do you think this has for the application?

The only impact I can think of is, that all the reads that come after a burst of writes would return more up to date information to the user, at least temporarily until the next set of writes comes along.

When the writes are more mingled with the reads, I think the degree of stale information returned to the client would be greater.

As far as performance is concerned, I think the difference between using fair or unfair aquisition order will be minimal.

It is just the degree of "staleness" of returned info I was thinking about.

One thing that still has me worried:

I originally thought that using the ReadWriteLock stuff would solve my physical locking. The more tests I do and think about this, the more I think this may not be the case.

As I understand it, the ReadLock doesn't really lock anything. It is just a fancy queue mechanism to coordinate with the WriteLock.

When concurrent reads are going on, multiple threads will still be accessing my

**single**RAF instance at the same time. This may still cause the seek and read operations on the raf to get mixed up. If this is the case, I may still need to synchronize on the raf instance even when I already have a ReadLock in place...

Obviously synchronizing on the raf during a write is not needed because the WriteLock takes care of that.

I would appreciate any thoughts you may have on this.

Thanks in advance.

Regards,

Ronald Wouters.

Sun Certified Developer for the Java 2 Platform

Sun Certified Enterprise Architect for the Java Platform, Enterprise Edition 5

posted 11 years ago
The Sun Certified Java Developer Exam with J2SE 5: paper version from Amazon, PDF from Apress, Online reference: Books 24x7 Personal blog

Hi Ronald,

Regards, Andrew

Correct - you are still going to need synchronization around your RAF access.One thing that still has me worried:

I originally thought that using the ReadWriteLock stuff would solve my physical locking. The more tests I do and think about this, the more I think this may not be the case.

As I understand it, the ReadLock doesn't really lock anything. It is just a fancy queue mechanism to coordinate with the WriteLock.

When concurrent reads are going on, multiple threads will still be accessing my single RAF instance at the same time. This may still cause the seek and read operations on the raf to get mixed up.

Regards, Andrew