concurrent-ruby 1.0.5 → 1.1.10

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 (164) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +155 -0
  3. data/Gemfile +37 -0
  4. data/LICENSE.txt +18 -18
  5. data/README.md +260 -103
  6. data/Rakefile +329 -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 +189 -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 → concurrent-ruby/concurrent}/agent.rb +7 -7
  23. data/lib/concurrent-ruby/concurrent/array.rb +66 -0
  24. data/lib/{concurrent → concurrent-ruby/concurrent}/async.rb +28 -24
  25. data/lib/{concurrent → concurrent-ruby/concurrent}/atom.rb +10 -10
  26. data/lib/{concurrent → concurrent-ruby/concurrent}/atomic/atomic_boolean.rb +26 -22
  27. data/lib/{concurrent → concurrent-ruby/concurrent}/atomic/atomic_fixnum.rb +27 -23
  28. data/lib/concurrent-ruby/concurrent/atomic/atomic_markable_reference.rb +164 -0
  29. data/lib/concurrent-ruby/concurrent/atomic/atomic_reference.rb +205 -0
  30. data/lib/{concurrent → concurrent-ruby/concurrent}/atomic/count_down_latch.rb +7 -7
  31. data/lib/{concurrent → concurrent-ruby/concurrent}/atomic/cyclic_barrier.rb +1 -1
  32. data/lib/{concurrent → concurrent-ruby/concurrent}/atomic/event.rb +3 -3
  33. data/lib/{concurrent → concurrent-ruby/concurrent}/atomic/java_count_down_latch.rb +9 -6
  34. data/lib/{concurrent → concurrent-ruby/concurrent}/atomic/mutex_atomic_boolean.rb +2 -0
  35. data/lib/{concurrent → concurrent-ruby/concurrent}/atomic/mutex_count_down_latch.rb +1 -0
  36. data/lib/{concurrent → concurrent-ruby/concurrent}/atomic/mutex_semaphore.rb +18 -2
  37. data/lib/{concurrent → concurrent-ruby/concurrent}/atomic/read_write_lock.rb +2 -1
  38. data/lib/{concurrent → concurrent-ruby/concurrent}/atomic/reentrant_read_write_lock.rb +7 -7
  39. data/lib/{concurrent → concurrent-ruby/concurrent}/atomic/ruby_thread_local_var.rb +60 -40
  40. data/lib/{concurrent → concurrent-ruby/concurrent}/atomic/semaphore.rb +34 -13
  41. data/lib/{concurrent → concurrent-ruby/concurrent}/atomic/thread_local_var.rb +8 -8
  42. data/lib/{concurrent → concurrent-ruby/concurrent}/atomic_reference/mutex_atomic.rb +3 -8
  43. data/lib/{concurrent → concurrent-ruby/concurrent}/atomic_reference/numeric_cas_wrapper.rb +1 -1
  44. data/lib/concurrent-ruby/concurrent/atomics.rb +10 -0
  45. data/lib/concurrent-ruby/concurrent/collection/lock_free_stack.rb +158 -0
  46. data/lib/{concurrent → concurrent-ruby/concurrent}/collection/map/atomic_reference_map_backend.rb +3 -3
  47. data/lib/{concurrent → concurrent-ruby/concurrent}/collection/map/mri_map_backend.rb +1 -1
  48. data/lib/{concurrent → concurrent-ruby/concurrent}/collection/map/non_concurrent_map_backend.rb +1 -2
  49. data/lib/concurrent-ruby/concurrent/collection/map/truffleruby_map_backend.rb +14 -0
  50. data/lib/{concurrent → concurrent-ruby/concurrent}/collection/non_concurrent_priority_queue.rb +30 -30
  51. data/lib/{concurrent → concurrent-ruby/concurrent}/collection/ruby_non_concurrent_priority_queue.rb +11 -1
  52. data/lib/{concurrent → concurrent-ruby/concurrent}/concern/dereferenceable.rb +3 -3
  53. data/lib/{concurrent → concurrent-ruby/concurrent}/concern/logging.rb +6 -1
  54. data/lib/{concurrent → concurrent-ruby/concurrent}/concern/observable.rb +7 -7
  55. data/lib/concurrent-ruby/concurrent/concurrent_ruby.jar +0 -0
  56. data/lib/{concurrent → concurrent-ruby/concurrent}/configuration.rb +15 -15
  57. data/lib/{concurrent → concurrent-ruby/concurrent}/constants.rb +1 -1
  58. data/lib/{concurrent → concurrent-ruby/concurrent}/dataflow.rb +2 -1
  59. data/lib/{concurrent → concurrent-ruby/concurrent}/delay.rb +9 -7
  60. data/lib/{concurrent → concurrent-ruby/concurrent}/exchanger.rb +21 -25
  61. data/lib/{concurrent → concurrent-ruby/concurrent}/executor/abstract_executor_service.rb +35 -38
  62. data/lib/{concurrent → concurrent-ruby/concurrent}/executor/cached_thread_pool.rb +5 -5
  63. data/lib/{concurrent → concurrent-ruby/concurrent}/executor/executor_service.rb +17 -17
  64. data/lib/{concurrent → concurrent-ruby/concurrent}/executor/fixed_thread_pool.rb +47 -33
  65. data/lib/{concurrent → concurrent-ruby/concurrent}/executor/java_executor_service.rb +20 -17
  66. data/lib/{concurrent → concurrent-ruby/concurrent}/executor/java_single_thread_executor.rb +4 -3
  67. data/lib/{concurrent → concurrent-ruby/concurrent}/executor/java_thread_pool_executor.rb +29 -9
  68. data/lib/{concurrent → concurrent-ruby/concurrent}/executor/ruby_executor_service.rb +10 -6
  69. data/lib/{concurrent → concurrent-ruby/concurrent}/executor/ruby_single_thread_executor.rb +0 -1
  70. data/lib/{concurrent → concurrent-ruby/concurrent}/executor/ruby_thread_pool_executor.rb +46 -42
  71. data/lib/{concurrent → concurrent-ruby/concurrent}/executor/safe_task_executor.rb +5 -5
  72. data/lib/{concurrent → concurrent-ruby/concurrent}/executor/simple_executor_service.rb +1 -1
  73. data/lib/{concurrent → concurrent-ruby/concurrent}/executor/single_thread_executor.rb +3 -2
  74. data/lib/{concurrent → concurrent-ruby/concurrent}/executor/thread_pool_executor.rb +7 -6
  75. data/lib/{concurrent → concurrent-ruby/concurrent}/executor/timer_set.rb +14 -17
  76. data/lib/{concurrent → concurrent-ruby/concurrent}/future.rb +4 -1
  77. data/lib/concurrent-ruby/concurrent/hash.rb +59 -0
  78. data/lib/{concurrent → concurrent-ruby/concurrent}/immutable_struct.rb +9 -1
  79. data/lib/{concurrent → concurrent-ruby/concurrent}/ivar.rb +5 -6
  80. data/lib/concurrent-ruby/concurrent/map.rb +346 -0
  81. data/lib/{concurrent → concurrent-ruby/concurrent}/maybe.rb +1 -1
  82. data/lib/{concurrent → concurrent-ruby/concurrent}/mutable_struct.rb +27 -16
  83. data/lib/{concurrent → concurrent-ruby/concurrent}/mvar.rb +2 -2
  84. data/lib/{concurrent → concurrent-ruby/concurrent}/promise.rb +54 -21
  85. data/lib/concurrent-ruby/concurrent/promises.rb +2167 -0
  86. data/lib/concurrent-ruby/concurrent/re_include.rb +58 -0
  87. data/lib/{concurrent → concurrent-ruby/concurrent}/scheduled_task.rb +29 -16
  88. data/lib/concurrent-ruby/concurrent/set.rb +74 -0
  89. data/lib/{concurrent → concurrent-ruby/concurrent}/settable_struct.rb +12 -1
  90. data/lib/{concurrent → concurrent-ruby/concurrent}/synchronization/abstract_lockable_object.rb +5 -5
  91. data/lib/{concurrent → concurrent-ruby/concurrent}/synchronization/abstract_struct.rb +18 -4
  92. data/lib/{concurrent → concurrent-ruby/concurrent}/synchronization/condition.rb +2 -0
  93. data/lib/{concurrent → concurrent-ruby/concurrent}/synchronization/jruby_object.rb +1 -0
  94. data/lib/{concurrent → concurrent-ruby/concurrent}/synchronization/lock.rb +2 -0
  95. data/lib/{concurrent → concurrent-ruby/concurrent}/synchronization/lockable_object.rb +8 -10
  96. data/lib/{concurrent → concurrent-ruby/concurrent}/synchronization/mri_object.rb +1 -0
  97. data/lib/concurrent-ruby/concurrent/synchronization/mutex_lockable_object.rb +88 -0
  98. data/lib/{concurrent → concurrent-ruby/concurrent}/synchronization/object.rb +53 -23
  99. data/lib/{concurrent → concurrent-ruby/concurrent}/synchronization/rbx_lockable_object.rb +6 -0
  100. data/lib/{concurrent → concurrent-ruby/concurrent}/synchronization/rbx_object.rb +1 -0
  101. data/lib/concurrent-ruby/concurrent/synchronization/truffleruby_object.rb +47 -0
  102. data/lib/{concurrent → concurrent-ruby/concurrent}/synchronization/volatile.rb +11 -9
  103. data/lib/{concurrent → concurrent-ruby/concurrent}/synchronization.rb +4 -5
  104. data/lib/concurrent-ruby/concurrent/thread_safe/util/data_structures.rb +88 -0
  105. data/lib/{concurrent → concurrent-ruby/concurrent}/thread_safe/util/striped64.rb +9 -4
  106. data/lib/{concurrent → concurrent-ruby/concurrent}/timer_task.rb +15 -35
  107. data/lib/{concurrent → concurrent-ruby/concurrent}/tuple.rb +1 -1
  108. data/lib/{concurrent → concurrent-ruby/concurrent}/tvar.rb +21 -58
  109. data/lib/{concurrent → concurrent-ruby/concurrent}/utility/engine.rb +4 -4
  110. data/lib/concurrent-ruby/concurrent/utility/monotonic_time.rb +90 -0
  111. data/lib/concurrent-ruby/concurrent/utility/native_extension_loader.rb +79 -0
  112. data/lib/{concurrent → concurrent-ruby/concurrent}/utility/processor_counter.rb +5 -35
  113. data/lib/concurrent-ruby/concurrent/version.rb +3 -0
  114. data/lib/concurrent-ruby/concurrent-ruby.rb +5 -0
  115. data/lib/{concurrent.rb → concurrent-ruby/concurrent.rb} +24 -20
  116. metadata +149 -134
  117. data/lib/concurrent/array.rb +0 -39
  118. data/lib/concurrent/atomic/atomic_reference.rb +0 -51
  119. data/lib/concurrent/atomic_reference/concurrent_update_error.rb +0 -8
  120. data/lib/concurrent/atomic_reference/direct_update.rb +0 -81
  121. data/lib/concurrent/atomic_reference/jruby+truffle.rb +0 -2
  122. data/lib/concurrent/atomic_reference/jruby.rb +0 -16
  123. data/lib/concurrent/atomic_reference/rbx.rb +0 -22
  124. data/lib/concurrent/atomic_reference/ruby.rb +0 -32
  125. data/lib/concurrent/atomics.rb +0 -53
  126. data/lib/concurrent/edge.rb +0 -26
  127. data/lib/concurrent/hash.rb +0 -36
  128. data/lib/concurrent/lazy_register.rb +0 -81
  129. data/lib/concurrent/map.rb +0 -240
  130. data/lib/concurrent/synchronization/mri_lockable_object.rb +0 -71
  131. data/lib/concurrent/synchronization/truffle_lockable_object.rb +0 -9
  132. data/lib/concurrent/synchronization/truffle_object.rb +0 -31
  133. data/lib/concurrent/thread_safe/util/array_hash_rbx.rb +0 -30
  134. data/lib/concurrent/utility/at_exit.rb +0 -97
  135. data/lib/concurrent/utility/monotonic_time.rb +0 -58
  136. data/lib/concurrent/utility/native_extension_loader.rb +0 -73
  137. data/lib/concurrent/version.rb +0 -4
  138. /data/lib/{concurrent → concurrent-ruby/concurrent}/atomic/abstract_thread_local_var.rb +0 -0
  139. /data/lib/{concurrent → concurrent-ruby/concurrent}/atomic/java_thread_local_var.rb +0 -0
  140. /data/lib/{concurrent → concurrent-ruby/concurrent}/atomic/mutex_atomic_fixnum.rb +0 -0
  141. /data/lib/{concurrent → concurrent-ruby/concurrent}/collection/copy_on_notify_observer_set.rb +0 -0
  142. /data/lib/{concurrent → concurrent-ruby/concurrent}/collection/copy_on_write_observer_set.rb +0 -0
  143. /data/lib/{concurrent → concurrent-ruby/concurrent}/collection/java_non_concurrent_priority_queue.rb +0 -0
  144. /data/lib/{concurrent → concurrent-ruby/concurrent}/collection/map/synchronized_map_backend.rb +0 -0
  145. /data/lib/{concurrent → concurrent-ruby/concurrent}/concern/deprecation.rb +0 -0
  146. /data/lib/{concurrent → concurrent-ruby/concurrent}/concern/obligation.rb +0 -0
  147. /data/lib/{concurrent → concurrent-ruby/concurrent}/errors.rb +0 -0
  148. /data/lib/{concurrent → concurrent-ruby/concurrent}/executor/immediate_executor.rb +0 -0
  149. /data/lib/{concurrent → concurrent-ruby/concurrent}/executor/indirect_immediate_executor.rb +0 -0
  150. /data/lib/{concurrent → concurrent-ruby/concurrent}/executor/serial_executor_service.rb +0 -0
  151. /data/lib/{concurrent → concurrent-ruby/concurrent}/executor/serialized_execution.rb +0 -0
  152. /data/lib/{concurrent → concurrent-ruby/concurrent}/executor/serialized_execution_delegator.rb +0 -0
  153. /data/lib/{concurrent → concurrent-ruby/concurrent}/executors.rb +0 -0
  154. /data/lib/{concurrent → concurrent-ruby/concurrent}/options.rb +0 -0
  155. /data/lib/{concurrent → concurrent-ruby/concurrent}/synchronization/abstract_object.rb +0 -0
  156. /data/lib/{concurrent → concurrent-ruby/concurrent}/synchronization/jruby_lockable_object.rb +0 -0
  157. /data/lib/{concurrent → concurrent-ruby/concurrent}/thread_safe/synchronized_delegator.rb +0 -0
  158. /data/lib/{concurrent → concurrent-ruby/concurrent}/thread_safe/util/adder.rb +0 -0
  159. /data/lib/{concurrent → concurrent-ruby/concurrent}/thread_safe/util/cheap_lockable.rb +0 -0
  160. /data/lib/{concurrent → concurrent-ruby/concurrent}/thread_safe/util/power_of_two_tuple.rb +0 -0
  161. /data/lib/{concurrent → concurrent-ruby/concurrent}/thread_safe/util/volatile.rb +0 -0
  162. /data/lib/{concurrent → concurrent-ruby/concurrent}/thread_safe/util/xor_shift_random.rb +0 -0
  163. /data/lib/{concurrent → concurrent-ruby/concurrent}/thread_safe/util.rb +0 -0
  164. /data/lib/{concurrent → concurrent-ruby/concurrent}/utility/native_integer.rb +0 -0
