concurrent-ruby 1.1.5

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 (143) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +478 -0
  3. data/Gemfile +41 -0
  4. data/LICENSE.md +23 -0
  5. data/README.md +381 -0
  6. data/Rakefile +327 -0
  7. data/ext/concurrent-ruby/ConcurrentRubyService.java +17 -0
  8. data/ext/concurrent-ruby/com/concurrent_ruby/ext/AtomicReferenceLibrary.java +175 -0
  9. data/ext/concurrent-ruby/com/concurrent_ruby/ext/JRubyMapBackendLibrary.java +248 -0
  10. data/ext/concurrent-ruby/com/concurrent_ruby/ext/JavaAtomicBooleanLibrary.java +93 -0
  11. data/ext/concurrent-ruby/com/concurrent_ruby/ext/JavaAtomicFixnumLibrary.java +113 -0
  12. data/ext/concurrent-ruby/com/concurrent_ruby/ext/JavaSemaphoreLibrary.java +159 -0
  13. data/ext/concurrent-ruby/com/concurrent_ruby/ext/SynchronizationLibrary.java +307 -0
  14. data/ext/concurrent-ruby/com/concurrent_ruby/ext/jsr166e/ConcurrentHashMap.java +31 -0
  15. data/ext/concurrent-ruby/com/concurrent_ruby/ext/jsr166e/ConcurrentHashMapV8.java +3863 -0
  16. data/ext/concurrent-ruby/com/concurrent_ruby/ext/jsr166e/LongAdder.java +203 -0
  17. data/ext/concurrent-ruby/com/concurrent_ruby/ext/jsr166e/Striped64.java +342 -0
  18. data/ext/concurrent-ruby/com/concurrent_ruby/ext/jsr166e/nounsafe/ConcurrentHashMapV8.java +3800 -0
  19. data/ext/concurrent-ruby/com/concurrent_ruby/ext/jsr166e/nounsafe/LongAdder.java +204 -0
  20. data/ext/concurrent-ruby/com/concurrent_ruby/ext/jsr166e/nounsafe/Striped64.java +291 -0
  21. data/ext/concurrent-ruby/com/concurrent_ruby/ext/jsr166y/ThreadLocalRandom.java +199 -0
  22. data/lib/concurrent-ruby.rb +1 -0
  23. data/lib/concurrent.rb +134 -0
  24. data/lib/concurrent/agent.rb +587 -0
  25. data/lib/concurrent/array.rb +66 -0
  26. data/lib/concurrent/async.rb +459 -0
  27. data/lib/concurrent/atom.rb +222 -0
  28. data/lib/concurrent/atomic/abstract_thread_local_var.rb +66 -0
  29. data/lib/concurrent/atomic/atomic_boolean.rb +126 -0
  30. data/lib/concurrent/atomic/atomic_fixnum.rb +143 -0
  31. data/lib/concurrent/atomic/atomic_markable_reference.rb +164 -0
  32. data/lib/concurrent/atomic/atomic_reference.rb +204 -0
  33. data/lib/concurrent/atomic/count_down_latch.rb +100 -0
  34. data/lib/concurrent/atomic/cyclic_barrier.rb +128 -0
  35. data/lib/concurrent/atomic/event.rb +109 -0
  36. data/lib/concurrent/atomic/java_count_down_latch.rb +42 -0
  37. data/lib/concurrent/atomic/java_thread_local_var.rb +37 -0
  38. data/lib/concurrent/atomic/mutex_atomic_boolean.rb +62 -0
  39. data/lib/concurrent/atomic/mutex_atomic_fixnum.rb +75 -0
  40. data/lib/concurrent/atomic/mutex_count_down_latch.rb +44 -0
  41. data/lib/concurrent/atomic/mutex_semaphore.rb +115 -0
  42. data/lib/concurrent/atomic/read_write_lock.rb +254 -0
  43. data/lib/concurrent/atomic/reentrant_read_write_lock.rb +379 -0
  44. data/lib/concurrent/atomic/ruby_thread_local_var.rb +161 -0
  45. data/lib/concurrent/atomic/semaphore.rb +145 -0
  46. data/lib/concurrent/atomic/thread_local_var.rb +104 -0
  47. data/lib/concurrent/atomic_reference/mutex_atomic.rb +56 -0
  48. data/lib/concurrent/atomic_reference/numeric_cas_wrapper.rb +28 -0
  49. data/lib/concurrent/atomics.rb +10 -0
  50. data/lib/concurrent/collection/copy_on_notify_observer_set.rb +107 -0
  51. data/lib/concurrent/collection/copy_on_write_observer_set.rb +111 -0
  52. data/lib/concurrent/collection/java_non_concurrent_priority_queue.rb +84 -0
  53. data/lib/concurrent/collection/lock_free_stack.rb +158 -0
  54. data/lib/concurrent/collection/map/atomic_reference_map_backend.rb +927 -0
  55. data/lib/concurrent/collection/map/mri_map_backend.rb +66 -0
  56. data/lib/concurrent/collection/map/non_concurrent_map_backend.rb +140 -0
  57. data/lib/concurrent/collection/map/synchronized_map_backend.rb +82 -0
  58. data/lib/concurrent/collection/non_concurrent_priority_queue.rb +143 -0
  59. data/lib/concurrent/collection/ruby_non_concurrent_priority_queue.rb +150 -0
  60. data/lib/concurrent/concern/deprecation.rb +34 -0
  61. data/lib/concurrent/concern/dereferenceable.rb +73 -0
  62. data/lib/concurrent/concern/logging.rb +32 -0
  63. data/lib/concurrent/concern/obligation.rb +220 -0
  64. data/lib/concurrent/concern/observable.rb +110 -0
  65. data/lib/concurrent/concurrent_ruby.jar +0 -0
  66. data/lib/concurrent/configuration.rb +184 -0
  67. data/lib/concurrent/constants.rb +8 -0
  68. data/lib/concurrent/dataflow.rb +81 -0
  69. data/lib/concurrent/delay.rb +199 -0
  70. data/lib/concurrent/errors.rb +69 -0
  71. data/lib/concurrent/exchanger.rb +352 -0
  72. data/lib/concurrent/executor/abstract_executor_service.rb +134 -0
  73. data/lib/concurrent/executor/cached_thread_pool.rb +62 -0
  74. data/lib/concurrent/executor/executor_service.rb +185 -0
  75. data/lib/concurrent/executor/fixed_thread_pool.rb +206 -0
  76. data/lib/concurrent/executor/immediate_executor.rb +66 -0
  77. data/lib/concurrent/executor/indirect_immediate_executor.rb +44 -0
  78. data/lib/concurrent/executor/java_executor_service.rb +91 -0
  79. data/lib/concurrent/executor/java_single_thread_executor.rb +29 -0
  80. data/lib/concurrent/executor/java_thread_pool_executor.rb +123 -0
  81. data/lib/concurrent/executor/ruby_executor_service.rb +78 -0
  82. data/lib/concurrent/executor/ruby_single_thread_executor.rb +22 -0
  83. data/lib/concurrent/executor/ruby_thread_pool_executor.rb +362 -0
  84. data/lib/concurrent/executor/safe_task_executor.rb +35 -0
  85. data/lib/concurrent/executor/serial_executor_service.rb +34 -0
  86. data/lib/concurrent/executor/serialized_execution.rb +107 -0
  87. data/lib/concurrent/executor/serialized_execution_delegator.rb +28 -0
  88. data/lib/concurrent/executor/simple_executor_service.rb +100 -0
  89. data/lib/concurrent/executor/single_thread_executor.rb +56 -0
  90. data/lib/concurrent/executor/thread_pool_executor.rb +87 -0
  91. data/lib/concurrent/executor/timer_set.rb +173 -0
  92. data/lib/concurrent/executors.rb +20 -0
  93. data/lib/concurrent/future.rb +141 -0
  94. data/lib/concurrent/hash.rb +59 -0
  95. data/lib/concurrent/immutable_struct.rb +93 -0
  96. data/lib/concurrent/ivar.rb +207 -0
  97. data/lib/concurrent/map.rb +337 -0
  98. data/lib/concurrent/maybe.rb +229 -0
  99. data/lib/concurrent/mutable_struct.rb +229 -0
  100. data/lib/concurrent/mvar.rb +242 -0
  101. data/lib/concurrent/options.rb +42 -0
  102. data/lib/concurrent/promise.rb +579 -0
  103. data/lib/concurrent/promises.rb +2167 -0
  104. data/lib/concurrent/re_include.rb +58 -0
  105. data/lib/concurrent/scheduled_task.rb +318 -0
  106. data/lib/concurrent/set.rb +66 -0
  107. data/lib/concurrent/settable_struct.rb +129 -0
  108. data/lib/concurrent/synchronization.rb +30 -0
  109. data/lib/concurrent/synchronization/abstract_lockable_object.rb +98 -0
  110. data/lib/concurrent/synchronization/abstract_object.rb +24 -0
  111. data/lib/concurrent/synchronization/abstract_struct.rb +160 -0
  112. data/lib/concurrent/synchronization/condition.rb +60 -0
  113. data/lib/concurrent/synchronization/jruby_lockable_object.rb +13 -0
  114. data/lib/concurrent/synchronization/jruby_object.rb +45 -0
  115. data/lib/concurrent/synchronization/lock.rb +36 -0
  116. data/lib/concurrent/synchronization/lockable_object.rb +74 -0
  117. data/lib/concurrent/synchronization/mri_object.rb +44 -0
  118. data/lib/concurrent/synchronization/mutex_lockable_object.rb +76 -0
  119. data/lib/concurrent/synchronization/object.rb +183 -0
  120. data/lib/concurrent/synchronization/rbx_lockable_object.rb +65 -0
  121. data/lib/concurrent/synchronization/rbx_object.rb +49 -0
  122. data/lib/concurrent/synchronization/truffleruby_object.rb +47 -0
  123. data/lib/concurrent/synchronization/volatile.rb +36 -0
  124. data/lib/concurrent/thread_safe/synchronized_delegator.rb +50 -0
  125. data/lib/concurrent/thread_safe/util.rb +16 -0
  126. data/lib/concurrent/thread_safe/util/adder.rb +74 -0
  127. data/lib/concurrent/thread_safe/util/cheap_lockable.rb +118 -0
  128. data/lib/concurrent/thread_safe/util/data_structures.rb +63 -0
  129. data/lib/concurrent/thread_safe/util/power_of_two_tuple.rb +38 -0
  130. data/lib/concurrent/thread_safe/util/striped64.rb +246 -0
  131. data/lib/concurrent/thread_safe/util/volatile.rb +75 -0
  132. data/lib/concurrent/thread_safe/util/xor_shift_random.rb +50 -0
  133. data/lib/concurrent/timer_task.rb +334 -0
  134. data/lib/concurrent/tuple.rb +86 -0
  135. data/lib/concurrent/tvar.rb +258 -0
  136. data/lib/concurrent/utility/at_exit.rb +97 -0
  137. data/lib/concurrent/utility/engine.rb +56 -0
  138. data/lib/concurrent/utility/monotonic_time.rb +58 -0
  139. data/lib/concurrent/utility/native_extension_loader.rb +79 -0
  140. data/lib/concurrent/utility/native_integer.rb +53 -0
  141. data/lib/concurrent/utility/processor_counter.rb +158 -0
  142. data/lib/concurrent/version.rb +3 -0
  143. metadata +193 -0
