@@ -33,91 +33,7 @@ module Concurrent
33
33
#
34
34
# @see https://docs.oracle.com/javase/7/docs/api/java/lang/ThreadLocal.html Java ThreadLocal
35
35
#
36
- # @!visibility private
37
- class AbstractThreadLocalVar
38
-
39
- # @!visibility private
40
- NIL_SENTINEL = Object . new
41
- private_constant :NIL_SENTINEL
42
-
43
- # @!macro [attach] thread_local_var_method_initialize
44
- #
45
- # Creates a thread local variable.
46
- #
47
- # @param [Object] default the default value when otherwise unset
48
- def initialize ( default = nil )
49
- @default = default
50
- allocate_storage
51
- end
52
-
53
- # @!macro [attach] thread_local_var_method_get
54
- #
55
- # Returns the value in the current thread's copy of this thread-local variable.
56
- #
57
- # @return [Object] the current value
58
- def value
59
- value = get
60
-
61
- if value . nil?
62
- @default
63
- elsif value == NIL_SENTINEL
64
- nil
65
- else
66
- value
67
- end
68
- end
69
-
70
- # @!macro [attach] thread_local_var_method_set
71
- #
72
- # Sets the current thread's copy of this thread-local variable to the specified value.
73
- #
74
- # @param [Object] value the value to set
75
- # @return [Object] the new value
76
- def value = ( value )
77
- bind value
78
- end
79
-
80
- # @!macro [attach] thread_local_var_method_bind
81
- #
82
- # Bind the given value to thread local storage during
83
- # execution of the given block.
84
- #
85
- # @param [Object] value the value to bind
86
- # @yield the operation to be performed with the bound variable
87
- # @return [Object] the value
88
- def bind ( value , &block )
89
- if value . nil?
90
- stored_value = NIL_SENTINEL
91
- else
92
- stored_value = value
93
- end
94
-
95
- set ( stored_value , &block )
96
-
97
- value
98
- end
99
-
100
- protected
101
-
102
- # @!visibility private
103
- def allocate_storage
104
- raise NotImplementedError
105
- end
106
-
107
- # @!visibility private
108
- def get
109
- raise NotImplementedError
110
- end
111
-
112
- # @!visibility private
113
- def set ( value )
114
- raise NotImplementedError
115
- end
116
- end
117
-
118
- # @!visibility private
119
- # @!macro internal_implementation_note
120
- class RubyThreadLocalVar < AbstractThreadLocalVar
36
+ class ThreadLocalVar
121
37
122
38
# Each thread has a (lazily initialized) array of thread-local variable values
123
39
# Each time a new thread-local var is created, we allocate an "index" for it
@@ -140,40 +56,19 @@ class RubyThreadLocalVar < AbstractThreadLocalVar
140
56
# But when a Thread is GC'd, we need to drop the reference to its thread-local
141
57
# array, so we don't leak memory
142
58
59
+ # @!visibility private
60
+ NIL_SENTINEL = Object . new
143
61
FREE = [ ]
144
62
LOCK = Mutex . new
145
63
ARRAYS = { } # used as a hash set
146
64
@@next = 0
65
+ private_constant :NIL_SENTINEL , :FREE , :LOCK , :ARRAYS
147
66
148
- protected
149
-
150
- # @!visibility private
151
- def self . threadlocal_finalizer ( index )
152
- proc do
153
- LOCK . synchronize do
154
- FREE . push ( index )
155
- # The cost of GC'ing a TLV is linear in the number of threads using TLVs
156
- # But that is natural! More threads means more storage is used per TLV
157
- # So naturally more CPU time is required to free more storage
158
- ARRAYS . each_value do |array |
159
- array [ index ] = nil
160
- end
161
- end
162
- end
163
- end
164
-
165
- # @!visibility private
166
- def self . thread_finalizer ( array )
167
- proc do
168
- LOCK . synchronize do
169
- # The thread which used this thread-local array is now gone
170
- # So don't hold onto a reference to the array (thus blocking GC)
171
- ARRAYS . delete ( array . object_id )
172
- end
173
- end
174
- end
175
-
176
- def allocate_storage
67
+ # Creates a thread local variable.
68
+ #
69
+ # @param [Object] default the default value when otherwise unset
70
+ def initialize ( default = nil )
71
+ @default = default
177
72
@index = LOCK . synchronize do
178
73
FREE . pop || begin
179
74
result = @@next
@@ -184,10 +79,6 @@ def allocate_storage
184
79
ObjectSpace . define_finalizer ( self , self . class . threadlocal_finalizer ( @index ) )
185
80
end
186
81
187
- public
188
-
189
- # @!macro [attach] thread_local_var_method_get
190
- #
191
82
# Returns the value in the current thread's copy of this thread-local variable.
192
83
#
193
84
# @return [Object] the current value
@@ -206,8 +97,6 @@ def value
206
97
end
207
98
end
208
99
209
- # @!macro [attach] thread_local_var_method_set
210
- #
211
100
# Sets the current thread's copy of this thread-local variable to the specified value.
212
101
#
213
102
# @param [Object] value the value to set
@@ -226,8 +115,34 @@ def value=(value)
226
115
value
227
116
end
228
117
229
- # @!macro [attach] thread_local_var_method_bind
230
- #
118
+ protected
119
+
120
+ # @!visibility private
121
+ def self . threadlocal_finalizer ( index )
122
+ proc do
123
+ LOCK . synchronize do
124
+ FREE . push ( index )
125
+ # The cost of GC'ing a TLV is linear in the number of threads using TLVs
126
+ # But that is natural! More threads means more storage is used per TLV
127
+ # So naturally more CPU time is required to free more storage
128
+ ARRAYS . each_value do |array |
129
+ array [ index ] = nil
130
+ end
131
+ end
132
+ end
133
+ end
134
+
135
+ # @!visibility private
136
+ def self . thread_finalizer ( array )
137
+ proc do
138
+ LOCK . synchronize do
139
+ # The thread which used this thread-local array is now gone
140
+ # So don't hold onto a reference to the array (thus blocking GC)
141
+ ARRAYS . delete ( array . object_id )
142
+ end
143
+ end
144
+ end
145
+
231
146
# Bind the given value to thread local storage during
232
147
# execution of the given block.
233
148
#
@@ -246,56 +161,4 @@ def bind(value, &block)
246
161
end
247
162
end
248
163
end
249
-
250
- if Concurrent . on_jruby?
251
-
252
- # @!visibility private
253
- # @!macro internal_implementation_note
254
- class JavaThreadLocalVar < AbstractThreadLocalVar
255
-
256
- protected
257
-
258
- # @!visibility private
259
- def allocate_storage
260
- @var = java . lang . ThreadLocal . new
261
- end
262
-
263
- # @!visibility private
264
- def get
265
- @var . get
266
- end
267
-
268
- # @!visibility private
269
- def set ( value )
270
- @var . set ( value )
271
- end
272
- end
273
- end
274
-
275
- # @!visibility private
276
- # @!macro internal_implementation_note
277
- ThreadLocalVarImplementation = case
278
- when Concurrent . on_jruby?
279
- JavaThreadLocalVar
280
- else
281
- RubyThreadLocalVar
282
- end
283
- private_constant :ThreadLocalVarImplementation
284
-
285
- # @!macro thread_local_var
286
- class ThreadLocalVar < ThreadLocalVarImplementation
287
-
288
- # @!method initialize(default = nil)
289
- # @!macro thread_local_var_method_initialize
290
-
291
- # @!method value
292
- # @!macro thread_local_var_method_get
293
-
294
- # @!method value=(value)
295
- # @!macro thread_local_var_method_set
296
-
297
- # @!method bind(value, &block)
298
- # @!macro thread_local_var_method_bind
299
-
300
- end
301
164
end
0 commit comments