concurrent-ruby 1.0.5 → 1.1.10

Sign up to get free protection for your applications and to get access to all the features.
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