• Post Reply
  • Bookmark Topic Watch Topic
  • New Topic

Using fair or unfair ReentrantReadWriteLock aquisition order ?

 
Ronald Wouters
Ranch Hand
Posts: 190
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
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 ]
 
Andrew Monkhouse
author and jackaroo
Marshal Commander
Pie
Posts: 11914
209
C++ Firefox Browser IntelliJ IDE Java Mac Oracle
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Hi Ronald,

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.

I am inclined to use the "fair" aquisition order because the "write"s come mostly in one bundled "burst".
Do you mean that your test case is sending writes in bursts, or that using the "fair" aquistion order is bundling them?

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
 
Ronald Wouters
Ranch Hand
Posts: 190
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
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.
 
Andrew Monkhouse
author and jackaroo
Marshal Commander
Pie
Posts: 11914
209
C++ Firefox Browser IntelliJ IDE Java Mac Oracle
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Hi Ronald,
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.
Correct - you are still going to need synchronization around your RAF access.

Regards, Andrew
 
  • Post Reply
  • Bookmark Topic Watch Topic
  • New Topic