@@ -1,7 +1,7 @@
1
1
  require 'concurrent/errors'
2
+ require 'concurrent/concern/deprecation'
2
3
  require 'concurrent/executor/executor_service'
3
4
  require 'concurrent/synchronization'
4
- require 'concurrent/utility/at_exit'
5
5
 
6
6
  module Concurrent
7
7
 
@@ -9,6 +9,7 @@ module Concurrent
9
9
  # @!visibility private
10
10
  class AbstractExecutorService < Synchronization::LockableObject
11
11
  include ExecutorService
12
+ include Concern::Deprecation
12
13
 
13
14
  # The set of possible fallback policies that may be set at thread pool creation.
14
15
  FALLBACK_POLICIES = [:abort, :discard, :caller_runs].freeze
@@ -16,10 +17,20 @@ module Concurrent
16
17
  # @!macro executor_service_attr_reader_fallback_policy
17
18
  attr_reader :fallback_policy
18
19
 
20
+ attr_reader :name
21
+
19
22
  # Create a new thread pool.
20
- def initialize(*args, &block)
23
+ def initialize(opts = {}, &block)
21
24
  super(&nil)
22
- synchronize { ns_initialize(*args, &block) }
25
+ synchronize do
26
+ @auto_terminate = opts.fetch(:auto_terminate, true)
27
+ @name = opts.fetch(:name) if opts.key?(:name)
28
+ ns_initialize(opts, &block)
29
+ end
30
+ end
31
+
32
+ def to_s
33
+ name ? "#{super[0..-2]} name: #{name}>" : super
23
34
  end
