concurrent-ruby 0.9.2 → 1.0.0.pre1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (77) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +15 -1
  3. data/README.md +67 -68
  4. data/lib/concurrent.rb +14 -1
  5. data/lib/concurrent/array.rb +38 -0
  6. data/lib/concurrent/async.rb +0 -17
  7. data/lib/concurrent/atomic/abstract_thread_local_var.rb +40 -0
  8. data/lib/concurrent/atomic/atomic_boolean.rb +81 -118
  9. data/lib/concurrent/atomic/atomic_fixnum.rb +98 -162
  10. data/lib/concurrent/atomic/atomic_reference.rb +0 -7
  11. data/lib/concurrent/atomic/count_down_latch.rb +62 -103
  12. data/lib/concurrent/atomic/cyclic_barrier.rb +2 -0
  13. data/lib/concurrent/atomic/java_count_down_latch.rb +39 -0
  14. data/lib/concurrent/atomic/java_thread_local_var.rb +50 -0
  15. data/lib/concurrent/atomic/mutex_atomic_boolean.rb +60 -0
  16. data/lib/concurrent/atomic/mutex_atomic_fixnum.rb +91 -0
  17. data/lib/concurrent/atomic/mutex_count_down_latch.rb +43 -0
  18. data/lib/concurrent/atomic/mutex_semaphore.rb +115 -0
  19. data/lib/concurrent/atomic/ruby_thread_local_var.rb +172 -0
  20. data/lib/concurrent/atomic/semaphore.rb +84 -178
  21. data/lib/concurrent/atomic/thread_local_var.rb +63 -294
  22. data/lib/concurrent/atomic_reference/mutex_atomic.rb +14 -8
  23. data/lib/concurrent/atomics.rb +0 -33
  24. data/lib/concurrent/collection/java_non_concurrent_priority_queue.rb +84 -0
  25. data/lib/concurrent/collection/map/atomic_reference_map_backend.rb +921 -0
  26. data/lib/concurrent/collection/map/mri_map_backend.rb +66 -0
  27. data/lib/concurrent/collection/map/non_concurrent_map_backend.rb +142 -0
  28. data/lib/concurrent/collection/map/synchronized_map_backend.rb +86 -0
  29. data/lib/concurrent/collection/non_concurrent_priority_queue.rb +143 -0
  30. data/lib/concurrent/collection/ruby_non_concurrent_priority_queue.rb +150 -0
  31. data/lib/concurrent/concern/logging.rb +1 -1
  32. data/lib/concurrent/concern/obligation.rb +0 -12
  33. data/lib/concurrent/configuration.rb +18 -148
  34. data/lib/concurrent/delay.rb +5 -4
  35. data/lib/concurrent/exchanger.rb +327 -41
  36. data/lib/concurrent/executor/abstract_executor_service.rb +134 -0
  37. data/lib/concurrent/executor/executor.rb +4 -29
  38. data/lib/concurrent/executor/executor_service.rb +23 -359
  39. data/lib/concurrent/executor/immediate_executor.rb +3 -2
  40. data/lib/concurrent/executor/java_executor_service.rb +100 -0
  41. data/lib/concurrent/executor/java_single_thread_executor.rb +3 -2
  42. data/lib/concurrent/executor/java_thread_pool_executor.rb +3 -4
  43. data/lib/concurrent/executor/ruby_executor_service.rb +72 -0
  44. data/lib/concurrent/executor/ruby_single_thread_executor.rb +7 -5
  45. data/lib/concurrent/executor/ruby_thread_pool_executor.rb +3 -11
  46. data/lib/concurrent/executor/safe_task_executor.rb +1 -1
  47. data/lib/concurrent/executor/serial_executor_service.rb +34 -0
  48. data/lib/concurrent/executor/serialized_execution.rb +8 -31
  49. data/lib/concurrent/executor/serialized_execution_delegator.rb +28 -0
  50. data/lib/concurrent/executor/simple_executor_service.rb +1 -10
  51. data/lib/concurrent/executor/timer_set.rb +4 -8
  52. data/lib/concurrent/executors.rb +13 -2
  53. data/lib/concurrent/future.rb +2 -2
  54. data/lib/concurrent/hash.rb +35 -0
  55. data/lib/concurrent/ivar.rb +9 -14
  56. data/lib/concurrent/map.rb +178 -0
  57. data/lib/concurrent/promise.rb +2 -2
  58. data/lib/concurrent/scheduled_task.rb +9 -69
  59. data/lib/concurrent/thread_safe/synchronized_delegator.rb +50 -0
  60. data/lib/concurrent/thread_safe/util.rb +23 -0
  61. data/lib/concurrent/thread_safe/util/adder.rb +71 -0
  62. data/lib/concurrent/thread_safe/util/array_hash_rbx.rb +28 -0
  63. data/lib/concurrent/thread_safe/util/cheap_lockable.rb +115 -0
  64. data/lib/concurrent/thread_safe/util/power_of_two_tuple.rb +37 -0
  65. data/lib/concurrent/thread_safe/util/striped64.rb +236 -0
  66. data/lib/concurrent/thread_safe/util/volatile.rb +73 -0
  67. data/lib/concurrent/thread_safe/util/xor_shift_random.rb +48 -0
  68. data/lib/concurrent/timer_task.rb +3 -3
  69. data/lib/concurrent/tuple.rb +86 -0
  70. data/lib/concurrent/version.rb +2 -2
  71. metadata +37 -10
  72. data/lib/concurrent/atomic/condition.rb +0 -78
  73. data/lib/concurrent/collection/priority_queue.rb +0 -360
  74. data/lib/concurrent/utilities.rb +0 -5
  75. data/lib/concurrent/utility/timeout.rb +0 -39
  76. data/lib/concurrent/utility/timer.rb +0 -26
  77. data/lib/concurrent_ruby.rb +0 -2