@@ -0,0 +1,161 @@
1
+ require 'thread'
2
+ require 'concurrent/atomic/abstract_thread_local_var'
3
+
4
+ module Concurrent
5
+
6
+ # @!visibility private
7
+ # @!macro internal_implementation_note
8
+ class RubyThreadLocalVar < AbstractThreadLocalVar
9
+
10
+ # Each thread has a (lazily initialized) array of thread-local variable values
11
+ # Each time a new thread-local var is created, we allocate an "index" for it
12
+ # For example, if the allocated index is 1, that means slot #1 in EVERY
13
+ # thread's thread-local array will be used for the value of that TLV
14
+ #
15
+ # The good thing about using a per-THREAD structure to hold values, rather
16
+ # than a per-TLV structure, is that no synchronization is needed when
17
+ # reading and writing those values (since the structure is only ever
18
+ # accessed by a single thread)
19
+ #
20
+ # Of course, when a TLV is GC'd, 1) we need to recover its index for use
21
+ # by other new TLVs (otherwise the thread-local arrays could get bigger
22
+ # and bigger with time), and 2) we need to null out all the references
23
+ # held in the now-unused slots (both to avoid blocking GC of those objects,
24
+ # and also to prevent "stale" values from being passed on to a new TLV
25
+ # when the index is reused)
26
+ # Because we need to null out freed slots, we need to keep references to
27
+ # ALL the thread-local arrays -- ARRAYS is for that
28
+ # But when a Thread is GC'd, we need to drop the reference to its thread-local
29
+ # array, so we don't leak memory
30
+
31
+ # @!visibility private
32
+ FREE = []
33
+ LOCK = Mutex.new
34
+ ARRAYS = {} # used as a hash set
35
+ @@next = 0
36
+ private_constant :FREE, :LOCK, :ARRAYS
37
+
38
+ # @!macro thread_local_var_method_get
39
+ def value
40
+ if array = get_threadlocal_array
41
+ value = array[@index]
42
+ if value.nil?
43
+ default
44
+ elsif value.equal?(NULL)
45
+ nil
46
+ else
47
+ value
48
+ end
49
+ else
50
+ default
51
+ end
52
+ end
53
+
54
+ # @!macro thread_local_var_method_set
55
+ def value=(value)
56
+ me = Thread.current
57
+ # We could keep the thread-local arrays in a hash, keyed by Thread
58
+ # But why? That would require locking
59
+ # Using Ruby's built-in thread-local storage is faster
60
+ unless array = get_threadlocal_array(me)
61
+ array = set_threadlocal_array([], me)
62
+ LOCK.synchronize { ARRAYS[array.object_id] = array }
63
+ ObjectSpace.define_finalizer(me, self.class.thread_finalizer(array))
64
+ end
65
+ array[@index] = (value.nil? ? NULL : value)
66
+ value
67
+ end
68
+
69
+ protected
70
+
71
+ # @!visibility private
72
+ def allocate_storage
73
+ @index = LOCK.synchronize do
74
+ FREE.pop || begin
75
+ result = @@next
76
+ @@next += 1
77
+ result
78
+ end
79
+ end
80
+ ObjectSpace.define_finalizer(self, self.class.threadlocal_finalizer(@index))
81
+ end
82
+
83
+ # @!visibility private
84
+ def self.threadlocal_finalizer(index)
85
+ proc do
86
+ Thread.new do # avoid error: can't be called from trap context
87
+ LOCK.synchronize do
88
+ FREE.push(index)
89
+ # The cost of GC'ing a TLV is linear in the number of threads using TLVs
90
+ # But that is natural! More threads means more storage is used per TLV
91
+ # So naturally more CPU time is required to free more storage
92
+ ARRAYS.each_value do |array|
93
+ array[index] = nil
94
+ end
95
+ end
96
+ end
97
+ end
98
+ end
99
+
100
+ # @!visibility private
101
+ def self.thread_finalizer(array)
102
+ proc do
103
+ Thread.new do # avoid error: can't be called from trap context
104
+ LOCK.synchronize do
105
+ # The thread which used this thread-local array is now gone
106
+ # So don't hold onto a reference to the array (thus blocking GC)
107
+ ARRAYS.delete(array.object_id)
108
+ end
109
+ end
110
+ end
111
+ end
112
+
113
+ private
114
+
115
+ if Thread.instance_methods.include?(:thread_variable_get)
116
+
117
+ def get_threadlocal_array(thread = Thread.current)
118
+ thread.thread_variable_get(:__threadlocal_array__)
119
+ end
120
+
121
+ def set_threadlocal_array(array, thread = Thread.current)
122
+ thread.thread_variable_set(:__threadlocal_array__, array)
123
+ end
124
+
125
+ else
126
+
127
+ def get_threadlocal_array(thread = Thread.current)
128
+ thread[:__threadlocal_array__]
129
+ end
130
+
131
+ def set_threadlocal_array(array, thread = Thread.current)
132
+ thread[:__threadlocal_array__] = array
133
+ end
134
+ end
135
+
136
+ # This exists only for use in testing
137
+ # @!visibility private
138
+ def value_for(thread)
139
+ if array = get_threadlocal_array(thread)
140
+ value = array[@index]
141
+ if value.nil?
142
+ default_for(thread)
143
+ elsif value.equal?(NULL)
144
+ nil
145
+ else
146
+ value
147
+ end
148
+ else
149
+ default_for(thread)
150
+ end
151
+ end
152
+
153
+ def default_for(thread)
154
+ if @default_block
155
+ raise "Cannot use default_for with default block"
156
+ else
157
+ @default
158
+ end
159
+ end
160
+ end
161
+ end
@@ -0,0 +1,145 @@
1
+ require 'concurrent/atomic/mutex_semaphore'
2
+ require 'concurrent/synchronization'
3
+
4
+ module Concurrent
5
+
6
+ ###################################################################
7
+
8
+ # @!macro semaphore_method_initialize
9
+ #
10
+ # Create a new `Semaphore` with the initial `count`.
11
+ #
12
+ # @param [Fixnum] count the initial count
13
+ #
14
+ # @raise [ArgumentError] if `count` is not an integer or is less than zero
15
+
16
+ # @!macro 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]
27
+
28
+ # @!macro semaphore_method_available_permits
29
+ #
30
+ # Returns the current number of permits available in this semaphore.
31
+ #
32
+ # @return [Integer]
33
+
34
+ # @!macro semaphore_method_drain_permits
35
+ #
36
+ # Acquires and returns all permits that are immediately available.
37
+ #
38
+ # @return [Integer]
39
+
40
+ # @!macro 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
56
+
57
+ # @!macro 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]
66
+
67
+ ###################################################################
68
+
69
+ # @!macro 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
88
+
89
+ ###################################################################
90
+
91
+ # @!visibility private
92
+ # @!macro internal_implementation_note
93
+ SemaphoreImplementation = case
94
+ when defined?(JavaSemaphore)
95
+ JavaSemaphore
96
+ else
97
+ MutexSemaphore
98
+ end
99
+ private_constant :SemaphoreImplementation
100
+
101
+ # @!macro semaphore
102
+ #
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
111
+ # @example
112
+ # semaphore = Concurrent::Semaphore.new(2)
113
+ #
114
+ # t1 = Thread.new do
115
+ # semaphore.acquire
116
+ # puts "Thread 1 acquired semaphore"
117
+ # end
118
+ #
119
+ # t2 = Thread.new do
120
+ # semaphore.acquire
121
+ # puts "Thread 2 acquired semaphore"
122
+ # end
123
+ #
124
+ # t3 = Thread.new do
125
+ # semaphore.acquire
126
+ # puts "Thread 3 acquired semaphore"
127
+ # end
128
+ #
129
+ # t4 = Thread.new do
130
+ # sleep(2)
131
+ # puts "Thread 4 releasing semaphore"
132
+ # semaphore.release
133
+ # end
134
+ #
135
+ # [t1, t2, t3, t4].each(&:join)
136
+ #
137
+ # # prints:
138
+ # # Thread 3 acquired semaphore
139
+ # # Thread 2 acquired semaphore
140
+ # # Thread 4 releasing semaphore
141
+ # # Thread 1 acquired semaphore
142
+ #
143
+ class Semaphore < SemaphoreImplementation
144
+ end
145
+ end
@@ -0,0 +1,104 @@
1
+ require 'concurrent/atomic/ruby_thread_local_var'
2
+ require 'concurrent/atomic/java_thread_local_var'
3
+ require 'concurrent/utility/engine'
4
+
5
+ module Concurrent
6
+
7
+ ###################################################################
8
+
9
+ # @!macro thread_local_var_method_initialize
10
+ #
11
+ # Creates a thread local variable.
12
+ #
13
+ # @param [Object] default the default value when otherwise unset
14
+ # @param [Proc] default_block Optional block that gets called to obtain the
15
+ # default value for each thread
16
+
17
+ # @!macro thread_local_var_method_get
18
+ #
19
+ # Returns the value in the current thread's copy of this thread-local variable.
20
+ #
21
+ # @return [Object] the current value
22
+
23
+ # @!macro thread_local_var_method_set
24
+ #
25
+ # Sets the current thread's copy of this thread-local variable to the specified value.
26
+ #
27
+ # @param [Object] value the value to set
28
+ # @return [Object] the new value
29
+
30
+ # @!macro thread_local_var_method_bind
31
+ #
32
+ # Bind the given value to thread local storage during
33
+ # execution of the given block.
34
+ #
35
+ # @param [Object] value the value to bind
36
+ # @yield the operation to be performed with the bound variable
37
+ # @return [Object] the value
38
+
39
+
40
+ ###################################################################
41
+
42
+ # @!macro thread_local_var_public_api
43
+ #
44
+ # @!method initialize(default = nil, &default_block)
45
+ # @!macro thread_local_var_method_initialize
46
+ #
47
+ # @!method value
48
+ # @!macro thread_local_var_method_get
49
+ #
50
+ # @!method value=(value)
51
+ # @!macro thread_local_var_method_set
52
+ #
53
+ # @!method bind(value, &block)
54
+ # @!macro thread_local_var_method_bind
55
+
56
+ ###################################################################
57
+
58
+ # @!visibility private
59
+ # @!macro internal_implementation_note
60
+ ThreadLocalVarImplementation = case
61
+ when Concurrent.on_jruby?
62
+ JavaThreadLocalVar
63
+ else
64
+ RubyThreadLocalVar
65
+ end
66
+ private_constant :ThreadLocalVarImplementation
67
+
68
+ # @!macro thread_local_var
69
+ #
70
+ # A `ThreadLocalVar` is a variable where the value is different for each thread.
71
+ # Each variable may have a default value, but when you modify the variable only
72
+ # the current thread will ever see that change.
73
+ #
74
+ # @!macro thread_safe_variable_comparison
75
+ #
76
+ # @example
77
+ # v = ThreadLocalVar.new(14)
78
+ # v.value #=> 14
79
+ # v.value = 2
80
+ # v.value #=> 2
81
+ #
82
+ # @example
83
+ # v = ThreadLocalVar.new(14)
84
+ #
85
+ # t1 = Thread.new do
86
+ # v.value #=> 14
87
+ # v.value = 1
88
+ # v.value #=> 1
89
+ # end
90
+ #
91
+ # t2 = Thread.new do
92
+ # v.value #=> 14
93
+ # v.value = 2
94
+ # v.value #=> 2
95
+ # end
96
+ #
97
+ # v.value #=> 14
98
+ #
99
+ # @see https://docs.oracle.com/javase/7/docs/api/java/lang/ThreadLocal.html Java ThreadLocal
100
+ #
101
+ # @!macro thread_local_var_public_api
102
+ class ThreadLocalVar < ThreadLocalVarImplementation
103
+ end
104
+ end
@@ -0,0 +1,56 @@
1
+ module Concurrent
2
+
3
+ # @!visibility private
4
+ # @!macro internal_implementation_note
5
+ class MutexAtomicReference < Synchronization::LockableObject
6
+ include AtomicDirectUpdate
7
+ include AtomicNumericCompareAndSetWrapper
8
+ alias_method :compare_and_swap, :compare_and_set
9
+
10
+ # @!macro atomic_reference_method_initialize
11
+ def initialize(value = nil)
12
+ super()
13
+ synchronize { ns_initialize(value) }
14
+ end
15
+
16
+ # @!macro atomic_reference_method_get
17
+ def get
18
+ synchronize { @value }
19
+ end
20
+ alias_method :value, :get
21
+
22
+ # @!macro atomic_reference_method_set
23
+ def set(new_value)
24
+ synchronize { @value = new_value }
25
+ end
26
+ alias_method :value=, :set
27
+
28
+ # @!macro atomic_reference_method_get_and_set
29
+ def get_and_set(new_value)
30
+ synchronize do
31
+ old_value = @value
32
+ @value = new_value
33
+ old_value
34
+ end
35
+ end
36
+ alias_method :swap, :get_and_set
37
+
38
+ # @!macro atomic_reference_method_compare_and_set
39
+ def _compare_and_set(old_value, new_value)
40
+ synchronize do
41
+ if @value.equal? old_value
42
+ @value = new_value
43
+ true
44
+ else
45
+ false
46
+ end
47
+ end
48
+ end
49
+
50
+ protected
51
+
52
+ def ns_initialize(value)
53
+ @value = value
54
+ end
55
+ end
56
+ end