24
35
 
25
36
  # @!macro executor_service_method_shutdown
@@ -54,38 +65,41 @@ module Concurrent
54
65
 
55
66
  # @!macro executor_service_method_auto_terminate_question
56
67
  def auto_terminate?
57
- synchronize { ns_auto_terminate? }
68
+ synchronize { @auto_terminate }
58
69
  end
59
70
 
60
71
  # @!macro executor_service_method_auto_terminate_setter
61
72
  def auto_terminate=(value)
62
- synchronize { self.ns_auto_terminate = value }
73
+ deprecated "Method #auto_terminate= has no effect. Set :auto_terminate option when executor is initialized."
63
74
  end
64
75
 
65
76
  private
66
77
 
67
- # Handler which executes the `fallback_policy` once the queue size
68
- # reaches `max_queue`.
78
+ # Returns an action which executes the `fallback_policy` once the queue
79
+ # size reaches `max_queue`. The reason for the indirection of an action
80
+ # is so that the work can be deferred outside of synchronization.
69
81
  #
70
82
  # @param [Array] args the arguments to the task which is being handled.
71
83
  #
72
84
  # @!visibility private
73
- def handle_fallback(*args)
85
+ def fallback_action(*args)
74
86
  case fallback_policy
75
87
  when :abort
76
- raise RejectedExecutionError
88
+ lambda { raise RejectedExecutionError }
77
89
  when :discard