@@ -1,171 +1,92 @@
1
- require 'concurrent/synchronization'
1
+ require 'concurrent/atomic/mutex_semaphore'
2
+ require 'concurrent/utility/native_extension_loader'
2
3
 
3
4
  module Concurrent
4
5
 
5
- # @!macro [attach] semaphore
6
+ ###################################################################
7
+
8
+ # @!macro [new] semaphore_method_initialize
6
9
  #
7
- # A counting semaphore. Conceptually, a semaphore maintains a set of
8
- # permits. Each {#acquire} blocks if necessary until a permit is
9
- # available, and then takes it. Each {#release} adds a permit, potentially
10
- # releasing a blocking acquirer.
11
- # However, no actual permit objects are used; the Semaphore just keeps a
12
- # count of the number available and acts accordingly.
10
+ # Create a new `Semaphore` with the initial `count`.
13
11
  #
14
- # @!visibility private
12
+ # @param [Fixnum] count the initial count
15
13
  #
16
- # @!macro internal_implementation_note
17
- class MutexSemaphore < Synchronization::Object
18
-
19
- # @!macro [attach] semaphore_method_initialize
20
- #
21
- # Create a new `Semaphore` with the initial `count`.
22
- #
23
- # @param [Fixnum] count the initial count
24
- #
25
- # @raise [ArgumentError] if `count` is not an integer or is less than zero
26
- def initialize(count)
27
- unless count.is_a?(Fixnum) && count >= 0
28
- fail ArgumentError, 'count must be an non-negative integer'
29
- end
30
- super()
31
- synchronize { ns_initialize count }
32
- end
33
-
34
- # @!macro [attach] semaphore_method_acquire
35
- #
36
- # Acquires the given number of permits from this semaphore,
37
- # blocking until all are available.
38
- #
39
- # @param [Fixnum] permits Number of permits to acquire
40
- #
41
- # @raise [ArgumentError] if `permits` is not an integer or is less than
42
- # one
43
- #
44
- # @return [Nil]
45
- def acquire(permits = 1)
46
- unless permits.is_a?(Fixnum) && permits > 0
47
- fail ArgumentError, 'permits must be an integer greater than zero'
48
- end
49
- synchronize do
50
- try_acquire_timed(permits, nil)
51
- nil
52
- end
53
- end
54
-
55
- # @!macro [attach] semaphore_method_available_permits
56
- #
57
- # Returns the current number of permits available in this semaphore.
58
- #
59
- # @return [Integer]
60
- def available_permits
61
- synchronize { @free }
62
- end
63
-
64
- # @!macro [attach] semaphore_method_drain_permits
65
- #
66
- # Acquires and returns all permits that are immediately available.
67
- #
68
- # @return [Integer]
69
- def drain_permits
70
- synchronize do
71
- @free.tap { |_| @free = 0 }
72
- end
73
- end
14
+ # @raise [ArgumentError] if `count` is not an integer or is less than zero
74
15
 
