@@ -33,91 +33,7 @@ module Concurrent
3333 #
3434 # @see https://docs.oracle.com/javase/7/docs/api/java/lang/ThreadLocal.html Java ThreadLocal
3535 #
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
12137
12238 # Each thread has a (lazily initialized) array of thread-local variable values
12339 # Each time a new thread-local var is created, we allocate an "index" for it
@@ -140,40 +56,19 @@ class RubyThreadLocalVar < AbstractThreadLocalVar
14056 # But when a Thread is GC'd, we need to drop the reference to its thread-local
14157 # array, so we don't leak memory
14258
59+ # @!visibility private
60+ NIL_SENTINEL = Object . new
14361 FREE = [ ]
14462 LOCK = Mutex . new
14563 ARRAYS = { } # used as a hash set
14664 @@next = 0
65+ private_constant :NIL_SENTINEL , :FREE , :LOCK , :ARRAYS
14766
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
17772 @index = LOCK . synchronize do
17873 FREE . pop || begin
17974 result = @@next
@@ -184,10 +79,6 @@ def allocate_storage
18479 ObjectSpace . define_finalizer ( self , self . class . threadlocal_finalizer ( @index ) )
18580 end
18681
187- public
188-
189- # @!macro [attach] thread_local_var_method_get
190- #
19182 # Returns the value in the current thread's copy of this thread-local variable.
19283 #
19384 # @return [Object] the current value
@@ -206,8 +97,6 @@ def value
20697 end
20798 end
20899
209- # @!macro [attach] thread_local_var_method_set
210- #
211100 # Sets the current thread's copy of this thread-local variable to the specified value.
212101 #
213102 # @param [Object] value the value to set
@@ -226,8 +115,34 @@ def value=(value)
226115 value
227116 end
228117
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+
231146 # Bind the given value to thread local storage during
232147 # execution of the given block.
233148 #
@@ -246,56 +161,4 @@ def bind(value, &block)
246161 end
247162 end
248163 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
301164end
0 commit comments