78
- false
90
+ lambda { false }
79
91
  when :caller_runs
80
- begin
81
- yield(*args)
82
- rescue => ex
83
- # let it fail
84
- log DEBUG, ex
85
- end
86
- true
92
+ lambda {
93
+ begin
94
+ yield(*args)
95
+ rescue => ex
96
+ # let it fail
97
+ log DEBUG, ex
98
+ end
99
+ true
100
+ }
87
101
  else
88
- fail "Unknown fallback policy #{fallback_policy}"
102
+ lambda { fail "Unknown fallback policy #{fallback_policy}" }
89
103
  end
90
104
  end
91
105
 
@@ -93,7 +107,7 @@ module Concurrent
93
107
  raise NotImplementedError
94
108
  end
95
109
 
96
- # @!macro [attach] executor_service_method_ns_shutdown_execution
110
+ # @!macro executor_service_method_ns_shutdown_execution
97
111
  #
98
112
  # Callback method called when an orderly shutdown has completed.
99
113
  # The default behavior is to signal all waiting threads.
@@ -101,7 +115,7 @@ module Concurrent
101
115
  # do nothing
102
116
  end
103
117
 
104
- # @!macro [attach] executor_service_method_ns_kill_execution
118
+ # @!macro executor_service_method_ns_kill_execution
105
119
  #
106
120
  # Callback method called when the executor has been killed.
107
121
  # The default behavior is to do nothing.
@@ -110,25 +124,8 @@ module Concurrent
110
124
  end
111
125
 
112
126
  def ns_auto_terminate?
113
- !!@auto_terminate
127
+ @auto_terminate
114
128
  end
115
129
 
116
- def ns_auto_terminate=(value)
117
- case value
118
- when true
119
- AtExit.add(self) { terminate_at_exit }
120
- @auto_terminate = true
121
- when false
122
- AtExit.delete(self)
123
- @auto_terminate = false
124
- else
125
- raise ArgumentError
126
- end
127
- end
128
-
129
- def terminate_at_exit
130
- kill # TODO be gentle first
131
- wait_for_termination(10)
132
- end
133
130
  end
134
131
  end
@@ -26,7 +26,7 @@ module Concurrent
26
26
  # @!macro thread_pool_options
27
27
  class CachedThreadPool < ThreadPoolExecutor
28
28
 
29
- # @!macro [attach] cached_thread_pool_method_initialize
29
+ # @!macro cached_thread_pool_method_initialize
30
30
  #
31
31
  # Create a new thread pool.
32
32
  #
@@ -37,7 +37,7 @@ module Concurrent
37
37
  #
38
38
  # @see http://docs.oracle.com/javase/8/docs/api/java/util/concurrent/Executors.html#newCachedThreadPool--
39
39
  def initialize(opts = {})
40
- defaults = { idletime: DEFAULT_THREAD_IDLETIMEOUT }
40
+ defaults = { idletime: DEFAULT_THREAD_IDLETIMEOUT }
41
41
  overrides = { min_threads: 0,
42
42
  max_threads: DEFAULT_MAX_POOL_SIZE,
43
43
  max_queue: DEFAULT_MAX_QUEUE_SIZE }
@@ -51,11 +51,11 @@ module Concurrent
51
51
  def ns_initialize(opts)
52
52
  super(opts)
53
53
  if Concurrent.on_jruby?
54
- @max_queue = 0
55
- @executor = java.util.concurrent.Executors.newCachedThreadPool
54
+ @max_queue = 0
55
+ @executor = java.util.concurrent.Executors.newCachedThreadPool(
56
+ DaemonThreadFactory.new(ns_auto_terminate?))
56
57
  @executor.setRejectedExecutionHandler(FALLBACK_POLICY_CLASSES[@fallback_policy].new)
57
58
  @executor.setKeepAliveTime(opts.fetch(:idletime, DEFAULT_THREAD_IDLETIMEOUT), java.util.concurrent.TimeUnit::SECONDS)
58
- self.auto_terminate = opts.fetch(:auto_terminate, true)
59
59
  end
60
60
  end
61
61
  end
@@ -4,7 +4,7 @@ module Concurrent
4
4
 
5
5
  ###################################################################
6
6
 
7
- # @!macro [new] executor_service_method_post
7
+ # @!macro executor_service_method_post
8
8
  #
9
9
  # Submit a task to the executor for asynchronous processing.
10
10
  #
@@ -17,7 +17,7 @@ module Concurrent
17
17
  #
18
18
  # @raise [ArgumentError] if no task is given
19
19
 
20
- # @!macro [new] executor_service_method_left_shift
20
+ # @!macro executor_service_method_left_shift
21
21
  #
22
22
  # Submit a task to the executor for asynchronous processing.
23
23
  #
@@ -25,13 +25,13 @@ module Concurrent
25
25
  #
26
26
  # @return [self] returns itself
27
27
 
