4
4
5
5
import java .util .concurrent .Callable ;
6
6
import java .util .concurrent .locks .StampedLock ;
7
+ import java .util .function .Supplier ;
7
8
8
9
/**
9
10
* Helper functions for {@code StampedLock}s.
@@ -29,7 +30,7 @@ private StampedLocks()
29
30
*
30
31
* @param <V> the type of value returned by the task
31
32
* @param lock a lock
32
- * @param task the task to run while holding the lock
33
+ * @param task the task to run
33
34
* @return the value returned by the task
34
35
* @throws NullPointerException if any of the arguments are null
35
36
* @throws WrappedCheckedException if any checked exceptions are thrown
@@ -51,7 +52,7 @@ public static <V> V optimisticRead(StampedLock lock, Callable<V> task)
51
52
*
52
53
* @param <V> the type of value returned by the task
53
54
* @param lock a lock
54
- * @param task the task to run while holding the lock
55
+ * @param task the task to run
55
56
* @return the value returned by the task
56
57
* @throws NullPointerException if any of the arguments are null
57
58
* @throws WrappedCheckedException if {@code task} throws a checked exception
@@ -73,26 +74,30 @@ public static <V> V read(StampedLock lock, Callable<V> task)
73
74
* Acquires a write lock and runs a task.
74
75
*
75
76
* @param lock a lock
76
- * @param task the task to run while holding the lock
77
- * @return a write lock as a resource
78
- * @throws NullPointerException if {@code lock} is null
77
+ * @param task the task to run
78
+ * @throws NullPointerException if any of the arguments are null
79
79
*/
80
- public static < V > V write (StampedLock lock , Runnable task )
80
+ public static void write (StampedLock lock , Runnable task )
81
81
{
82
- return write (lock , () ->
82
+ long stamp = lock .writeLock ();
83
+ try
83
84
{
84
- task .run ();
85
- return null ;
86
- });
85
+ runTask (task );
86
+ }
87
+ finally
88
+ {
89
+ lock .unlockWrite (stamp );
90
+ }
87
91
}
88
92
89
93
/**
90
94
* Acquires a write lock and runs a task.
91
95
*
96
+ * @param <V> the type of value returned by the task
92
97
* @param lock a lock
93
- * @param task the task to run while holding the lock
94
- * @return a write lock as a resource
95
- * @throws NullPointerException if {@code lock} is null
98
+ * @param task the task to run
99
+ * @return the value returned by the task
100
+ * @throws NullPointerException if any of the arguments are null
96
101
*/
97
102
public static <V > V write (StampedLock lock , Callable <V > task )
98
103
{
@@ -107,11 +112,30 @@ public static <V> V write(StampedLock lock, Callable<V> task)
107
112
}
108
113
}
109
114
115
+ /**
116
+ * Runs a task.
117
+ *
118
+ * @param task the task to run
119
+ * @throws NullPointerException if {@code task} is null
120
+ * @throws WrappedCheckedException if {@code task} throws a checked exception
121
+ */
122
+ private static void runTask (Runnable task )
123
+ {
124
+ try
125
+ {
126
+ task .run ();
127
+ }
128
+ catch (Exception e )
129
+ {
130
+ throw WrappedCheckedException .wrap (e );
131
+ }
132
+ }
133
+
110
134
/**
111
135
* Runs a task.
112
136
*
113
137
* @param <V> the type of value returned by the task
114
- * @param task the task to run while holding the lock
138
+ * @param task the task to run
115
139
* @return the value returned by the task
116
140
* @throws NullPointerException if {@code task} is null
117
141
* @throws WrappedCheckedException if {@code task} throws a checked exception
@@ -127,4 +151,105 @@ private static <V> V runTask(Callable<V> task)
127
151
throw WrappedCheckedException .wrap (e );
128
152
}
129
153
}
154
+
155
+ /**
156
+ * Returns a value, initializing it if it hasn't been initialized yet.
157
+ *
158
+ * @param <V> the type of value returned by the task
159
+ * @param lock the lock used to ensure thread safety
160
+ * @param supplier returns the value, or {@code null} if it hasn't been initialized yet
161
+ * @param initializer initializes the value if it hasn't been initialized yet and returns it
162
+ * @return the initialized value
163
+ * @throws NullPointerException if any of the arguments are null
164
+ */
165
+ public static <V > V getLazilyInitializedValue (StampedLock lock , Supplier <V > supplier ,
166
+ Callable <V > initializer )
167
+ {
168
+ long stamp = lock .tryOptimisticRead ();
169
+ if (stamp == 0 )
170
+ return getLazilyInitializedValueUsingRead (lock , supplier , initializer );
171
+ V value = supplier .get ();
172
+ if (!lock .validate (stamp ))
173
+ return getLazilyInitializedValueUsingRead (lock , supplier , initializer );
174
+ if (value != null )
175
+ return value ;
176
+ stamp = lock .tryConvertToWriteLock (stamp );
177
+ if (stamp == 0 )
178
+ return getLazilyInitializedValueUsingWrite (lock , supplier , initializer );
179
+ try
180
+ {
181
+ return runTask (initializer );
182
+ }
183
+ finally
184
+ {
185
+ lock .unlockWrite (stamp );
186
+ }
187
+ }
188
+
189
+ /**
190
+ * Returns a value, initializing it if it hasn't been initialized yet, using a read lock.
191
+ *
192
+ * @param <V> the type of value returned by the task
193
+ * @param lock the lock used to ensure thread safety
194
+ * @param supplier returns the value, or {@code null} if it hasn't been initialized yet
195
+ * @param initializer initializes the value if it hasn't been initialized yet
196
+ * @return the initialized value
197
+ * @throws NullPointerException if any of the arguments are null
198
+ */
199
+ private static <V > V getLazilyInitializedValueUsingRead (StampedLock lock , Supplier <V > supplier ,
200
+ Callable <V > initializer )
201
+ {
202
+ long stamp = lock .readLock ();
203
+ V value ;
204
+ try
205
+ {
206
+ value = supplier .get ();
207
+ }
208
+ catch (RuntimeException e )
209
+ {
210
+ lock .unlockRead (stamp );
211
+ throw e ;
212
+ }
213
+ if (value != null )
214
+ {
215
+ lock .unlockRead (stamp );
216
+ return value ;
217
+ }
218
+ stamp = lock .tryConvertToWriteLock (stamp );
219
+ if (stamp == 0 )
220
+ {
221
+ lock .unlockRead (stamp );
222
+ return getLazilyInitializedValueUsingWrite (lock , supplier , initializer );
223
+ }
224
+ try
225
+ {
226
+ return runTask (initializer );
227
+ }
228
+ finally
229
+ {
230
+ lock .unlockWrite (stamp );
231
+ }
232
+ }
233
+
234
+ /**
235
+ * Returns a value, initializing it if it hasn't been initialized yet, using a write lock.
236
+ *
237
+ * @param <V> the type of value returned by the task
238
+ * @param lock the lock used to ensure thread safety
239
+ * @param supplier returns the value, or {@code null} if it hasn't been initialized yet
240
+ * @param initializer initializes the value if it hasn't been initialized yet
241
+ * @return the value
242
+ * @throws NullPointerException if any of the arguments are null
243
+ */
244
+ private static <V > V getLazilyInitializedValueUsingWrite (StampedLock lock , Supplier <V > supplier ,
245
+ Callable <V > initializer )
246
+ {
247
+ return write (lock , () ->
248
+ {
249
+ V value = supplier .get ();
250
+ if (value != null )
251
+ return value ;
252
+ return runTask (initializer );
253
+ });
254
+ }
130
255
}
0 commit comments