75
- # @!macro [attach] semaphore_method_try_acquire
76
- #
77
- # Acquires the given number of permits from this semaphore,
78
- # only if all are available at the time of invocation or within
79
- # `timeout` interval
80
- #
81
- # @param [Fixnum] permits the number of permits to acquire
82
- #
83
- # @param [Fixnum] timeout the number of seconds to wait for the counter
84
- # or `nil` to return immediately
85
- #
86
- # @raise [ArgumentError] if `permits` is not an integer or is less than
87
- # one
88
- #
89
- # @return [Boolean] `false` if no permits are available, `true` when
90
- # acquired a permit
91
- def try_acquire(permits = 1, timeout = nil)
92
- unless permits.is_a?(Fixnum) && permits > 0
93
- fail ArgumentError, 'permits must be an integer greater than zero'
94
- end
95
- synchronize do
96
- if timeout.nil?
97
- try_acquire_now(permits)
98
- else
99
- try_acquire_timed(permits, timeout)
100
- end
101
- end
102
- end
16
+ # @!macro [new] semaphore_method_acquire
17
+ #
18
+ # Acquires the given number of permits from this semaphore,
19
+ # blocking until all are available.
20
+ #
21
+ # @param [Fixnum] permits Number of permits to acquire
22
+ #
23
+ # @raise [ArgumentError] if `permits` is not an integer or is less than
24
+ # one
25
+ #
26
+ # @return [nil]
103
27
 
104
- # @!macro [attach] semaphore_method_release
105
- #
106
- # Releases the given number of permits, returning them to the semaphore.
107
- #
108
- # @param [Fixnum] permits Number of permits to return to the semaphore.
109
- #
110
- # @raise [ArgumentError] if `permits` is not a number or is less than one
111
- #
112
- # @return [Nil]
113
- def release(permits = 1)
114
- unless permits.is_a?(Fixnum) && permits > 0
115
- fail ArgumentError, 'permits must be an integer greater than zero'
116
- end
117
- synchronize do
118
- @free += permits
119
- permits.times { ns_signal }
120
- end
121
- nil
122
- end
28
+ # @!macro [new] semaphore_method_available_permits
29
+ #
30
+ # Returns the current number of permits available in this semaphore.
31
+ #
32
+ # @return [Integer]
123
33
 
124
- # @!macro [attach] semaphore_method_reduce_permits
125
- #
126
- # @api private
127
- #
128
- # Shrinks the number of available permits by the indicated reduction.
129
- #
130
- # @param [Fixnum] reduction Number of permits to remove.
131
- #
132
- # @raise [ArgumentError] if `reduction` is not an integer or is negative
133
- #
134
- # @raise [ArgumentError] if `@free` - `@reduction` is less than zero
135
- #
136
- # @return [Nil]
137
- def reduce_permits(reduction)
138
- unless reduction.is_a?(Fixnum) && reduction >= 0
139
- fail ArgumentError, 'reduction must be an non-negative integer'
140
- end
141
- synchronize { @free -= reduction }
142
- nil
143
- end
34
+ # @!macro [new] semaphore_method_drain_permits
35
+ #
36
+ # Acquires and returns all permits that are immediately available.
37
+ #
38
+ # @return [Integer]
144
39
 
145
- protected
40
+ # @!macro [new] semaphore_method_try_acquire
41
+ #
42
+ # Acquires the given number of permits from this semaphore,
43
+ # only if all are available at the time of invocation or within
44
+ # `timeout` interval
45
+ #
46
+ # @param [Fixnum] permits the number of permits to acquire
47
+ #
48
+ # @param [Fixnum] timeout the number of seconds to wait for the counter
49
+ # or `nil` to return immediately
50
+ #
51
+ # @raise [ArgumentError] if `permits` is not an integer or is less than
52
+ # one
53
+ #
54
+ # @return [Boolean] `false` if no permits are available, `true` when
55
+ # acquired a permit
146
56
 
147
- # @!visibility private
148
- def ns_initialize(count)
149
- @free = count
150
- end
57
+ # @!macro [new] semaphore_method_release
58
+ #
59
+ # Releases the given number of permits, returning them to the semaphore.
60
+ #
61
+ # @param [Fixnum] permits Number of permits to return to the semaphore.
62
+ #
63
+ # @raise [ArgumentError] if `permits` is not a number or is less than one
64
+ #
65
+ # @return [nil]
151
66
 
152
- private
67
+ ###################################################################
153
68
 