28
- # @!macro [new] executor_service_method_can_overflow_question
28
+ # @!macro executor_service_method_can_overflow_question
29
29
  #
30
30
  # Does the task queue have a maximum size?
31
31
  #
32
32
  # @return [Boolean] True if the task queue has a maximum size else false.
33
33
 
34
- # @!macro [new] executor_service_method_serialized_question
34
+ # @!macro executor_service_method_serialized_question
35
35
  #
36
36
  # Does this executor guarantee serialization of its operations?
37
37
  #
@@ -41,7 +41,7 @@ module Concurrent
41
41
 
42
42
  ###################################################################
43
43
 
44
- # @!macro [new] executor_service_public_api
44
+ # @!macro executor_service_public_api
45
45
  #
46
46
  # @!method post(*args, &task)
47
47
  # @!macro executor_service_method_post
@@ -57,23 +57,23 @@ module Concurrent
57
57
 
58
58
  ###################################################################
59
59
 
60
- # @!macro [new] executor_service_attr_reader_fallback_policy
60
+ # @!macro executor_service_attr_reader_fallback_policy
61
61
  # @return [Symbol] The fallback policy in effect. Either `:abort`, `:discard`, or `:caller_runs`.
62
62
 
63
- # @!macro [new] executor_service_method_shutdown
63
+ # @!macro executor_service_method_shutdown
64
64
  #
65
65
  # Begin an orderly shutdown. Tasks already in the queue will be executed,
66
66
  # but no new tasks will be accepted. Has no additional effect if the
67
67
  # thread pool is not running.
68
68
 
69
- # @!macro [new] executor_service_method_kill
69
+ # @!macro executor_service_method_kill
70
70
  #
71
71
  # Begin an immediate shutdown. In-progress tasks will be allowed to
72
72
  # complete but enqueued tasks will be dismissed and no new tasks
73
73
  # will be accepted. Has no additional effect if the thread pool is
74
74
  # not running.
75
75
 
76
- # @!macro [new] executor_service_method_wait_for_termination
76
+ # @!macro executor_service_method_wait_for_termination
77
77
  #
78
78
  # Block until executor shutdown is complete or until `timeout` seconds have
79
79
  # passed.
@@ -85,41 +85,41 @@ module Concurrent
85
85
  #
86
86
  # @return [Boolean] `true` if shutdown complete or false on `timeout`
87
87
 
88
- # @!macro [new] executor_service_method_running_question
88
+ # @!macro executor_service_method_running_question
89
89
  #
90
90
  # Is the executor running?
91
91
  #
92
92
  # @return [Boolean] `true` when running, `false` when shutting down or shutdown
93
93
 
94
- # @!macro [new] executor_service_method_shuttingdown_question
94
+ # @!macro executor_service_method_shuttingdown_question
95
95
  #
96
96
  # Is the executor shuttingdown?
97
97
  #
98
98
  # @return [Boolean] `true` when not running and not shutdown, else `false`
99
99
 
100
- # @!macro [new] executor_service_method_shutdown_question
100
+ # @!macro executor_service_method_shutdown_question
101
101
  #
102
102
  # Is the executor shutdown?
103
103
  #
104
104
  # @return [Boolean] `true` when shutdown, `false` when shutting down or running
105
105
 
106
- # @!macro [new] executor_service_method_auto_terminate_question
106
+ # @!macro executor_service_method_auto_terminate_question
107
107
  #
108
108
  # Is the executor auto-terminate when the application exits?
109
109
  #
110
110
  # @return [Boolean] `true` when auto-termination is enabled else `false`.
111
111
 
112
- # @!macro [new] executor_service_method_auto_terminate_setter
112
+ # @!macro executor_service_method_auto_terminate_setter
113
113
  #
114
- # Set the auto-terminate behavior for this executor.
115
114
  #
115
+ # Set the auto-terminate behavior for this executor.
116
+ # @deprecated Has no effect
116
117
  # @param [Boolean] value The new auto-terminate value to set for this executor.
117
- #
118
118
  # @return [Boolean] `true` when auto-termination is enabled else `false`.
119
119
 
120
120
  ###################################################################
121
121
 
122
- # @!macro [new] abstract_executor_service_public_api
122
+ # @!macro abstract_executor_service_public_api
123
123
  #
124
124
  # @!macro executor_service_public_api
125
125
  #
@@ -3,44 +3,51 @@ require 'concurrent/executor/thread_pool_executor'
3
3
 
4
4
  module Concurrent
5
5
 
6
- # @!macro [new] thread_pool_executor_constant_default_max_pool_size
6
+ # @!macro thread_pool_executor_constant_default_max_pool_size
7
7
  # Default maximum number of threads that will be created in the pool.
8
8
 
9
- # @!macro [new] thread_pool_executor_constant_default_min_pool_size
9
+ # @!macro thread_pool_executor_constant_default_min_pool_size
10
10
  # Default minimum number of threads that will be retained in the pool.
11
11
 
12
- # @!macro [new] thread_pool_executor_constant_default_max_queue_size
12
+ # @!macro thread_pool_executor_constant_default_max_queue_size
13
13
  # Default maximum number of tasks that may be added to the task queue.
14
14
 
15
- # @!macro [new] thread_pool_executor_constant_default_thread_timeout
15
+ # @!macro thread_pool_executor_constant_default_thread_timeout
16
16
  # Default maximum number of seconds a thread in the pool may remain idle
17
17
  # before being reclaimed.
18
18
 
19
- # @!macro [new] thread_pool_executor_attr_reader_max_length
19
+ # @!macro thread_pool_executor_constant_default_synchronous
20
+ # Default value of the :synchronous option.
21
+
22
+ # @!macro thread_pool_executor_attr_reader_max_length
20
23
  # The maximum number of threads that may be created in the pool.
21
24
  # @return [Integer] The maximum number of threads that may be created in the pool.
22
25
 
23
- # @!macro [new] thread_pool_executor_attr_reader_min_length
26
+ # @!macro thread_pool_executor_attr_reader_min_length
24
27
  # The minimum number of threads that may be retained in the pool.
