File: FIFOReadWriteLock.java

package info (click to toggle)
concurrent-dfsg 1.3.4-4
  • links: PTS, VCS
  • area: main
  • in suites: buster, jessie, jessie-kfreebsd, squeeze, stretch, wheezy
  • size: 976 kB
  • ctags: 2,018
  • sloc: java: 10,704; xml: 49; makefile: 12
file content (186 lines) | stat: -rw-r--r-- 5,717 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
/*
  File: FIFOReadWriteLock.java

  Originally written by Doug Lea and released into the public domain.
  This may be used for any purposes whatsoever without acknowledgment.
  Thanks for the assistance and support of Sun Microsystems Labs,
  and everyone contributing, testing, and using this code.

  History:
  Date       Who                What
  11Jun1998  dl               Create public version
  23nov2001  dl               Replace main algorithm with fairer
                              version based on one by Alexander Terekhov
*/

package EDU.oswego.cs.dl.util.concurrent;


/**
 * This class implements a policy for reader/writer locks in which
 * threads contend in a First-in/First-out manner for access (modulo
 * the limitations of FIFOSemaphore, which is used for queuing).  This
 * policy does not particularly favor readers or writers.  As a
 * byproduct of the FIFO policy, the <tt>attempt</tt> methods may
 * return <tt>false</tt> even when the lock might logically be
 * available, but, due to contention, cannot be accessed within the
 * given time bound.  <p>
 *
 * This lock is <em>NOT</em> reentrant. Current readers and
 * writers should not try to re-obtain locks while holding them.
 * <p>
 *
 * [<a href="http://gee.cs.oswego.edu/dl/classes/EDU/oswego/cs/dl/util/concurrent/intro.html"> Introduction to this package. </a>] <p>
 *
 * @see FIFOSemaphore
**/

public class FIFOReadWriteLock implements ReadWriteLock {

  /** 
   * Fair Semaphore serving as a kind of mutual exclusion lock.
   * Writers acquire on entry, and hold until rwlock exit.
   * Readers acquire and release only during entry (but are
   * blocked from doing so if there is an active writer).
   **/
  protected final FIFOSemaphore entryLock = new FIFOSemaphore(1);

  /** 
   * Number of threads that have entered read lock.  Note that this is
   * never reset to zero. Incremented only during acquisition of read
   * lock while the "entryLock" is held, but read elsewhere, so is
   * declared volatile.
   **/
  protected volatile int readers;

  /** 
   * Number of threads that have exited read lock.  Note that this is
   * never reset to zero. Accessed only in code protected by
   * synchronized(this). When exreaders != readers, the rwlock is
   * being used for reading. Else if the entry lock is held, it is
   * being used for writing (or in transition). Else it is free.
   * Note: To distinguish these states, we assume that fewer than 2^32
   * reader threads can simultaneously execute.
   **/
  protected int exreaders;

  protected void acquireRead() throws InterruptedException {
    entryLock.acquire();
    ++readers; 
    entryLock.release();
  }

  protected synchronized void releaseRead() {
    /*
      If this is the last reader, notify a possibly waiting writer.
      Because waits occur only when entry lock is held, at most one
      writer can be waiting for this notification.  Because increments
      to "readers" aren't protected by "this" lock, the notification
      may be spurious (when an incoming reader in in the process of
      updating the field), but at the point tested in acquiring write
      lock, both locks will be held, thus avoiding false alarms. And
      we will never miss an opportunity to send a notification when it
      is actually needed.
    */

    if (++exreaders == readers) 
      notify(); 
  }

  protected void acquireWrite() throws InterruptedException {
    // Acquiring entryLock first forces subsequent entering readers
    // (as well as writers) to block.
    entryLock.acquire();
    
    // Only read "readers" once now before loop.  We know it won't
    // change because we hold the entry lock needed to update it.
    int r = readers;
    
    try {
      synchronized(this) {
        while (exreaders != r) 
          wait();
      }
    }
    catch (InterruptedException ie) {
      entryLock.release();
      throw ie;
    }
  }

  protected void releaseWrite() {
    entryLock.release();
  }

  protected boolean attemptRead(long msecs) throws InterruptedException {
    if (!entryLock.attempt(msecs)) 
      return false;

    ++readers; 
    entryLock.release();
    return true;
  }

  protected boolean attemptWrite(long msecs) throws InterruptedException {
    long startTime = (msecs <= 0)? 0 : System.currentTimeMillis();

    if (!entryLock.attempt(msecs)) 
      return false;

    int r = readers;

    try {
      synchronized(this) {
        while (exreaders != r) {
          long timeLeft = (msecs <= 0)? 0:
            msecs - (System.currentTimeMillis() - startTime);
          
          if (timeLeft <= 0) {
            entryLock.release();
            return false;
          }
          
          wait(timeLeft);
        }
        return true;
      }
    }
    catch (InterruptedException ie) {
      entryLock.release();
      throw ie;
    }
  }

  // support for ReadWriteLock interface

  protected class ReaderSync implements Sync {
    public void acquire() throws InterruptedException {
      acquireRead();
    }
    public  void release()  { 
      releaseRead();
    }
    public boolean attempt(long msecs) throws InterruptedException {
      return attemptRead(msecs);
    }
  }

  protected class WriterSync implements Sync {
    public void acquire() throws InterruptedException {
      acquireWrite();
    }
    public  void release()  { 
      releaseWrite();
    }
    public boolean attempt(long msecs) throws InterruptedException {
      return attemptWrite(msecs);
    }
  }

  protected final Sync readerSync = new ReaderSync();
  protected final Sync writerSync = new WriterSync();

  public Sync writeLock() { return writerSync; }
  public Sync readLock() { return readerSync; }

}