29
29
import java .util .concurrent .locks .Lock ;
30
30
import java .util .concurrent .locks .ReadWriteLock ;
31
31
32
+ import org .slf4j .Logger ;
33
+ import org .slf4j .LoggerFactory ;
34
+
32
35
/**
33
36
* Class responsible for control the access for reader or writer
34
37
*
35
- * Allows multiple readers to hold the lock at same time, but if any writer holds the lock then
36
- * readers wait. If reader holds the lock then writer waits. This lock is not fair.
38
+ * Allows multiple readers to hold the lock at same time, but if any writer holds the lock then readers wait. If reader
39
+ * holds the lock then writer waits. This lock is not fair.
37
40
*/
38
41
public class ReaderWriterLock implements ReadWriteLock {
42
+
43
+ private static final Logger LOGGER = LoggerFactory .getLogger (ReaderWriterLock .class );
39
44
40
45
41
46
private Object readerMutex = new Object ();
@@ -45,10 +50,10 @@ public class ReaderWriterLock implements ReadWriteLock {
45
50
/**
46
51
* Global mutex is used to indicate that whether reader or writer gets the lock in the moment.
47
52
* <p>
48
- * 1. When it contains the reference of {@link readerLock}, it means that the lock is acquired by
49
- * the reader, another reader can also do the read operation concurrently. <br>
50
- * 2. When it contains the reference of reference of {@link writerLock}, it means that the lock is
51
- * acquired by the writer exclusively, no more reader or writer can get the lock.
53
+ * 1. When it contains the reference of {@link readerLock}, it means that the lock is acquired by the reader, another
54
+ * reader can also do the read operation concurrently. <br>
55
+ * 2. When it contains the reference of reference of {@link writerLock}, it means that the lock is acquired by the
56
+ * writer exclusively, no more reader or writer can get the lock.
52
57
* <p>
53
58
* This is the most important field in this class to control the access for reader/writer.
54
59
*/
@@ -74,13 +79,6 @@ private boolean doesWriterOwnThisLock() {
74
79
return globalMutex .contains (writerLock );
75
80
}
76
81
77
- /**
78
- * return true when globalMutex hold the reference of readerLock
79
- */
80
- private boolean doesReaderOwnThisLock () {
81
- return globalMutex .contains (readerLock );
82
- }
83
-
84
82
/**
85
83
* Nobody get the lock when globalMutex contains nothing
86
84
*
@@ -89,43 +87,39 @@ private boolean isLockFree() {
89
87
return globalMutex .isEmpty ();
90
88
}
91
89
92
- private static void waitUninterruptibly (Object o ) {
93
- try {
94
- o .wait ();
95
- } catch (InterruptedException e ) {
96
- e .printStackTrace ();
97
- }
98
- }
99
-
100
90
/**
101
91
* Reader Lock, can be access for more than one reader concurrently if no writer get the lock
102
92
*/
103
93
private class ReadLock implements Lock {
104
94
105
95
@ Override
106
96
public void lock () {
107
-
108
97
synchronized (readerMutex ) {
109
-
110
98
currentReaderCount ++;
111
99
if (currentReaderCount == 1 ) {
112
- // Try to get the globalMutex lock for the first reader
113
- synchronized (globalMutex ) {
114
- while (true ) {
115
- // If the no one get the lock or the lock is locked by reader, just set the reference
116
- // to the globalMutex to indicate that the lock is locked by Reader.
117
- if (isLockFree () || doesReaderOwnThisLock ()) {
118
- globalMutex .add (this );
119
- break ;
120
- } else {
121
- // If lock is acquired by the write, let the thread wait until the writer release
122
- // the lock
123
- waitUninterruptibly (globalMutex );
124
- }
125
- }
126
- }
100
+ acquireForReaders ();
101
+ }
102
+ }
103
+ }
127
104
105
+ /**
106
+ * Acquire the globalMutex lock on behalf of current and future concurrent readers. Make sure no writers currently
107
+ * owns the lock.
108
+ */
109
+ private void acquireForReaders () {
110
+ // Try to get the globalMutex lock for the first reader
111
+ synchronized (globalMutex ) {
112
+ // If the no one get the lock or the lock is locked by reader, just set the reference
113
+ // to the globalMutex to indicate that the lock is locked by Reader.
114
+ while (doesWriterOwnThisLock ()) {
115
+ try {
116
+ globalMutex .wait ();
117
+ } catch (InterruptedException e ) {
118
+ LOGGER .info ("InterruptedException while waiting for globalMutex in acquireForReaders" , e );
119
+ Thread .currentThread ().interrupt ();
120
+ }
128
121
}
122
+ globalMutex .add (this );
129
123
}
130
124
}
131
125
@@ -179,23 +173,17 @@ public void lock() {
179
173
180
174
synchronized (globalMutex ) {
181
175
182
- while (true ) {
183
- // When there is no one acquired the lock, just put the writeLock reference to the
184
- // globalMutex to indicate that the lock is acquired by one writer.
185
- // It is ensure that writer can only get the lock when no reader/writer acquired the lock.
186
- if (isLockFree ()) {
187
- globalMutex .add (this );
188
- break ;
189
- } else if (doesWriterOwnThisLock ()) {
190
- // Wait when other writer get the lock
191
- waitUninterruptibly (globalMutex );
192
- } else if (doesReaderOwnThisLock ()) {
193
- // Wait when other reader get the lock
194
- waitUninterruptibly (globalMutex );
195
- } else {
196
- throw new AssertionError ("it should never reach here" );
176
+ // Wait until the lock is free.
177
+ while (!isLockFree ()) {
178
+ try {
179
+ globalMutex .wait ();
180
+ } catch (InterruptedException e ) {
181
+ LOGGER .info ("InterruptedException while waiting for globalMutex to begin writing" , e );
182
+ Thread .currentThread ().interrupt ();
197
183
}
198
184
}
185
+ // When the lock is free, acquire it by placing an entry in globalMutex
186
+ globalMutex .add (this );
199
187
}
200
188
}
201
189
0 commit comments