25
28
  # @return [Integer] The minimum number of threads that may be retained in the pool.
26
29
 
27
- # @!macro [new] thread_pool_executor_attr_reader_largest_length
30
+ # @!macro thread_pool_executor_attr_reader_largest_length
28
31
  # The largest number of threads that have been created in the pool since construction.
29
32
  # @return [Integer] The largest number of threads that have been created in the pool since construction.
30
33
 
31
- # @!macro [new] thread_pool_executor_attr_reader_scheduled_task_count
34
+ # @!macro thread_pool_executor_attr_reader_scheduled_task_count
32
35
  # The number of tasks that have been scheduled for execution on the pool since construction.
33
36
  # @return [Integer] The number of tasks that have been scheduled for execution on the pool since construction.
34
37
 
35
- # @!macro [new] thread_pool_executor_attr_reader_completed_task_count
38
+ # @!macro thread_pool_executor_attr_reader_completed_task_count
36
39
  # The number of tasks that have been completed by the pool since construction.
37
40
  # @return [Integer] The number of tasks that have been completed by the pool since construction.
38
41
 
39
- # @!macro [new] thread_pool_executor_attr_reader_idletime
42
+ # @!macro thread_pool_executor_attr_reader_idletime
40
43
  # The number of seconds that a thread may be idle before being reclaimed.
41
44
  # @return [Integer] The number of seconds that a thread may be idle before being reclaimed.
42
45
 
43
- # @!macro [new] thread_pool_executor_attr_reader_max_queue
46
+ # @!macro thread_pool_executor_attr_reader_synchronous
47
+ # Whether or not a value of 0 for :max_queue option means the queue must perform direct hand-off or rather unbounded queue.
48
+ # @return [true, false]
49
+
50
+ # @!macro thread_pool_executor_attr_reader_max_queue
44
51
  # The maximum number of tasks that may be waiting in the work queue at any one time.
45
52
  # When the queue size reaches `max_queue` subsequent tasks will be rejected in
46
53
  # accordance with the configured `fallback_policy`.
@@ -49,26 +56,33 @@ module Concurrent
49
56
  # When the queue size reaches `max_queue` subsequent tasks will be rejected in
50
57
  # accordance with the configured `fallback_policy`.
51
58
 
52
- # @!macro [new] thread_pool_executor_attr_reader_length
59
+ # @!macro thread_pool_executor_attr_reader_length
53
60
  # The number of threads currently in the pool.
54
61
  # @return [Integer] The number of threads currently in the pool.
55
62
 
56
- # @!macro [new] thread_pool_executor_attr_reader_queue_length
63
+ # @!macro thread_pool_executor_attr_reader_queue_length
57
64
  # The number of tasks in the queue awaiting execution.
58
65
  # @return [Integer] The number of tasks in the queue awaiting execution.
59
66
 
60
- # @!macro [new] thread_pool_executor_attr_reader_remaining_capacity
67
+ # @!macro thread_pool_executor_attr_reader_remaining_capacity
61
68
  # Number of tasks that may be enqueued before reaching `max_queue` and rejecting
62
69
  # new tasks. A value of -1 indicates that the queue may grow without bound.
63
70
  #
64
71
  # @return [Integer] Number of tasks that may be enqueued before reaching `max_queue` and rejecting
65
72
  # new tasks. A value of -1 indicates that the queue may grow without bound.
66
73
 
74
+ # @!macro thread_pool_executor_method_prune_pool
75
+ # Prune the thread pool of unneeded threads
76
+ #
77
+ # What is being pruned is controlled by the min_threads and idletime
78
+ # parameters passed at pool creation time
79
+ #
80
+ # This is a no-op on some pool implementation (e.g. the Java one). The Ruby
81
+ # pool will auto-prune each time a new job is posted. You will need to call
82
+ # this method explicitely in case your application post jobs in bursts (a
83
+ # lot of jobs and then nothing for long periods)
67
84
 
68
-
69
-
70
-
71
- # @!macro [new] thread_pool_executor_public_api
85
+ # @!macro thread_pool_executor_public_api
72
86
  #
73
87
  # @!macro abstract_executor_service_public_api
74
88
  #
@@ -104,23 +118,27 @@ module Concurrent
104
118
  #
105
119
  # @!method can_overflow?
106
120
  # @!macro executor_service_method_can_overflow_question
121
+ #
122
+ # @!method prune_pool
123
+ # @!macro thread_pool_executor_method_prune_pool
107
124
 
108
125
 
109
126
 
110
127
 
111
- # @!macro [new] thread_pool_options
128
+ # @!macro thread_pool_options
112
129
  #
113
130
  # **Thread Pool Options**
114
131
  #
115
132
  # Thread pools support several configuration options:
116
133
  #
117
134
  # * `idletime`: The number of seconds that a thread may be idle before being reclaimed.
135
+ # * `name`: The name of the executor (optional). Printed in the executor's `#to_s` output and
136
+ # a `<name>-worker-<id>` name is given to its threads if supported by used Ruby
137
+ # implementation. `<id>` is uniq for each thread.
118
138
  # * `max_queue`: The maximum number of tasks that may be waiting in the work queue at
119
139
  # any one time. When the queue size reaches `max_queue` and no new threads can be created,
120
140
  # subsequent tasks will be rejected in accordance with the configured `fallback_policy`.
121
- # * `auto_terminate`: When true (default) an `at_exit` handler will be registered which
122
- # will stop the thread pool when the application exits. See below for more information
123
- # on shutting down thread pools.
141
+ # * `auto_terminate`: When true (default), the threads started will be marked as daemon.
124
142
  # * `fallback_policy`: The policy defining how rejected tasks are handled.
125
143
  #
126
144
  # Three fallback policies are supported:
@@ -145,16 +163,12 @@ module Concurrent
145
163
  #