154
- # @!visibility private
155
- def try_acquire_now(permits)
156
- if @free >= permits
157
- @free -= permits
158
- true
159
- else
160
- false
161
- end
162
- end
69
+ # @!macro [new] semaphore_public_api
70
+ #
71
+ # @!method initialize(count)
72
+ # @!macro semaphore_method_initialize
73
+ #
74
+ # @!method acquire(permits = 1)
75
+ # @!macro semaphore_method_acquire
76
+ #
77
+ # @!method available_permits
78
+ # @!macro semaphore_method_available_permits
79
+ #
80
+ # @!method drain_permits
81
+ # @!macro semaphore_method_drain_permits
82
+ #
83
+ # @!method try_acquire(permits = 1, timeout = nil)
84
+ # @!macro semaphore_method_try_acquire
85
+ #
86
+ # @!method release(permits = 1)
87
+ # @!macro semaphore_method_release
163
88
 
164
- # @!visibility private
165
- def try_acquire_timed(permits, timeout)
166
- ns_wait_until(timeout) { try_acquire_now(permits) }
167
- end
168
- end
89
+ ###################################################################
169
90
 
170
91
  # @!visibility private
171
92
  # @!macro internal_implementation_note
@@ -177,31 +98,16 @@ module Concurrent
177
98
  end
178
99
  private_constant :SemaphoreImplementation
179
100
 
180
- # @!macro semaphore
101
+ # @!macro [attach] semaphore
181
102
  #
182
- # @see Concurrent::MutexSemaphore
103
+ # A counting semaphore. Conceptually, a semaphore maintains a set of
104
+ # permits. Each {#acquire} blocks if necessary until a permit is
105
+ # available, and then takes it. Each {#release} adds a permit, potentially
106
+ # releasing a blocking acquirer.
107
+ # However, no actual permit objects are used; the Semaphore just keeps a
108
+ # count of the number available and acts accordingly.
109
+ #
110
+ # @!macro semaphore_public_api
183
111
  class Semaphore < SemaphoreImplementation
184
-
185
- # @!method initialize(count)
186
- # @!macro semaphore_method_initialize
187
-
188
- # @!method acquire(permits = 1)
189
- # @!macro semaphore_method_acquire
190
-
191
- # @!method available_permits
192
- # @!macro semaphore_method_available_permits
193
-
194
- # @!method drain_permits
195
- # @!macro semaphore_method_drain_permits
196
-
197
- # @!method try_acquire(permits = 1, timeout = nil)
198
- # @!macro semaphore_method_try_acquire
199
-
200
- # @!method release(permits = 1)
201
- # @!macro semaphore_method_release
202
-
203
- # @!method reduce_permits(reduction)
204
- # @!macro semaphore_method_reduce_permits
205
-
206
112
  end
207
113
  end
@@ -1,7 +1,68 @@
1
- require 'thread'
1
+ require 'concurrent/atomic/ruby_thread_local_var'
2
+ require 'concurrent/atomic/java_thread_local_var'
3
+ require 'concurrent/utility/engine'
2
4
 
3
5
  module Concurrent
4
6
 
7
+ ###################################################################
8
+
9
+ # @!macro [new] thread_local_var_method_initialize
10
+ #
11
+ # Creates a thread local variable.
12
+ #
13
+ # @param [Object] default the default value when otherwise unset
14
+
15
+ # @!macro [new] thread_local_var_method_get
16
+ #
17
+ # Returns the value in the current thread's copy of this thread-local variable.
18
+ #
19
+ # @return [Object] the current value
20
+
21
+ # @!macro [new] thread_local_var_method_set
22
+ #
23
+ # Sets the current thread's copy of this thread-local variable to the specified value.
24
+ #
25
+ # @param [Object] value the value to set
26
+ # @return [Object] the new value
27
+
28
+ # @!macro [new] thread_local_var_method_bind
29
+ #
30
+ # Bind the given value to thread local storage during
31
+ # execution of the given block.
32
+ #
33
+ # @param [Object] value the value to bind
34
+ # @yield the operation to be performed with the bound variable
35
+ # @return [Object] the value
36
+
37
+
38
+ ###################################################################
39
+
40
+ # @!macro [new] thread_local_var_public_api
41
+ #
42
+ # @!method initialize(default = nil)
43
+ # @!macro thread_local_var_method_initialize
44
+ #
45
+ # @!method value
46
+ # @!macro thread_local_var_method_get
47
+ #
48
+ # @!method value=(value)
49
+ # @!macro thread_local_var_method_set
50
+ #
51
+ # @!method bind(value, &block)
52
+ # @!macro thread_local_var_method_bind
53
+
54
+ ###################################################################
55
+
56
+ # @!visibility private
57
+ # @!macro internal_implementation_note
58
+ ThreadLocalVarImplementation = case
59
+ when Concurrent.on_jruby?
60
+ JavaThreadLocalVar
61
+ else
62
+ RubyThreadLocalVar
63
+ end
64
+ private_constant :ThreadLocalVarImplementation
65
+
5
66
  # @!macro [attach] thread_local_var
