concurrent-ruby 0.6.0.pre.1 → 0.6.0.pre.2
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.
- checksums.yaml +4 -4
- data/README.md +16 -0
- data/lib/concurrent.rb +9 -29
- data/lib/concurrent/{actor.rb → actor/actor.rb} +3 -3
- data/lib/concurrent/actor/actor_context.rb +77 -0
- data/lib/concurrent/actor/actor_ref.rb +67 -0
- data/lib/concurrent/{postable.rb → actor/postable.rb} +1 -1
- data/lib/concurrent/actor/simple_actor_ref.rb +94 -0
- data/lib/concurrent/actors.rb +5 -0
- data/lib/concurrent/agent.rb +81 -47
- data/lib/concurrent/async.rb +35 -35
- data/lib/concurrent/atomic/atomic_boolean.rb +157 -0
- data/lib/concurrent/atomic/atomic_fixnum.rb +170 -0
- data/lib/concurrent/{condition.rb → atomic/condition.rb} +0 -0
- data/lib/concurrent/{copy_on_notify_observer_set.rb → atomic/copy_on_notify_observer_set.rb} +48 -13
- data/lib/concurrent/{copy_on_write_observer_set.rb → atomic/copy_on_write_observer_set.rb} +41 -20
- data/lib/concurrent/atomic/count_down_latch.rb +116 -0
- data/lib/concurrent/atomic/cyclic_barrier.rb +106 -0
- data/lib/concurrent/atomic/event.rb +103 -0
- data/lib/concurrent/{thread_local_var.rb → atomic/thread_local_var.rb} +0 -0
- data/lib/concurrent/atomics.rb +9 -0
- data/lib/concurrent/channel/buffered_channel.rb +6 -4
- data/lib/concurrent/channel/channel.rb +30 -2
- data/lib/concurrent/channel/unbuffered_channel.rb +2 -2
- data/lib/concurrent/channel/waitable_list.rb +3 -1
- data/lib/concurrent/channels.rb +5 -0
- data/lib/concurrent/{channel → collection}/blocking_ring_buffer.rb +16 -5
- data/lib/concurrent/collection/priority_queue.rb +305 -0
- data/lib/concurrent/{channel → collection}/ring_buffer.rb +6 -1
- data/lib/concurrent/collections.rb +3 -0
- data/lib/concurrent/configuration.rb +68 -19
- data/lib/concurrent/dataflow.rb +9 -9
- data/lib/concurrent/delay.rb +21 -13
- data/lib/concurrent/dereferenceable.rb +40 -33
- data/lib/concurrent/exchanger.rb +3 -0
- data/lib/concurrent/{cached_thread_pool.rb → executor/cached_thread_pool.rb} +8 -9
- data/lib/concurrent/executor/executor.rb +222 -0
- data/lib/concurrent/{fixed_thread_pool.rb → executor/fixed_thread_pool.rb} +6 -7
- data/lib/concurrent/{immediate_executor.rb → executor/immediate_executor.rb} +5 -5
- data/lib/concurrent/executor/java_cached_thread_pool.rb +31 -0
- data/lib/concurrent/{java_fixed_thread_pool.rb → executor/java_fixed_thread_pool.rb} +7 -11
- data/lib/concurrent/executor/java_single_thread_executor.rb +21 -0
- data/lib/concurrent/{java_thread_pool_executor.rb → executor/java_thread_pool_executor.rb} +66 -77
- data/lib/concurrent/executor/one_by_one.rb +65 -0
- data/lib/concurrent/{per_thread_executor.rb → executor/per_thread_executor.rb} +4 -4
- data/lib/concurrent/executor/ruby_cached_thread_pool.rb +29 -0
- data/lib/concurrent/{ruby_fixed_thread_pool.rb → executor/ruby_fixed_thread_pool.rb} +5 -4
- data/lib/concurrent/executor/ruby_single_thread_executor.rb +72 -0
- data/lib/concurrent/executor/ruby_thread_pool_executor.rb +282 -0
- data/lib/concurrent/{ruby_thread_pool_worker.rb → executor/ruby_thread_pool_worker.rb} +6 -6
- data/lib/concurrent/{safe_task_executor.rb → executor/safe_task_executor.rb} +20 -13
- data/lib/concurrent/executor/single_thread_executor.rb +35 -0
- data/lib/concurrent/executor/thread_pool_executor.rb +68 -0
- data/lib/concurrent/executor/timer_set.rb +138 -0
- data/lib/concurrent/executors.rb +9 -0
- data/lib/concurrent/future.rb +39 -40
- data/lib/concurrent/ivar.rb +22 -15
- data/lib/concurrent/mvar.rb +2 -1
- data/lib/concurrent/obligation.rb +9 -3
- data/lib/concurrent/observable.rb +33 -0
- data/lib/concurrent/options_parser.rb +46 -0
- data/lib/concurrent/promise.rb +23 -24
- data/lib/concurrent/scheduled_task.rb +21 -45
- data/lib/concurrent/timer_task.rb +204 -126
- data/lib/concurrent/tvar.rb +1 -1
- data/lib/concurrent/utilities.rb +3 -36
- data/lib/concurrent/{processor_count.rb → utility/processor_count.rb} +1 -1
- data/lib/concurrent/utility/timeout.rb +36 -0
- data/lib/concurrent/utility/timer.rb +21 -0
- data/lib/concurrent/version.rb +1 -1
- data/lib/concurrent_ruby_ext.bundle +0 -0
- data/spec/concurrent/{actor_context_spec.rb → actor/actor_context_spec.rb} +0 -8
- data/spec/concurrent/{actor_ref_shared.rb → actor/actor_ref_shared.rb} +9 -59
- data/spec/concurrent/{actor_spec.rb → actor/actor_spec.rb} +43 -41
- data/spec/concurrent/{postable_shared.rb → actor/postable_shared.rb} +0 -0
- data/spec/concurrent/actor/simple_actor_ref_spec.rb +135 -0
- data/spec/concurrent/agent_spec.rb +160 -71
- data/spec/concurrent/atomic/atomic_boolean_spec.rb +172 -0
- data/spec/concurrent/atomic/atomic_fixnum_spec.rb +186 -0
- data/spec/concurrent/{condition_spec.rb → atomic/condition_spec.rb} +2 -2
- data/spec/concurrent/{copy_on_notify_observer_set_spec.rb → atomic/copy_on_notify_observer_set_spec.rb} +0 -0
- data/spec/concurrent/{copy_on_write_observer_set_spec.rb → atomic/copy_on_write_observer_set_spec.rb} +0 -0
- data/spec/concurrent/atomic/count_down_latch_spec.rb +151 -0
- data/spec/concurrent/atomic/cyclic_barrier_spec.rb +248 -0
- data/spec/concurrent/{event_spec.rb → atomic/event_spec.rb} +18 -3
- data/spec/concurrent/{observer_set_shared.rb → atomic/observer_set_shared.rb} +15 -6
- data/spec/concurrent/{thread_local_var_spec.rb → atomic/thread_local_var_spec.rb} +0 -0
- data/spec/concurrent/channel/buffered_channel_spec.rb +1 -1
- data/spec/concurrent/channel/channel_spec.rb +6 -4
- data/spec/concurrent/channel/probe_spec.rb +37 -9
- data/spec/concurrent/channel/unbuffered_channel_spec.rb +2 -2
- data/spec/concurrent/{channel → collection}/blocking_ring_buffer_spec.rb +0 -0
- data/spec/concurrent/collection/priority_queue_spec.rb +317 -0
- data/spec/concurrent/{channel → collection}/ring_buffer_spec.rb +0 -0
- data/spec/concurrent/configuration_spec.rb +4 -70
- data/spec/concurrent/dereferenceable_shared.rb +5 -4
- data/spec/concurrent/exchanger_spec.rb +10 -5
- data/spec/concurrent/{cached_thread_pool_shared.rb → executor/cached_thread_pool_shared.rb} +15 -37
- data/spec/concurrent/{fixed_thread_pool_shared.rb → executor/fixed_thread_pool_shared.rb} +0 -0
- data/spec/concurrent/{global_thread_pool_shared.rb → executor/global_thread_pool_shared.rb} +10 -8
- data/spec/concurrent/{immediate_executor_spec.rb → executor/immediate_executor_spec.rb} +0 -0
- data/spec/concurrent/{java_cached_thread_pool_spec.rb → executor/java_cached_thread_pool_spec.rb} +1 -21
- data/spec/concurrent/{java_fixed_thread_pool_spec.rb → executor/java_fixed_thread_pool_spec.rb} +0 -0
- data/spec/concurrent/executor/java_single_thread_executor_spec.rb +21 -0
- data/spec/concurrent/{java_thread_pool_executor_spec.rb → executor/java_thread_pool_executor_spec.rb} +0 -0
- data/spec/concurrent/{per_thread_executor_spec.rb → executor/per_thread_executor_spec.rb} +0 -4
- data/spec/concurrent/{ruby_cached_thread_pool_spec.rb → executor/ruby_cached_thread_pool_spec.rb} +1 -1
- data/spec/concurrent/{ruby_fixed_thread_pool_spec.rb → executor/ruby_fixed_thread_pool_spec.rb} +0 -0
- data/spec/concurrent/executor/ruby_single_thread_executor_spec.rb +18 -0
- data/spec/concurrent/{ruby_thread_pool_executor_spec.rb → executor/ruby_thread_pool_executor_spec.rb} +12 -24
- data/spec/concurrent/executor/safe_task_executor_spec.rb +103 -0
- data/spec/concurrent/{thread_pool_class_cast_spec.rb → executor/thread_pool_class_cast_spec.rb} +12 -0
- data/spec/concurrent/{thread_pool_executor_shared.rb → executor/thread_pool_executor_shared.rb} +0 -0
- data/spec/concurrent/{thread_pool_shared.rb → executor/thread_pool_shared.rb} +84 -119
- data/spec/concurrent/executor/timer_set_spec.rb +183 -0
- data/spec/concurrent/future_spec.rb +12 -0
- data/spec/concurrent/ivar_spec.rb +11 -1
- data/spec/concurrent/observable_shared.rb +173 -0
- data/spec/concurrent/observable_spec.rb +51 -0
- data/spec/concurrent/options_parser_spec.rb +71 -0
- data/spec/concurrent/runnable_shared.rb +6 -0
- data/spec/concurrent/scheduled_task_spec.rb +60 -40
- data/spec/concurrent/timer_task_spec.rb +130 -144
- data/spec/concurrent/{processor_count_spec.rb → utility/processor_count_spec.rb} +0 -0
- data/spec/concurrent/{utilities_spec.rb → utility/timeout_spec.rb} +0 -0
- data/spec/concurrent/utility/timer_spec.rb +52 -0
- metadata +147 -108
- data/lib/concurrent/actor_context.rb +0 -31
- data/lib/concurrent/actor_ref.rb +0 -39
- data/lib/concurrent/atomic.rb +0 -121
- data/lib/concurrent/channel/probe.rb +0 -19
- data/lib/concurrent/count_down_latch.rb +0 -60
- data/lib/concurrent/event.rb +0 -80
- data/lib/concurrent/java_cached_thread_pool.rb +0 -45
- data/lib/concurrent/ruby_cached_thread_pool.rb +0 -37
- data/lib/concurrent/ruby_thread_pool_executor.rb +0 -268
- data/lib/concurrent/simple_actor_ref.rb +0 -124
- data/lib/concurrent/thread_pool_executor.rb +0 -30
- data/spec/concurrent/atomic_spec.rb +0 -201
- data/spec/concurrent/count_down_latch_spec.rb +0 -125
- data/spec/concurrent/safe_task_executor_spec.rb +0 -58
- data/spec/concurrent/simple_actor_ref_spec.rb +0 -219
@@ -0,0 +1,222 @@
|
|
1
|
+
require 'concurrent/atomic/event'
|
2
|
+
|
3
|
+
module Concurrent
|
4
|
+
|
5
|
+
# An exception class raised when the maximum queue size is reached and the
|
6
|
+
# `overflow_policy` is set to `:abort`.
|
7
|
+
RejectedExecutionError = Class.new(StandardError)
|
8
|
+
|
9
|
+
module Executor
|
10
|
+
|
11
|
+
# Submit a task to the executor for asynchronous processing.
|
12
|
+
#
|
13
|
+
# @param [Array] args zero or more arguments to be passed to the task
|
14
|
+
#
|
15
|
+
# @yield the asynchronous task to perform
|
16
|
+
#
|
17
|
+
# @return [Boolean] `true` if the task is queued, `false` if the executor
|
18
|
+
# is not running
|
19
|
+
#
|
20
|
+
# @raise [ArgumentError] if no task is given
|
21
|
+
def post(*args, &task)
|
22
|
+
raise ArgumentError.new('no block given') unless block_given?
|
23
|
+
mutex.synchronize do
|
24
|
+
return false unless running?
|
25
|
+
execute(*args, &task)
|
26
|
+
true
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
# Submit a task to the executor for asynchronous processing.
|
31
|
+
#
|
32
|
+
# @param [Proc] task the asynchronous task to perform
|
33
|
+
#
|
34
|
+
# @return [self] returns itself
|
35
|
+
def <<(task)
|
36
|
+
post(&task)
|
37
|
+
self
|
38
|
+
end
|
39
|
+
|
40
|
+
# Is the executor running?
|
41
|
+
#
|
42
|
+
# @return [Boolean] `true` when running, `false` when shutting down or shutdown
|
43
|
+
def running?
|
44
|
+
! stop_event.set?
|
45
|
+
end
|
46
|
+
|
47
|
+
# Is the executor shuttingdown?
|
48
|
+
#
|
49
|
+
# @return [Boolean] `true` when not running and not shutdown, else `false`
|
50
|
+
def shuttingdown?
|
51
|
+
! (running? || shutdown?)
|
52
|
+
end
|
53
|
+
|
54
|
+
# Is the executor shutdown?
|
55
|
+
#
|
56
|
+
# @return [Boolean] `true` when shutdown, `false` when shutting down or running
|
57
|
+
def shutdown?
|
58
|
+
stopped_event.set?
|
59
|
+
end
|
60
|
+
|
61
|
+
# Begin an orderly shutdown. Tasks already in the queue will be executed,
|
62
|
+
# but no new tasks will be accepted. Has no additional effect if the
|
63
|
+
# thread pool is not running.
|
64
|
+
def shutdown
|
65
|
+
mutex.synchronize do
|
66
|
+
break unless running?
|
67
|
+
stop_event.set
|
68
|
+
shutdown_execution
|
69
|
+
end
|
70
|
+
true
|
71
|
+
end
|
72
|
+
|
73
|
+
# Begin an immediate shutdown. In-progress tasks will be allowed to
|
74
|
+
# complete but enqueued tasks will be dismissed and no new tasks
|
75
|
+
# will be accepted. Has no additional effect if the thread pool is
|
76
|
+
# not running.
|
77
|
+
def kill
|
78
|
+
mutex.synchronize do
|
79
|
+
break if shutdown?
|
80
|
+
stop_event.set
|
81
|
+
kill_execution
|
82
|
+
stopped_event.set
|
83
|
+
end
|
84
|
+
true
|
85
|
+
end
|
86
|
+
|
87
|
+
# Block until executor shutdown is complete or until `timeout` seconds have
|
88
|
+
# passed.
|
89
|
+
#
|
90
|
+
# @note Does not initiate shutdown or termination. Either `shutdown` or `kill`
|
91
|
+
# must be called before this method (or on another thread).
|
92
|
+
#
|
93
|
+
# @param [Integer] timeout the maximum number of seconds to wait for shutdown to complete
|
94
|
+
#
|
95
|
+
# @return [Boolean] `true` if shutdown complete or false on `timeout`
|
96
|
+
def wait_for_termination(timeout = nil)
|
97
|
+
stopped_event.wait(timeout)
|
98
|
+
end
|
99
|
+
|
100
|
+
protected
|
101
|
+
|
102
|
+
attr_reader :mutex, :stop_event, :stopped_event
|
103
|
+
|
104
|
+
def init_executor
|
105
|
+
@mutex = Mutex.new
|
106
|
+
@stop_event = Event.new
|
107
|
+
@stopped_event = Event.new
|
108
|
+
end
|
109
|
+
|
110
|
+
def execute(*args, &task)
|
111
|
+
raise NotImplementedError
|
112
|
+
end
|
113
|
+
|
114
|
+
def shutdown_execution
|
115
|
+
stopped_event.set
|
116
|
+
end
|
117
|
+
|
118
|
+
def kill_execution
|
119
|
+
# do nothing
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
if RUBY_PLATFORM == 'java'
|
124
|
+
|
125
|
+
module JavaExecutor
|
126
|
+
|
127
|
+
# Submit a task to the executor for asynchronous processing.
|
128
|
+
#
|
129
|
+
# @param [Array] args zero or more arguments to be passed to the task
|
130
|
+
#
|
131
|
+
# @yield the asynchronous task to perform
|
132
|
+
#
|
133
|
+
# @return [Boolean] `true` if the task is queued, `false` if the executor
|
134
|
+
# is not running
|
135
|
+
#
|
136
|
+
# @raise [ArgumentError] if no task is given
|
137
|
+
def post(*args)
|
138
|
+
raise ArgumentError.new('no block given') unless block_given?
|
139
|
+
if running?
|
140
|
+
@executor.submit{ yield(*args) }
|
141
|
+
true
|
142
|
+
else
|
143
|
+
false
|
144
|
+
end
|
145
|
+
rescue Java::JavaUtilConcurrent::RejectedExecutionException => ex
|
146
|
+
raise RejectedExecutionError
|
147
|
+
end
|
148
|
+
|
149
|
+
# Submit a task to the executor for asynchronous processing.
|
150
|
+
#
|
151
|
+
# @param [Proc] task the asynchronous task to perform
|
152
|
+
#
|
153
|
+
# @return [self] returns itself
|
154
|
+
def <<(task)
|
155
|
+
post(&task)
|
156
|
+
self
|
157
|
+
end
|
158
|
+
|
159
|
+
# Is the executor running?
|
160
|
+
#
|
161
|
+
# @return [Boolean] `true` when running, `false` when shutting down or shutdown
|
162
|
+
def running?
|
163
|
+
! (shuttingdown? || shutdown?)
|
164
|
+
end
|
165
|
+
|
166
|
+
# Is the executor shuttingdown?
|
167
|
+
#
|
168
|
+
# @return [Boolean] `true` when not running and not shutdown, else `false`
|
169
|
+
def shuttingdown?
|
170
|
+
if @executor.respond_to? :isTerminating
|
171
|
+
@executor.isTerminating
|
172
|
+
else
|
173
|
+
false
|
174
|
+
end
|
175
|
+
end
|
176
|
+
|
177
|
+
# Is the executor shutdown?
|
178
|
+
#
|
179
|
+
# @return [Boolean] `true` when shutdown, `false` when shutting down or running
|
180
|
+
def shutdown?
|
181
|
+
@executor.isShutdown || @executor.isTerminated
|
182
|
+
end
|
183
|
+
|
184
|
+
# Block until executor shutdown is complete or until `timeout` seconds have
|
185
|
+
# passed.
|
186
|
+
#
|
187
|
+
# @note Does not initiate shutdown or termination. Either `shutdown` or `kill`
|
188
|
+
# must be called before this method (or on another thread).
|
189
|
+
#
|
190
|
+
# @param [Integer] timeout the maximum number of seconds to wait for shutdown to complete
|
191
|
+
#
|
192
|
+
# @return [Boolean] `true` if shutdown complete or false on `timeout`
|
193
|
+
def wait_for_termination(timeout)
|
194
|
+
@executor.awaitTermination(1000 * timeout, java.util.concurrent.TimeUnit::MILLISECONDS)
|
195
|
+
end
|
196
|
+
|
197
|
+
# Begin an orderly shutdown. Tasks already in the queue will be executed,
|
198
|
+
# but no new tasks will be accepted. Has no additional effect if the
|
199
|
+
# executor is not running.
|
200
|
+
def shutdown
|
201
|
+
@executor.shutdown
|
202
|
+
nil
|
203
|
+
end
|
204
|
+
|
205
|
+
# Begin an immediate shutdown. In-progress tasks will be allowed to
|
206
|
+
# complete but enqueued tasks will be dismissed and no new tasks
|
207
|
+
# will be accepted. Has no additional effect if the executor is
|
208
|
+
# not running.
|
209
|
+
def kill
|
210
|
+
@executor.shutdownNow
|
211
|
+
nil
|
212
|
+
end
|
213
|
+
|
214
|
+
protected
|
215
|
+
|
216
|
+
def set_shutdown_hook
|
217
|
+
# without this the process may fail to exit
|
218
|
+
at_exit { self.kill }
|
219
|
+
end
|
220
|
+
end
|
221
|
+
end
|
222
|
+
end
|
@@ -1,21 +1,21 @@
|
|
1
|
-
require 'concurrent/ruby_fixed_thread_pool'
|
1
|
+
require 'concurrent/executor/ruby_fixed_thread_pool'
|
2
2
|
|
3
3
|
module Concurrent
|
4
4
|
|
5
5
|
if RUBY_PLATFORM == 'java'
|
6
|
-
require 'concurrent/java_fixed_thread_pool'
|
6
|
+
require 'concurrent/executor/java_fixed_thread_pool'
|
7
7
|
# @!macro [attach] fixed_thread_pool
|
8
8
|
#
|
9
9
|
# A thread pool with a set number of threads. The number of threads in the pool
|
10
10
|
# is set on construction and remains constant. When all threads are busy new
|
11
|
-
# tasks
|
11
|
+
# tasks `#post` to the thread pool are enqueued until a thread becomes available.
|
12
12
|
# Should a thread crash for any reason the thread will immediately be removed
|
13
13
|
# from the pool and replaced.
|
14
14
|
#
|
15
|
-
# The API and behavior of this class are based on Java's
|
15
|
+
# The API and behavior of this class are based on Java's `FixedThreadPool`
|
16
16
|
#
|
17
|
-
# @note When running on the JVM (JRuby) this class will inherit from
|
18
|
-
# On all other platforms it will inherit from
|
17
|
+
# @note When running on the JVM (JRuby) this class will inherit from `JavaFixedThreadPool`.
|
18
|
+
# On all other platforms it will inherit from `RubyFixedThreadPool`.
|
19
19
|
#
|
20
20
|
# @see Concurrent::RubyFixedThreadPool
|
21
21
|
# @see Concurrent::JavaFixedThreadPool
|
@@ -23,7 +23,6 @@ module Concurrent
|
|
23
23
|
# @see http://docs.oracle.com/javase/tutorial/essential/concurrency/pools.html
|
24
24
|
# @see http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/Executors.html
|
25
25
|
# @see http://docs.oracle.com/javase/8/docs/api/java/util/concurrent/ExecutorService.html
|
26
|
-
# @see http://stackoverflow.com/questions/17957382/fixedthreadpool-vs-fixedthreadpool-the-lesser-of-two-evils
|
27
26
|
class FixedThreadPool < JavaFixedThreadPool
|
28
27
|
end
|
29
28
|
else
|
@@ -1,14 +1,14 @@
|
|
1
1
|
module Concurrent
|
2
2
|
class ImmediateExecutor
|
3
3
|
|
4
|
-
def post(*args, &
|
4
|
+
def post(*args, &task)
|
5
5
|
raise ArgumentError.new('no block given') unless block_given?
|
6
|
-
|
7
|
-
|
6
|
+
task.call(*args)
|
7
|
+
true
|
8
8
|
end
|
9
9
|
|
10
|
-
def <<(
|
11
|
-
post(&
|
10
|
+
def <<(task)
|
11
|
+
post(&task)
|
12
12
|
self
|
13
13
|
end
|
14
14
|
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
if RUBY_PLATFORM == 'java'
|
2
|
+
|
3
|
+
require 'concurrent/executor/java_thread_pool_executor'
|
4
|
+
|
5
|
+
module Concurrent
|
6
|
+
|
7
|
+
# @!macro cached_thread_pool
|
8
|
+
class JavaCachedThreadPool < JavaThreadPoolExecutor
|
9
|
+
|
10
|
+
# Create a new thread pool.
|
11
|
+
#
|
12
|
+
# @param [Hash] opts the options defining pool behavior.
|
13
|
+
# @option opts [Symbol] :overflow_policy (`:abort`) the overflow policy
|
14
|
+
#
|
15
|
+
# @raise [ArgumentError] if `overflow_policy` is not a known policy
|
16
|
+
#
|
17
|
+
# @see http://docs.oracle.com/javase/8/docs/api/java/util/concurrent/Executors.html#newCachedThreadPool--
|
18
|
+
def initialize(opts = {})
|
19
|
+
@overflow_policy = opts.fetch(:overflow_policy, :abort)
|
20
|
+
@max_queue = 0
|
21
|
+
|
22
|
+
raise ArgumentError.new("#{@overflow_policy} is not a valid overflow policy") unless OVERFLOW_POLICIES.keys.include?(@overflow_policy)
|
23
|
+
|
24
|
+
@executor = java.util.concurrent.Executors.newCachedThreadPool
|
25
|
+
@executor.setRejectedExecutionHandler(OVERFLOW_POLICIES[@overflow_policy].new)
|
26
|
+
|
27
|
+
set_shutdown_hook
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -1,6 +1,6 @@
|
|
1
1
|
if RUBY_PLATFORM == 'java'
|
2
2
|
|
3
|
-
require 'concurrent/java_thread_pool_executor'
|
3
|
+
require 'concurrent/executor/java_thread_pool_executor'
|
4
4
|
|
5
5
|
module Concurrent
|
6
6
|
|
@@ -10,10 +10,10 @@ if RUBY_PLATFORM == 'java'
|
|
10
10
|
# Create a new thread pool.
|
11
11
|
#
|
12
12
|
# @param [Hash] opts the options defining pool behavior.
|
13
|
-
# @option opts [Symbol] :overflow_policy (
|
13
|
+
# @option opts [Symbol] :overflow_policy (`:abort`) the overflow policy
|
14
14
|
#
|
15
|
-
# @raise [ArgumentError] if
|
16
|
-
# @raise [ArgumentError] if
|
15
|
+
# @raise [ArgumentError] if `num_threads` is less than or equal to zero
|
16
|
+
# @raise [ArgumentError] if `overflow_policy` is not a known policy
|
17
17
|
#
|
18
18
|
# @see http://docs.oracle.com/javase/8/docs/api/java/util/concurrent/Executors.html#newFixedThreadPool-int-
|
19
19
|
def initialize(num_threads, opts = {})
|
@@ -23,14 +23,10 @@ if RUBY_PLATFORM == 'java'
|
|
23
23
|
raise ArgumentError.new('number of threads must be greater than zero') if num_threads < 1
|
24
24
|
raise ArgumentError.new("#{@overflow_policy} is not a valid overflow policy") unless OVERFLOW_POLICIES.keys.include?(@overflow_policy)
|
25
25
|
|
26
|
-
@executor = java.util.concurrent.
|
27
|
-
|
28
|
-
@max_queue, java.util.concurrent.TimeUnit::SECONDS,
|
29
|
-
java.util.concurrent.LinkedBlockingQueue.new,
|
30
|
-
OVERFLOW_POLICIES[@overflow_policy].new)
|
26
|
+
@executor = java.util.concurrent.Executors.newFixedThreadPool(num_threads)
|
27
|
+
@executor.setRejectedExecutionHandler(OVERFLOW_POLICIES[@overflow_policy].new)
|
31
28
|
|
32
|
-
|
33
|
-
at_exit { self.kill }
|
29
|
+
set_shutdown_hook
|
34
30
|
end
|
35
31
|
end
|
36
32
|
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
if RUBY_PLATFORM == 'java'
|
2
|
+
require_relative 'executor'
|
3
|
+
|
4
|
+
module Concurrent
|
5
|
+
|
6
|
+
# @!macro single_thread_executor
|
7
|
+
class JavaSingleThreadExecutor
|
8
|
+
include JavaExecutor
|
9
|
+
|
10
|
+
# Create a new thread pool.
|
11
|
+
#
|
12
|
+
# @see http://docs.oracle.com/javase/tutorial/essential/concurrency/pools.html
|
13
|
+
# @see http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/Executors.html
|
14
|
+
# @see http://docs.oracle.com/javase/8/docs/api/java/util/concurrent/ExecutorService.html
|
15
|
+
def initialize(opts = {})
|
16
|
+
@executor = java.util.concurrent.Executors.newSingleThreadExecutor
|
17
|
+
set_shutdown_hook
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -1,26 +1,26 @@
|
|
1
1
|
if RUBY_PLATFORM == 'java'
|
2
|
+
require_relative 'executor'
|
2
3
|
|
3
4
|
module Concurrent
|
4
5
|
|
5
|
-
RejectedExecutionError = Class.new(StandardError) unless defined? RejectedExecutionError
|
6
|
-
|
7
6
|
# @!macro thread_pool_executor
|
8
7
|
class JavaThreadPoolExecutor
|
8
|
+
include JavaExecutor
|
9
9
|
|
10
|
-
#
|
11
|
-
# (unless overridden during construction).
|
10
|
+
# Default maximum number of threads that will be created in the pool.
|
12
11
|
DEFAULT_MAX_POOL_SIZE = java.lang.Integer::MAX_VALUE # 2147483647
|
13
12
|
|
14
|
-
#
|
15
|
-
# (unless overridden during construction).
|
13
|
+
# Default minimum number of threads that will be retained in the pool.
|
16
14
|
DEFAULT_MIN_POOL_SIZE = 0
|
17
15
|
|
16
|
+
# Default maximum number of tasks that may be added to the task queue.
|
18
17
|
DEFAULT_MAX_QUEUE_SIZE = 0
|
19
18
|
|
20
|
-
#
|
21
|
-
# being reclaimed
|
19
|
+
# Default maximum number of seconds a thread in the pool may remain idle
|
20
|
+
# before being reclaimed.
|
22
21
|
DEFAULT_THREAD_IDLETIMEOUT = 60
|
23
22
|
|
23
|
+
# The set of possible overflow policies that may be set at thread pool creation.
|
24
24
|
OVERFLOW_POLICIES = {
|
25
25
|
abort: java.util.concurrent.ThreadPoolExecutor::AbortPolicy,
|
26
26
|
discard: java.util.concurrent.ThreadPoolExecutor::DiscardPolicy,
|
@@ -30,12 +30,37 @@ if RUBY_PLATFORM == 'java'
|
|
30
30
|
# The maximum number of threads that may be created in the pool.
|
31
31
|
attr_reader :max_length
|
32
32
|
|
33
|
+
# The maximum number of tasks that may be waiting in the work queue at any one time.
|
34
|
+
# When the queue size reaches `max_queue` subsequent tasks will be rejected in
|
35
|
+
# accordance with the configured `overflow_policy`.
|
33
36
|
attr_reader :max_queue
|
34
37
|
|
38
|
+
# The policy defining how rejected tasks (tasks received once the queue size reaches
|
39
|
+
# the configured `max_queue`) are handled. Must be one of the values specified in
|
40
|
+
# `OVERFLOW_POLICIES`.
|
35
41
|
attr_reader :overflow_policy
|
36
42
|
|
37
43
|
# Create a new thread pool.
|
38
44
|
#
|
45
|
+
# @param [Hash] opts the options which configure the thread pool
|
46
|
+
#
|
47
|
+
# @option opts [Integer] :max_threads (DEFAULT_MAX_POOL_SIZE) the maximum
|
48
|
+
# number of threads to be created
|
49
|
+
# @option opts [Integer] :min_threads (DEFAULT_MIN_POOL_SIZE) the minimum
|
50
|
+
# number of threads to be retained
|
51
|
+
# @option opts [Integer] :idletime (DEFAULT_THREAD_IDLETIMEOUT) the maximum
|
52
|
+
# number of seconds a thread may be idle before being reclaimed
|
53
|
+
# @option opts [Integer] :max_queue (DEFAULT_MAX_QUEUE_SIZE) the maximum
|
54
|
+
# number of tasks allowed in the work queue at any one time; a value of
|
55
|
+
# zero means the queue may grow without bounnd
|
56
|
+
# @option opts [Symbol] :overflow_policy (:abort) the policy for handling new
|
57
|
+
# tasks that are received when the queue size has reached `max_queue`
|
58
|
+
#
|
59
|
+
# @raise [ArgumentError] if `:max_threads` is less than one
|
60
|
+
# @raise [ArgumentError] if `:min_threads` is less than zero
|
61
|
+
# @raise [ArgumentError] if `:overflow_policy` is not one of the values specified
|
62
|
+
# in `OVERFLOW_POLICIES`
|
63
|
+
#
|
39
64
|
# @see http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/ThreadPoolExecutor.html
|
40
65
|
def initialize(opts = {})
|
41
66
|
min_length = opts.fetch(:min_threads, DEFAULT_MIN_POOL_SIZE).to_i
|
@@ -61,43 +86,70 @@ if RUBY_PLATFORM == 'java'
|
|
61
86
|
idletime, java.util.concurrent.TimeUnit::SECONDS,
|
62
87
|
queue, OVERFLOW_POLICIES[@overflow_policy].new)
|
63
88
|
|
64
|
-
|
65
|
-
at_exit { self.kill }
|
89
|
+
set_shutdown_hook
|
66
90
|
end
|
67
91
|
|
92
|
+
# The minimum number of threads that may be retained in the pool.
|
93
|
+
#
|
94
|
+
# @return [Integer] the min_length
|
68
95
|
def min_length
|
69
96
|
@executor.getCorePoolSize
|
70
97
|
end
|
71
98
|
|
99
|
+
# The maximum number of threads that may be created in the pool.
|
100
|
+
#
|
101
|
+
# @return [Integer] the max_length
|
72
102
|
def max_length
|
73
103
|
@executor.getMaximumPoolSize
|
74
104
|
end
|
75
105
|
|
106
|
+
# The number of threads currently in the pool.
|
107
|
+
#
|
108
|
+
# @return [Integer] the length
|
76
109
|
def length
|
77
110
|
@executor.getPoolSize
|
78
111
|
end
|
79
112
|
alias_method :current_length, :length
|
80
113
|
|
114
|
+
# The largest number of threads that have been created in the pool since construction.
|
115
|
+
#
|
116
|
+
# @return [Integer] the largest_length
|
81
117
|
def largest_length
|
82
118
|
@executor.getLargestPoolSize
|
83
119
|
end
|
84
120
|
|
121
|
+
# The number of tasks that have been scheduled for execution on the pool since construction.
|
122
|
+
#
|
123
|
+
# @return [Integer] the scheduled_task_count
|
85
124
|
def scheduled_task_count
|
86
125
|
@executor.getTaskCount
|
87
126
|
end
|
88
127
|
|
128
|
+
# The number of tasks that have been completed by the pool since construction.
|
129
|
+
#
|
130
|
+
# @return [Integer] the completed_task_count
|
89
131
|
def completed_task_count
|
90
132
|
@executor.getCompletedTaskCount
|
91
133
|
end
|
92
134
|
|
135
|
+
# The number of seconds that a thread may be idle before being reclaimed.
|
136
|
+
#
|
137
|
+
# @return [Integer] the idletime
|
93
138
|
def idletime
|
94
139
|
@executor.getKeepAliveTime(java.util.concurrent.TimeUnit::SECONDS)
|
95
140
|
end
|
96
141
|
|
142
|
+
# The number of tasks in the queue awaiting execution.
|
143
|
+
#
|
144
|
+
# @return [Integer] the queue_length
|
97
145
|
def queue_length
|
98
146
|
@executor.getQueue.size
|
99
147
|
end
|
100
148
|
|
149
|
+
# Number of tasks that may be enqueued before reaching `max_queue` and rejecting
|
150
|
+
# new tasks. A value of -1 indicates that the queue may grow without bound.
|
151
|
+
#
|
152
|
+
# @return [Integer] the remaining_capacity
|
101
153
|
def remaining_capacity
|
102
154
|
@max_queue == 0 ? -1 : @executor.getQueue.remainingCapacity
|
103
155
|
end
|
@@ -113,81 +165,18 @@ if RUBY_PLATFORM == 'java'
|
|
113
165
|
|
114
166
|
# Is the thread pool running?
|
115
167
|
#
|
116
|
-
# @return [Boolean]
|
168
|
+
# @return [Boolean] `true` when running, `false` when shutting down or shutdown
|
117
169
|
def running?
|
118
|
-
|
119
|
-
end
|
120
|
-
|
121
|
-
# Is the thread pool shutdown?
|
122
|
-
#
|
123
|
-
# @return [Boolean] +true+ when shutdown, +false+ when shutting down or running
|
124
|
-
def shutdown?
|
125
|
-
@executor.isShutdown
|
126
|
-
end
|
127
|
-
|
128
|
-
# Block until thread pool shutdown is complete or until +timeout+ seconds have
|
129
|
-
# passed.
|
130
|
-
#
|
131
|
-
# @note Does not initiate shutdown or termination. Either +shutdown+ or +kill+
|
132
|
-
# must be called before this method (or on another thread).
|
133
|
-
#
|
134
|
-
# @param [Integer] timeout the maximum number of seconds to wait for shutdown to complete
|
135
|
-
#
|
136
|
-
# @return [Boolean] +true+ if shutdown complete or false on +timeout+
|
137
|
-
def wait_for_termination(timeout)
|
138
|
-
@executor.awaitTermination(timeout.to_i, java.util.concurrent.TimeUnit::SECONDS)
|
139
|
-
end
|
140
|
-
|
141
|
-
# Submit a task to the thread pool for asynchronous processing.
|
142
|
-
#
|
143
|
-
# @param [Array] args zero or more arguments to be passed to the task
|
144
|
-
#
|
145
|
-
# @yield the asynchronous task to perform
|
146
|
-
#
|
147
|
-
# @return [Boolean] +true+ if the task is queued, +false+ if the thread pool
|
148
|
-
# is not running
|
149
|
-
#
|
150
|
-
# @raise [ArgumentError] if no task is given
|
151
|
-
def post(*args)
|
152
|
-
raise ArgumentError.new('no block given') unless block_given?
|
153
|
-
if running?
|
154
|
-
@executor.submit{ yield(*args) }
|
155
|
-
true
|
156
|
-
else
|
157
|
-
false
|
158
|
-
end
|
159
|
-
rescue Java::JavaUtilConcurrent::RejectedExecutionException => ex
|
160
|
-
raise RejectedExecutionError
|
161
|
-
end
|
162
|
-
|
163
|
-
# Submit a task to the thread pool for asynchronous processing.
|
164
|
-
#
|
165
|
-
# @param [Proc] task the asynchronous task to perform
|
166
|
-
#
|
167
|
-
# @return [self] returns itself
|
168
|
-
def <<(task)
|
169
|
-
@executor.submit(&task)
|
170
|
-
rescue Java::JavaUtilConcurrent::RejectedExecutionException => ex
|
171
|
-
raise RejectedExecutionError
|
170
|
+
super && ! @executor.isTerminating
|
172
171
|
end
|
173
172
|
|
174
173
|
# Begin an orderly shutdown. Tasks already in the queue will be executed,
|
175
174
|
# but no new tasks will be accepted. Has no additional effect if the
|
176
175
|
# thread pool is not running.
|
177
176
|
def shutdown
|
178
|
-
|
179
|
-
@executor.getQueue.clear
|
180
|
-
return nil
|
181
|
-
end
|
182
|
-
|
183
|
-
# Begin an immediate shutdown. In-progress tasks will be allowed to
|
184
|
-
# complete but enqueued tasks will be dismissed and no new tasks
|
185
|
-
# will be accepted. Has no additional effect if the thread pool is
|
186
|
-
# not running.
|
187
|
-
def kill
|
188
|
-
@executor.shutdownNow
|
177
|
+
super
|
189
178
|
@executor.getQueue.clear
|
190
|
-
|
179
|
+
nil
|
191
180
|
end
|
192
181
|
end
|
193
182
|
end
|