146
164
  # On some runtime platforms (most notably the JVM) the application will not
147
165
  # exit until all thread pools have been shutdown. To prevent applications from
148
- # "hanging" on exit all thread pools include an `at_exit` handler that will
149
- # stop the thread pool when the application exits. This handler uses a brute
150
- # force method to stop the pool and makes no guarantees regarding resources being
151
- # used by any tasks still running. Registration of this `at_exit` handler can be
152
- # prevented by setting the thread pool's constructor `:auto_terminate` option to
153
- # `false` when the thread pool is created. All thread pools support this option.
166
+ # "hanging" on exit, all threads can be marked as daemon according to the
167
+ # `:auto_terminate` option.
154
168
  #
155
169
  # ```ruby
156
- # pool1 = Concurrent::FixedThreadPool.new(5) # an `at_exit` handler will be registered
157
- # pool2 = Concurrent::FixedThreadPool.new(5, auto_terminate: false) # prevent `at_exit` handler registration
170
+ # pool1 = Concurrent::FixedThreadPool.new(5) # threads will be marked as daemon
171
+ # pool2 = Concurrent::FixedThreadPool.new(5, auto_terminate: false) # mark threads as non-daemon
158
172
  # ```
159
173
  #
160
174
  # @note Failure to properly shutdown a thread pool can lead to unpredictable results.
@@ -163,13 +177,13 @@ module Concurrent
163
177
  # @see http://docs.oracle.com/javase/tutorial/essential/concurrency/pools.html Java Tutorials: Thread Pools
164
178
  # @see http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/Executors.html Java Executors class
165
179
  # @see http://docs.oracle.com/javase/8/docs/api/java/util/concurrent/ExecutorService.html Java ExecutorService interface
166
- # @see http://ruby-doc.org//core-2.2.0/Kernel.html#method-i-at_exit Kernel#at_exit
180
+ # @see https://docs.oracle.com/javase/8/docs/api/java/lang/Thread.html#setDaemon-boolean-
167
181
 
168
182
 
169
183
 
170
184
 
171
185
 
172
- # @!macro [attach] fixed_thread_pool
186
+ # @!macro fixed_thread_pool
173
187
  #
174
188
  # A thread pool that reuses a fixed number of threads operating off an unbounded queue.
175
189
  # At any point, at most `num_threads` will be active processing tasks. When all threads are busy new
@@ -182,7 +196,7 @@ module Concurrent
182
196
  # @!macro thread_pool_options
183
197
  class FixedThreadPool < ThreadPoolExecutor
184
198
 
185
- # @!macro [attach] fixed_thread_pool_method_initialize
199
+ # @!macro fixed_thread_pool_method_initialize
186
200
  #
187
201
  # Create a new thread pool.
188
202
  #
@@ -18,15 +18,10 @@ if Concurrent.on_jruby?
18
18
  }.freeze
19
19
  private_constant :FALLBACK_POLICY_CLASSES
20
20
 
21
- def initialize(*args, &block)
22
- super
23
- ns_make_executor_runnable
24
- end
25
-
26
21
  def post(*args, &task)
27
22
  raise ArgumentError.new('no block given') unless block_given?
28
- return handle_fallback(*args, &task) unless running?
29
- @executor.submit_runnable Job.new(args, task)
23
+ return fallback_action(*args, &task).call unless running?
24
+ @executor.submit Job.new(args, task)
30
25
  true
31
26
  rescue Java::JavaUtilConcurrent::RejectedExecutionException
32
27
  raise RejectedExecutionError
@@ -43,7 +38,6 @@ if Concurrent.on_jruby?
43
38
 
44
39
  def shutdown
45
40
  synchronize do
46
- self.ns_auto_terminate = false
47
41
  @executor.shutdown
48
42
  nil
49
43
  end
@@ -51,7 +45,6 @@ if Concurrent.on_jruby?
51
45
 
52
46
  def kill
53
47
  synchronize do
54
- self.ns_auto_terminate = false
55
48
  @executor.shutdownNow
56
49
  nil
57
50
  end
@@ -75,14 +68,6 @@ if Concurrent.on_jruby?
75
68
  @executor.isShutdown || @executor.isTerminated
76
69
  end
77
70
 
78
- def ns_make_executor_runnable
79
- if !defined?(@executor.submit_runnable)
80
- @executor.class.class_eval do
81
- java_alias :submit_runnable, :submit, [java.lang.Runnable.java_class]
82
- end
83
- end
84
- end
85
-
86
71
  class Job
87
72
  include Runnable
88
73
  def initialize(args, block)
@@ -96,5 +81,23 @@ if Concurrent.on_jruby?
96
81
  end
97
82
  private_constant :Job
98
83
  end
84
+
85
+ class DaemonThreadFactory
86
+ # hide include from YARD
87
+ send :include, java.util.concurrent.ThreadFactory
88
+
89
+ def initialize(daemonize = true)
90
+ @daemonize = daemonize
91
+ end
92
+
93
+ def newThread(runnable)
94
+ thread = java.util.concurrent.Executors.defaultThreadFactory().newThread(runnable)
95
+ thread.setDaemon(@daemonize)
96
+ return thread
97
+ end
98
+ end
99
+
100
+ private_constant :DaemonThreadFactory
101
+
99
102
  end
100
103
  end
@@ -17,12 +17,13 @@ if Concurrent.on_jruby?
17
17
  end
18
18
 
19
19
  private
20
-
20
+
21
21
  def ns_initialize(opts)
22
- @executor = java.util.concurrent.Executors.newSingleThreadExecutor
22
+ @executor = java.util.concurrent.Executors.newSingleThreadExecutor(
23
+ DaemonThreadFactory.new(ns_auto_terminate?)
24
+ )
23
25
  @fallback_policy = opts.fetch(:fallback_policy, :discard)
24
26
  raise ArgumentError.new("#{@fallback_policy} is not a valid fallback policy") unless FALLBACK_POLICY_CLASSES.keys.include?(@fallback_policy)