6
67
  #
7
68
  # A `ThreadLocalVar` is a variable where the value is different for each thread.
@@ -33,299 +94,7 @@ module Concurrent
33
94
  #
34
95
  # @see https://docs.oracle.com/javase/7/docs/api/java/lang/ThreadLocal.html Java ThreadLocal
35
96
  #
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
- raise NotImplementedError
60
- end
61
-
62
- # @!macro [attach] thread_local_var_method_set
63
- #
64
- # Sets the current thread's copy of this thread-local variable to the specified value.
65
- #
66
- # @param [Object] value the value to set
67
- # @return [Object] the new value
68
- def value=(value)
69
- raise NotImplementedError
70
- end
71
-
72
- # @!macro [attach] thread_local_var_method_bind
73
- #
74
- # Bind the given value to thread local storage during
75
- # execution of the given block.
76
- #
77
- # @param [Object] value the value to bind
78
- # @yield the operation to be performed with the bound variable
79
- # @return [Object] the value
80
- def bind(value, &block)
81
- raise NotImplementedError
82
- end
83
-
84
- protected
85
-
86
- # @!visibility private
87
- def allocate_storage
88
- raise NotImplementedError
89
- end
90
- end
91
-
92
- # @!visibility private
93
- # @!macro internal_implementation_note
94
- class RubyThreadLocalVar < AbstractThreadLocalVar
95
-
96
- # Each thread has a (lazily initialized) array of thread-local variable values
97
- # Each time a new thread-local var is created, we allocate an "index" for it
98
- # For example, if the allocated index is 1, that means slot #1 in EVERY
99
- # thread's thread-local array will be used for the value of that TLV
100
- #
101
- # The good thing about using a per-THREAD structure to hold values, rather
102
- # than a per-TLV structure, is that no synchronization is needed when
103
- # reading and writing those values (since the structure is only ever
104
- # accessed by a single thread)
105
- #
106
- # Of course, when a TLV is GC'd, 1) we need to recover its index for use
107
- # by other new TLVs (otherwise the thread-local arrays could get bigger
108
- # and bigger with time), and 2) we need to null out all the references
109
- # held in the now-unused slots (both to avoid blocking GC of those objects,
110
- # and also to prevent "stale" values from being passed on to a new TLV
111
- # when the index is reused)
112
- # Because we need to null out freed slots, we need to keep references to
113
- # ALL the thread-local arrays -- ARRAYS is for that
114
- # But when a Thread is GC'd, we need to drop the reference to its thread-local
115
- # array, so we don't leak memory
116
-
117
- # @!visibility private
118
- FREE = []
119
- LOCK = Mutex.new
120
- ARRAYS = {} # used as a hash set
121
- @@next = 0
122
- private_constant :FREE, :LOCK, :ARRAYS
123
-
124
- # @!macro [attach] thread_local_var_method_initialize
125
- #
126
- # Creates a thread local variable.
127
- #
128
- # @param [Object] default the default value when otherwise unset
129
- def initialize(default = nil)
130
- @default = default
131
- allocate_storage
132
- end
133
-
134
- # @!macro thread_local_var_method_get
135
- def value
136
- if array = get_threadlocal_array
137
- value = array[@index]
138
- if value.nil?
139
- @default
140
- elsif value.equal?(NIL_SENTINEL)
141
- nil
142
- else
143
- value
144
- end
145
- else
146
- @default
147
- end
148
- end
149
-
150
- # @!macro thread_local_var_method_set
151
- def value=(value)
152
- me = Thread.current
153
- # We could keep the thread-local arrays in a hash, keyed by Thread
154
- # But why? That would require locking
155
- # Using Ruby's built-in thread-local storage is faster
156
- unless array = get_threadlocal_array(me)
157
- array = set_threadlocal_array([], me)
158
- LOCK.synchronize { ARRAYS[array.object_id] = array }
159
- ObjectSpace.define_finalizer(me, self.class.thread_finalizer(array))
160
- end
161
- array[@index] = (value.nil? ? NIL_SENTINEL : value)
162
- value
163
- end
164
-
165
- # @!macro thread_local_var_method_bind
166
- def bind(value, &block)
167
- if block_given?
168
- old_value = self.value
169
- begin
170
- self.value = value
171
- yield
172
- ensure
173
- self.value = old_value
174
- end
175
- end
176
- end
177
-
178
- protected
179
-
180
- # @!visibility private
181
- def allocate_storage
182
- @index = LOCK.synchronize do
183
- FREE.pop || begin
184
- result = @@next
185
- @@next += 1
186
- result
187
- end
188
- end
189
- ObjectSpace.define_finalizer(self, self.class.threadlocal_finalizer(@index))
190
- end
191
-
192
- # @!visibility private
193
- def self.threadlocal_finalizer(index)
194
- proc do
195
- LOCK.synchronize do
196
- FREE.push(index)
197
- # The cost of GC'ing a TLV is linear in the number of threads using TLVs
198
- # But that is natural! More threads means more storage is used per TLV
199
- # So naturally more CPU time is required to free more storage
200
- ARRAYS.each_value do |array|
201
- array[index] = nil
202
- end
203
- end
204
- end
205
- end
206
-
207
- # @!visibility private
208
- def self.thread_finalizer(array)
209
- proc do
210
- LOCK.synchronize do
211
- # The thread which used this thread-local array is now gone
212
- # So don't hold onto a reference to the array (thus blocking GC)
213
- ARRAYS.delete(array.object_id)
214
- end
215
- end
216
- end
217
-
218
- private
219
-
220
- if Thread.instance_methods.include?(:thread_variable_get)
221
-
222
- def get_threadlocal_array(thread = Thread.current)
223
- thread.thread_variable_get(:__threadlocal_array__)
224
- end
225
-
226
- def set_threadlocal_array(array, thread = Thread.current)
227
- thread.thread_variable_set(:__threadlocal_array__, array)
228
- end
229
-
230
- else
231
-
232
- def get_threadlocal_array(thread = Thread.current)
233
- thread[:__threadlocal_array__]
234
- end
235
-
236
- def set_threadlocal_array(array, thread = Thread.current)
237
- thread[:__threadlocal_array__] = array
238
- end
239
- end
240
-
241
- # This exists only for use in testing
242
- # @!visibility private
243
- def value_for(thread)
244
- if array = get_threadlocal_array(thread)
245
- value = array[@index]
246
- if value.nil?
247
- @default
248
- elsif value.equal?(NIL_SENTINEL)
249
- nil
250
- else
251
- value
252
- end
253
- else
254
- @default
255
- end
256
- end
257
- end
258
-
259
- if Concurrent.on_jruby?
260
-
261
- # @!visibility private
262
- # @!macro internal_implementation_note
263
- class JavaThreadLocalVar < AbstractThreadLocalVar
264
-
265
- # @!macro thread_local_var_method_get
266
- def value
267
- value = @var.get
268
-
269
- if value.nil?
270
- @default
271
- elsif value == NIL_SENTINEL
272
- nil
273
- else
274
- value
275
- end
276
- end
277
-
278
- # @!macro thread_local_var_method_set
279
- def value=(value)
280
- @var.set(value)
281
- end
282
-
283
- # @!macro thread_local_var_method_bind
284
- def bind(value, &block)
285
- if block_given?
286
- old_value = @var.get
287
- begin
288
- @var.set(value)
289
- yield
290
- ensure
291
- @var.set(old_value)
292
- end
293
- end
294
- end
295
-
296
- protected
297
-
298
- # @!visibility private
299
- def allocate_storage
300
- @var = java.lang.ThreadLocal.new
301
- end
302
- end
303
- end
304
-
305
- # @!visibility private
306
- # @!macro internal_implementation_note
307
- ThreadLocalVarImplementation = case
308
- when Concurrent.on_jruby?
309
- JavaThreadLocalVar
310
- else
311
- RubyThreadLocalVar
312
- end
313
- private_constant :ThreadLocalVarImplementation
314
-
315
- # @!macro thread_local_var
97
+ # @!macro thread_local_var_public_api
316
98
  class ThreadLocalVar < ThreadLocalVarImplementation
317
-
318
- # @!method initialize(default = nil)
319
- # @!macro thread_local_var_method_initialize
320
-
321
- # @!method value
322
- # @!macro thread_local_var_method_get
323
-
324
- # @!method value=(value)
325
- # @!macro thread_local_var_method_set
326
-
327
- # @!method bind(value, &block)
328
- # @!macro thread_local_var_method_bind
329
-
330
99
  end
331
100
  end