25
- self.auto_terminate = opts.fetch(:auto_terminate, true)
26
27
  end
27
28
  end
28
29
  end
@@ -21,12 +21,18 @@ if Concurrent.on_jruby?
21
21
  # @!macro thread_pool_executor_constant_default_thread_timeout
22
22
  DEFAULT_THREAD_IDLETIMEOUT = 60
23
23
 
24
+ # @!macro thread_pool_executor_constant_default_synchronous
25
+ DEFAULT_SYNCHRONOUS = false
26
+
24
27
  # @!macro thread_pool_executor_attr_reader_max_length
25
28
  attr_reader :max_length
26
29
 
27
30
  # @!macro thread_pool_executor_attr_reader_max_queue
28
31
  attr_reader :max_queue
29
32
 
33
+ # @!macro thread_pool_executor_attr_reader_synchronous
34
+ attr_reader :synchronous
35
+
30
36
  # @!macro thread_pool_executor_method_initialize
31
37
  def initialize(opts = {})
32
38
  super(opts)
@@ -87,15 +93,21 @@ if Concurrent.on_jruby?
87
93
  super && !@executor.isTerminating
88
94
  end
89
95
 
96
+ # @!macro thread_pool_executor_method_prune_pool
97
+ def prune_pool
98
+ end
99
+
90
100
  private
91
101
 
92
102
  def ns_initialize(opts)
93
- min_length = opts.fetch(:min_threads, DEFAULT_MIN_POOL_SIZE).to_i
94
- max_length = opts.fetch(:max_threads, DEFAULT_MAX_POOL_SIZE).to_i
95
- idletime = opts.fetch(:idletime, DEFAULT_THREAD_IDLETIMEOUT).to_i
96
- @max_queue = opts.fetch(:max_queue, DEFAULT_MAX_QUEUE_SIZE).to_i
103
+ min_length = opts.fetch(:min_threads, DEFAULT_MIN_POOL_SIZE).to_i
104
+ max_length = opts.fetch(:max_threads, DEFAULT_MAX_POOL_SIZE).to_i
105
+ idletime = opts.fetch(:idletime, DEFAULT_THREAD_IDLETIMEOUT).to_i
106
+ @max_queue = opts.fetch(:max_queue, DEFAULT_MAX_QUEUE_SIZE).to_i
107
+ @synchronous = opts.fetch(:synchronous, DEFAULT_SYNCHRONOUS)
97
108
  @fallback_policy = opts.fetch(:fallback_policy, :abort)
98
109
 
110
+ raise ArgumentError.new("`synchronous` cannot be set unless `max_queue` is 0") if @synchronous && @max_queue > 0
99
111
  raise ArgumentError.new("`max_threads` cannot be less than #{DEFAULT_MIN_POOL_SIZE}") if max_length < DEFAULT_MIN_POOL_SIZE
100
112
  raise ArgumentError.new("`max_threads` cannot be greater than #{DEFAULT_MAX_POOL_SIZE}") if max_length > DEFAULT_MAX_POOL_SIZE
101
113
  raise ArgumentError.new("`min_threads` cannot be less than #{DEFAULT_MIN_POOL_SIZE}") if min_length < DEFAULT_MIN_POOL_SIZE
@@ -103,18 +115,26 @@ if Concurrent.on_jruby?
103
115
  raise ArgumentError.new("#{fallback_policy} is not a valid fallback policy") unless FALLBACK_POLICY_CLASSES.include?(@fallback_policy)
104
116
 
105
117
  if @max_queue == 0
106
- queue = java.util.concurrent.LinkedBlockingQueue.new
118
+ if @synchronous
119
+ queue = java.util.concurrent.SynchronousQueue.new
120
+ else
121
+ queue = java.util.concurrent.LinkedBlockingQueue.new
122
+ end
107
123
  else
108
124
  queue = java.util.concurrent.LinkedBlockingQueue.new(@max_queue)
109
125
  end
110
126
 
111
127
  @executor = java.util.concurrent.ThreadPoolExecutor.new(
112
- min_length, max_length,
113
- idletime, java.util.concurrent.TimeUnit::SECONDS,
114
- queue, FALLBACK_POLICY_CLASSES[@fallback_policy].new)
128
+ min_length,
129
+ max_length,
130
+ idletime,
131
+ java.util.concurrent.TimeUnit::SECONDS,
132
+ queue,
133
+ DaemonThreadFactory.new(ns_auto_terminate?),
134
+ FALLBACK_POLICY_CLASSES[@fallback_policy].new)
115
135
 
116
- self.auto_terminate = opts.fetch(:auto_terminate, true)
117
136
  end
118
137
  end
138
+
119
139
  end
120
140
  end
@@ -16,10 +16,16 @@ module Concurrent
16
16
 
17
17
  def post(*args, &task)
18
18
  raise ArgumentError.new('no block given') unless block_given?
19
- synchronize do
20
- # If the executor is shut down, reject this task
21
- return handle_fallback(*args, &task) unless running?
22
- ns_execute(*args, &task)
19
+ deferred_action = synchronize {
20
+ if running?
21
+ ns_execute(*args, &task)
22
+ else
23
+ fallback_action(*args, &task)
24
+ end
25
+ }
26
+ if deferred_action
27
+ deferred_action.call
28
+ else
23
29
  true
24
30
  end
25
31
  end
@@ -27,7 +33,6 @@ module Concurrent
27
33
  def shutdown
28
34
  synchronize do
29
35
  break unless running?
30
- self.ns_auto_terminate = false
31
36
  stop_event.set
32
37
  ns_shutdown_execution
33
38
  end
@@ -37,7 +42,6 @@ module Concurrent
37
42
  def kill
38
43
  synchronize do
39
44
  break if shutdown?
40
- self.ns_auto_terminate = false
41
45
  stop_event.set
42
46
  ns_kill_execution
43
47
  stopped_event.set