concurrent-ruby 1.1.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/CHANGELOG.md +478 -0
- data/Gemfile +41 -0
- data/LICENSE.md +23 -0
- data/README.md +381 -0
- data/Rakefile +327 -0
- data/ext/concurrent-ruby/ConcurrentRubyService.java +17 -0
- data/ext/concurrent-ruby/com/concurrent_ruby/ext/AtomicReferenceLibrary.java +175 -0
- data/ext/concurrent-ruby/com/concurrent_ruby/ext/JRubyMapBackendLibrary.java +248 -0
- data/ext/concurrent-ruby/com/concurrent_ruby/ext/JavaAtomicBooleanLibrary.java +93 -0
- data/ext/concurrent-ruby/com/concurrent_ruby/ext/JavaAtomicFixnumLibrary.java +113 -0
- data/ext/concurrent-ruby/com/concurrent_ruby/ext/JavaSemaphoreLibrary.java +159 -0
- data/ext/concurrent-ruby/com/concurrent_ruby/ext/SynchronizationLibrary.java +307 -0
- data/ext/concurrent-ruby/com/concurrent_ruby/ext/jsr166e/ConcurrentHashMap.java +31 -0
- data/ext/concurrent-ruby/com/concurrent_ruby/ext/jsr166e/ConcurrentHashMapV8.java +3863 -0
- data/ext/concurrent-ruby/com/concurrent_ruby/ext/jsr166e/LongAdder.java +203 -0
- data/ext/concurrent-ruby/com/concurrent_ruby/ext/jsr166e/Striped64.java +342 -0
- data/ext/concurrent-ruby/com/concurrent_ruby/ext/jsr166e/nounsafe/ConcurrentHashMapV8.java +3800 -0
- data/ext/concurrent-ruby/com/concurrent_ruby/ext/jsr166e/nounsafe/LongAdder.java +204 -0
- data/ext/concurrent-ruby/com/concurrent_ruby/ext/jsr166e/nounsafe/Striped64.java +291 -0
- data/ext/concurrent-ruby/com/concurrent_ruby/ext/jsr166y/ThreadLocalRandom.java +199 -0
- data/lib/concurrent-ruby.rb +1 -0
- data/lib/concurrent.rb +134 -0
- data/lib/concurrent/agent.rb +587 -0
- data/lib/concurrent/array.rb +66 -0
- data/lib/concurrent/async.rb +459 -0
- data/lib/concurrent/atom.rb +222 -0
- data/lib/concurrent/atomic/abstract_thread_local_var.rb +66 -0
- data/lib/concurrent/atomic/atomic_boolean.rb +126 -0
- data/lib/concurrent/atomic/atomic_fixnum.rb +143 -0
- data/lib/concurrent/atomic/atomic_markable_reference.rb +164 -0
- data/lib/concurrent/atomic/atomic_reference.rb +204 -0
- data/lib/concurrent/atomic/count_down_latch.rb +100 -0
- data/lib/concurrent/atomic/cyclic_barrier.rb +128 -0
- data/lib/concurrent/atomic/event.rb +109 -0
- data/lib/concurrent/atomic/java_count_down_latch.rb +42 -0
- data/lib/concurrent/atomic/java_thread_local_var.rb +37 -0
- data/lib/concurrent/atomic/mutex_atomic_boolean.rb +62 -0
- data/lib/concurrent/atomic/mutex_atomic_fixnum.rb +75 -0
- data/lib/concurrent/atomic/mutex_count_down_latch.rb +44 -0
- data/lib/concurrent/atomic/mutex_semaphore.rb +115 -0
- data/lib/concurrent/atomic/read_write_lock.rb +254 -0
- data/lib/concurrent/atomic/reentrant_read_write_lock.rb +379 -0
- data/lib/concurrent/atomic/ruby_thread_local_var.rb +161 -0
- data/lib/concurrent/atomic/semaphore.rb +145 -0
- data/lib/concurrent/atomic/thread_local_var.rb +104 -0
- data/lib/concurrent/atomic_reference/mutex_atomic.rb +56 -0
- data/lib/concurrent/atomic_reference/numeric_cas_wrapper.rb +28 -0
- data/lib/concurrent/atomics.rb +10 -0
- data/lib/concurrent/collection/copy_on_notify_observer_set.rb +107 -0
- data/lib/concurrent/collection/copy_on_write_observer_set.rb +111 -0
- data/lib/concurrent/collection/java_non_concurrent_priority_queue.rb +84 -0
- data/lib/concurrent/collection/lock_free_stack.rb +158 -0
- data/lib/concurrent/collection/map/atomic_reference_map_backend.rb +927 -0
- data/lib/concurrent/collection/map/mri_map_backend.rb +66 -0
- data/lib/concurrent/collection/map/non_concurrent_map_backend.rb +140 -0
- data/lib/concurrent/collection/map/synchronized_map_backend.rb +82 -0
- data/lib/concurrent/collection/non_concurrent_priority_queue.rb +143 -0
- data/lib/concurrent/collection/ruby_non_concurrent_priority_queue.rb +150 -0
- data/lib/concurrent/concern/deprecation.rb +34 -0
- data/lib/concurrent/concern/dereferenceable.rb +73 -0
- data/lib/concurrent/concern/logging.rb +32 -0
- data/lib/concurrent/concern/obligation.rb +220 -0
- data/lib/concurrent/concern/observable.rb +110 -0
- data/lib/concurrent/concurrent_ruby.jar +0 -0
- data/lib/concurrent/configuration.rb +184 -0
- data/lib/concurrent/constants.rb +8 -0
- data/lib/concurrent/dataflow.rb +81 -0
- data/lib/concurrent/delay.rb +199 -0
- data/lib/concurrent/errors.rb +69 -0
- data/lib/concurrent/exchanger.rb +352 -0
- data/lib/concurrent/executor/abstract_executor_service.rb +134 -0
- data/lib/concurrent/executor/cached_thread_pool.rb +62 -0
- data/lib/concurrent/executor/executor_service.rb +185 -0
- data/lib/concurrent/executor/fixed_thread_pool.rb +206 -0
- data/lib/concurrent/executor/immediate_executor.rb +66 -0
- data/lib/concurrent/executor/indirect_immediate_executor.rb +44 -0
- data/lib/concurrent/executor/java_executor_service.rb +91 -0
- data/lib/concurrent/executor/java_single_thread_executor.rb +29 -0
- data/lib/concurrent/executor/java_thread_pool_executor.rb +123 -0
- data/lib/concurrent/executor/ruby_executor_service.rb +78 -0
- data/lib/concurrent/executor/ruby_single_thread_executor.rb +22 -0
- data/lib/concurrent/executor/ruby_thread_pool_executor.rb +362 -0
- data/lib/concurrent/executor/safe_task_executor.rb +35 -0
- data/lib/concurrent/executor/serial_executor_service.rb +34 -0
- data/lib/concurrent/executor/serialized_execution.rb +107 -0
- data/lib/concurrent/executor/serialized_execution_delegator.rb +28 -0
- data/lib/concurrent/executor/simple_executor_service.rb +100 -0
- data/lib/concurrent/executor/single_thread_executor.rb +56 -0
- data/lib/concurrent/executor/thread_pool_executor.rb +87 -0
- data/lib/concurrent/executor/timer_set.rb +173 -0
- data/lib/concurrent/executors.rb +20 -0
- data/lib/concurrent/future.rb +141 -0
- data/lib/concurrent/hash.rb +59 -0
- data/lib/concurrent/immutable_struct.rb +93 -0
- data/lib/concurrent/ivar.rb +207 -0
- data/lib/concurrent/map.rb +337 -0
- data/lib/concurrent/maybe.rb +229 -0
- data/lib/concurrent/mutable_struct.rb +229 -0
- data/lib/concurrent/mvar.rb +242 -0
- data/lib/concurrent/options.rb +42 -0
- data/lib/concurrent/promise.rb +579 -0
- data/lib/concurrent/promises.rb +2167 -0
- data/lib/concurrent/re_include.rb +58 -0
- data/lib/concurrent/scheduled_task.rb +318 -0
- data/lib/concurrent/set.rb +66 -0
- data/lib/concurrent/settable_struct.rb +129 -0
- data/lib/concurrent/synchronization.rb +30 -0
- data/lib/concurrent/synchronization/abstract_lockable_object.rb +98 -0
- data/lib/concurrent/synchronization/abstract_object.rb +24 -0
- data/lib/concurrent/synchronization/abstract_struct.rb +160 -0
- data/lib/concurrent/synchronization/condition.rb +60 -0
- data/lib/concurrent/synchronization/jruby_lockable_object.rb +13 -0
- data/lib/concurrent/synchronization/jruby_object.rb +45 -0
- data/lib/concurrent/synchronization/lock.rb +36 -0
- data/lib/concurrent/synchronization/lockable_object.rb +74 -0
- data/lib/concurrent/synchronization/mri_object.rb +44 -0
- data/lib/concurrent/synchronization/mutex_lockable_object.rb +76 -0
- data/lib/concurrent/synchronization/object.rb +183 -0
- data/lib/concurrent/synchronization/rbx_lockable_object.rb +65 -0
- data/lib/concurrent/synchronization/rbx_object.rb +49 -0
- data/lib/concurrent/synchronization/truffleruby_object.rb +47 -0
- data/lib/concurrent/synchronization/volatile.rb +36 -0
- data/lib/concurrent/thread_safe/synchronized_delegator.rb +50 -0
- data/lib/concurrent/thread_safe/util.rb +16 -0
- data/lib/concurrent/thread_safe/util/adder.rb +74 -0
- data/lib/concurrent/thread_safe/util/cheap_lockable.rb +118 -0
- data/lib/concurrent/thread_safe/util/data_structures.rb +63 -0
- data/lib/concurrent/thread_safe/util/power_of_two_tuple.rb +38 -0
- data/lib/concurrent/thread_safe/util/striped64.rb +246 -0
- data/lib/concurrent/thread_safe/util/volatile.rb +75 -0
- data/lib/concurrent/thread_safe/util/xor_shift_random.rb +50 -0
- data/lib/concurrent/timer_task.rb +334 -0
- data/lib/concurrent/tuple.rb +86 -0
- data/lib/concurrent/tvar.rb +258 -0
- data/lib/concurrent/utility/at_exit.rb +97 -0
- data/lib/concurrent/utility/engine.rb +56 -0
- data/lib/concurrent/utility/monotonic_time.rb +58 -0
- data/lib/concurrent/utility/native_extension_loader.rb +79 -0
- data/lib/concurrent/utility/native_integer.rb +53 -0
- data/lib/concurrent/utility/processor_counter.rb +158 -0
- data/lib/concurrent/version.rb +3 -0
- metadata +193 -0
@@ -0,0 +1,66 @@
|
|
1
|
+
require 'concurrent/atomic/event'
|
2
|
+
require 'concurrent/executor/abstract_executor_service'
|
3
|
+
require 'concurrent/executor/serial_executor_service'
|
4
|
+
|
5
|
+
module Concurrent
|
6
|
+
|
7
|
+
# An executor service which runs all operations on the current thread,
|
8
|
+
# blocking as necessary. Operations are performed in the order they are
|
9
|
+
# received and no two operations can be performed simultaneously.
|
10
|
+
#
|
11
|
+
# This executor service exists mainly for testing an debugging. When used
|
12
|
+
# it immediately runs every `#post` operation on the current thread, blocking
|
13
|
+
# that thread until the operation is complete. This can be very beneficial
|
14
|
+
# during testing because it makes all operations deterministic.
|
15
|
+
#
|
16
|
+
# @note Intended for use primarily in testing and debugging.
|
17
|
+
class ImmediateExecutor < AbstractExecutorService
|
18
|
+
include SerialExecutorService
|
19
|
+
|
20
|
+
# Creates a new executor
|
21
|
+
def initialize
|
22
|
+
@stopped = Concurrent::Event.new
|
23
|
+
end
|
24
|
+
|
25
|
+
# @!macro executor_service_method_post
|
26
|
+
def post(*args, &task)
|
27
|
+
raise ArgumentError.new('no block given') unless block_given?
|
28
|
+
return false unless running?
|
29
|
+
task.call(*args)
|
30
|
+
true
|
31
|
+
end
|
32
|
+
|
33
|
+
# @!macro executor_service_method_left_shift
|
34
|
+
def <<(task)
|
35
|
+
post(&task)
|
36
|
+
self
|
37
|
+
end
|
38
|
+
|
39
|
+
# @!macro executor_service_method_running_question
|
40
|
+
def running?
|
41
|
+
! shutdown?
|
42
|
+
end
|
43
|
+
|
44
|
+
# @!macro executor_service_method_shuttingdown_question
|
45
|
+
def shuttingdown?
|
46
|
+
false
|
47
|
+
end
|
48
|
+
|
49
|
+
# @!macro executor_service_method_shutdown_question
|
50
|
+
def shutdown?
|
51
|
+
@stopped.set?
|
52
|
+
end
|
53
|
+
|
54
|
+
# @!macro executor_service_method_shutdown
|
55
|
+
def shutdown
|
56
|
+
@stopped.set
|
57
|
+
true
|
58
|
+
end
|
59
|
+
alias_method :kill, :shutdown
|
60
|
+
|
61
|
+
# @!macro executor_service_method_wait_for_termination
|
62
|
+
def wait_for_termination(timeout = nil)
|
63
|
+
@stopped.wait(timeout)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
require 'concurrent/executor/immediate_executor'
|
2
|
+
require 'concurrent/executor/simple_executor_service'
|
3
|
+
|
4
|
+
module Concurrent
|
5
|
+
# An executor service which runs all operations on a new thread, blocking
|
6
|
+
# until it completes. Operations are performed in the order they are received
|
7
|
+
# and no two operations can be performed simultaneously.
|
8
|
+
#
|
9
|
+
# This executor service exists mainly for testing an debugging. When used it
|
10
|
+
# immediately runs every `#post` operation on a new thread, blocking the
|
11
|
+
# current thread until the operation is complete. This is similar to how the
|
12
|
+
# ImmediateExecutor works, but the operation has the full stack of the new
|
13
|
+
# thread at its disposal. This can be helpful when the operations will spawn
|
14
|
+
# more operations on the same executor and so on - such a situation might
|
15
|
+
# overflow the single stack in case of an ImmediateExecutor, which is
|
16
|
+
# inconsistent with how it would behave for a threaded executor.
|
17
|
+
#
|
18
|
+
# @note Intended for use primarily in testing and debugging.
|
19
|
+
class IndirectImmediateExecutor < ImmediateExecutor
|
20
|
+
# Creates a new executor
|
21
|
+
def initialize
|
22
|
+
super
|
23
|
+
@internal_executor = SimpleExecutorService.new
|
24
|
+
end
|
25
|
+
|
26
|
+
# @!macro executor_service_method_post
|
27
|
+
def post(*args, &task)
|
28
|
+
raise ArgumentError.new("no block given") unless block_given?
|
29
|
+
return false unless running?
|
30
|
+
|
31
|
+
event = Concurrent::Event.new
|
32
|
+
@internal_executor.post do
|
33
|
+
begin
|
34
|
+
task.call(*args)
|
35
|
+
ensure
|
36
|
+
event.set
|
37
|
+
end
|
38
|
+
end
|
39
|
+
event.wait
|
40
|
+
|
41
|
+
true
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,91 @@
|
|
1
|
+
if Concurrent.on_jruby?
|
2
|
+
|
3
|
+
require 'concurrent/errors'
|
4
|
+
require 'concurrent/utility/engine'
|
5
|
+
require 'concurrent/executor/abstract_executor_service'
|
6
|
+
|
7
|
+
module Concurrent
|
8
|
+
|
9
|
+
# @!macro abstract_executor_service_public_api
|
10
|
+
# @!visibility private
|
11
|
+
class JavaExecutorService < AbstractExecutorService
|
12
|
+
java_import 'java.lang.Runnable'
|
13
|
+
|
14
|
+
FALLBACK_POLICY_CLASSES = {
|
15
|
+
abort: java.util.concurrent.ThreadPoolExecutor::AbortPolicy,
|
16
|
+
discard: java.util.concurrent.ThreadPoolExecutor::DiscardPolicy,
|
17
|
+
caller_runs: java.util.concurrent.ThreadPoolExecutor::CallerRunsPolicy
|
18
|
+
}.freeze
|
19
|
+
private_constant :FALLBACK_POLICY_CLASSES
|
20
|
+
|
21
|
+
def initialize(*args, &block)
|
22
|
+
super
|
23
|
+
end
|
24
|
+
|
25
|
+
def post(*args, &task)
|
26
|
+
raise ArgumentError.new('no block given') unless block_given?
|
27
|
+
return handle_fallback(*args, &task) unless running?
|
28
|
+
@executor.submit Job.new(args, task)
|
29
|
+
true
|
30
|
+
rescue Java::JavaUtilConcurrent::RejectedExecutionException
|
31
|
+
raise RejectedExecutionError
|
32
|
+
end
|
33
|
+
|
34
|
+
def wait_for_termination(timeout = nil)
|
35
|
+
if timeout.nil?
|
36
|
+
ok = @executor.awaitTermination(60, java.util.concurrent.TimeUnit::SECONDS) until ok
|
37
|
+
true
|
38
|
+
else
|
39
|
+
@executor.awaitTermination(1000 * timeout, java.util.concurrent.TimeUnit::MILLISECONDS)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def shutdown
|
44
|
+
synchronize do
|
45
|
+
self.ns_auto_terminate = false
|
46
|
+
@executor.shutdown
|
47
|
+
nil
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def kill
|
52
|
+
synchronize do
|
53
|
+
self.ns_auto_terminate = false
|
54
|
+
@executor.shutdownNow
|
55
|
+
nil
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
private
|
60
|
+
|
61
|
+
def ns_running?
|
62
|
+
!(ns_shuttingdown? || ns_shutdown?)
|
63
|
+
end
|
64
|
+
|
65
|
+
def ns_shuttingdown?
|
66
|
+
if @executor.respond_to? :isTerminating
|
67
|
+
@executor.isTerminating
|
68
|
+
else
|
69
|
+
false
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
def ns_shutdown?
|
74
|
+
@executor.isShutdown || @executor.isTerminated
|
75
|
+
end
|
76
|
+
|
77
|
+
class Job
|
78
|
+
include Runnable
|
79
|
+
def initialize(args, block)
|
80
|
+
@args = args
|
81
|
+
@block = block
|
82
|
+
end
|
83
|
+
|
84
|
+
def run
|
85
|
+
@block.call(*@args)
|
86
|
+
end
|
87
|
+
end
|
88
|
+
private_constant :Job
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
if Concurrent.on_jruby?
|
2
|
+
|
3
|
+
require 'concurrent/executor/java_executor_service'
|
4
|
+
require 'concurrent/executor/serial_executor_service'
|
5
|
+
|
6
|
+
module Concurrent
|
7
|
+
|
8
|
+
# @!macro single_thread_executor
|
9
|
+
# @!macro abstract_executor_service_public_api
|
10
|
+
# @!visibility private
|
11
|
+
class JavaSingleThreadExecutor < JavaExecutorService
|
12
|
+
include SerialExecutorService
|
13
|
+
|
14
|
+
# @!macro single_thread_executor_method_initialize
|
15
|
+
def initialize(opts = {})
|
16
|
+
super(opts)
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
def ns_initialize(opts)
|
22
|
+
@executor = java.util.concurrent.Executors.newSingleThreadExecutor
|
23
|
+
@fallback_policy = opts.fetch(:fallback_policy, :discard)
|
24
|
+
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
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,123 @@
|
|
1
|
+
if Concurrent.on_jruby?
|
2
|
+
|
3
|
+
require 'concurrent/executor/java_executor_service'
|
4
|
+
|
5
|
+
module Concurrent
|
6
|
+
|
7
|
+
# @!macro thread_pool_executor
|
8
|
+
# @!macro thread_pool_options
|
9
|
+
# @!visibility private
|
10
|
+
class JavaThreadPoolExecutor < JavaExecutorService
|
11
|
+
|
12
|
+
# @!macro thread_pool_executor_constant_default_max_pool_size
|
13
|
+
DEFAULT_MAX_POOL_SIZE = java.lang.Integer::MAX_VALUE # 2147483647
|
14
|
+
|
15
|
+
# @!macro thread_pool_executor_constant_default_min_pool_size
|
16
|
+
DEFAULT_MIN_POOL_SIZE = 0
|
17
|
+
|
18
|
+
# @!macro thread_pool_executor_constant_default_max_queue_size
|
19
|
+
DEFAULT_MAX_QUEUE_SIZE = 0
|
20
|
+
|
21
|
+
# @!macro thread_pool_executor_constant_default_thread_timeout
|
22
|
+
DEFAULT_THREAD_IDLETIMEOUT = 60
|
23
|
+
|
24
|
+
# @!macro thread_pool_executor_attr_reader_max_length
|
25
|
+
attr_reader :max_length
|
26
|
+
|
27
|
+
# @!macro thread_pool_executor_attr_reader_max_queue
|
28
|
+
attr_reader :max_queue
|
29
|
+
|
30
|
+
# @!macro thread_pool_executor_method_initialize
|
31
|
+
def initialize(opts = {})
|
32
|
+
super(opts)
|
33
|
+
end
|
34
|
+
|
35
|
+
# @!macro executor_service_method_can_overflow_question
|
36
|
+
def can_overflow?
|
37
|
+
@max_queue != 0
|
38
|
+
end
|
39
|
+
|
40
|
+
# @!macro thread_pool_executor_attr_reader_min_length
|
41
|
+
def min_length
|
42
|
+
@executor.getCorePoolSize
|
43
|
+
end
|
44
|
+
|
45
|
+
# @!macro thread_pool_executor_attr_reader_max_length
|
46
|
+
def max_length
|
47
|
+
@executor.getMaximumPoolSize
|
48
|
+
end
|
49
|
+
|
50
|
+
# @!macro thread_pool_executor_attr_reader_length
|
51
|
+
def length
|
52
|
+
@executor.getPoolSize
|
53
|
+
end
|
54
|
+
|
55
|
+
# @!macro thread_pool_executor_attr_reader_largest_length
|
56
|
+
def largest_length
|
57
|
+
@executor.getLargestPoolSize
|
58
|
+
end
|
59
|
+
|
60
|
+
# @!macro thread_pool_executor_attr_reader_scheduled_task_count
|
61
|
+
def scheduled_task_count
|
62
|
+
@executor.getTaskCount
|
63
|
+
end
|
64
|
+
|
65
|
+
# @!macro thread_pool_executor_attr_reader_completed_task_count
|
66
|
+
def completed_task_count
|
67
|
+
@executor.getCompletedTaskCount
|
68
|
+
end
|
69
|
+
|
70
|
+
# @!macro thread_pool_executor_attr_reader_idletime
|
71
|
+
def idletime
|
72
|
+
@executor.getKeepAliveTime(java.util.concurrent.TimeUnit::SECONDS)
|
73
|
+
end
|
74
|
+
|
75
|
+
# @!macro thread_pool_executor_attr_reader_queue_length
|
76
|
+
def queue_length
|
77
|
+
@executor.getQueue.size
|
78
|
+
end
|
79
|
+
|
80
|
+
# @!macro thread_pool_executor_attr_reader_remaining_capacity
|
81
|
+
def remaining_capacity
|
82
|
+
@max_queue == 0 ? -1 : @executor.getQueue.remainingCapacity
|
83
|
+
end
|
84
|
+
|
85
|
+
# @!macro executor_service_method_running_question
|
86
|
+
def running?
|
87
|
+
super && !@executor.isTerminating
|
88
|
+
end
|
89
|
+
|
90
|
+
private
|
91
|
+
|
92
|
+
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
|
97
|
+
@fallback_policy = opts.fetch(:fallback_policy, :abort)
|
98
|
+
|
99
|
+
raise ArgumentError.new("`max_threads` cannot be less than #{DEFAULT_MIN_POOL_SIZE}") if max_length < DEFAULT_MIN_POOL_SIZE
|
100
|
+
raise ArgumentError.new("`max_threads` cannot be greater than #{DEFAULT_MAX_POOL_SIZE}") if max_length > DEFAULT_MAX_POOL_SIZE
|
101
|
+
raise ArgumentError.new("`min_threads` cannot be less than #{DEFAULT_MIN_POOL_SIZE}") if min_length < DEFAULT_MIN_POOL_SIZE
|
102
|
+
raise ArgumentError.new("`min_threads` cannot be more than `max_threads`") if min_length > max_length
|
103
|
+
raise ArgumentError.new("#{fallback_policy} is not a valid fallback policy") unless FALLBACK_POLICY_CLASSES.include?(@fallback_policy)
|
104
|
+
|
105
|
+
if @max_queue == 0
|
106
|
+
queue = java.util.concurrent.LinkedBlockingQueue.new
|
107
|
+
else
|
108
|
+
queue = java.util.concurrent.LinkedBlockingQueue.new(@max_queue)
|
109
|
+
end
|
110
|
+
|
111
|
+
@executor = java.util.concurrent.ThreadPoolExecutor.new(
|
112
|
+
min_length,
|
113
|
+
max_length,
|
114
|
+
idletime,
|
115
|
+
java.util.concurrent.TimeUnit::SECONDS,
|
116
|
+
queue,
|
117
|
+
FALLBACK_POLICY_CLASSES[@fallback_policy].new)
|
118
|
+
|
119
|
+
self.auto_terminate = opts.fetch(:auto_terminate, true)
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
@@ -0,0 +1,78 @@
|
|
1
|
+
require 'concurrent/executor/abstract_executor_service'
|
2
|
+
require 'concurrent/atomic/event'
|
3
|
+
|
4
|
+
module Concurrent
|
5
|
+
|
6
|
+
# @!macro abstract_executor_service_public_api
|
7
|
+
# @!visibility private
|
8
|
+
class RubyExecutorService < AbstractExecutorService
|
9
|
+
safe_initialization!
|
10
|
+
|
11
|
+
def initialize(*args, &block)
|
12
|
+
super
|
13
|
+
@StopEvent = Event.new
|
14
|
+
@StoppedEvent = Event.new
|
15
|
+
end
|
16
|
+
|
17
|
+
def post(*args, &task)
|
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)
|
23
|
+
true
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def shutdown
|
28
|
+
synchronize do
|
29
|
+
break unless running?
|
30
|
+
self.ns_auto_terminate = false
|
31
|
+
stop_event.set
|
32
|
+
ns_shutdown_execution
|
33
|
+
end
|
34
|
+
true
|
35
|
+
end
|
36
|
+
|
37
|
+
def kill
|
38
|
+
synchronize do
|
39
|
+
break if shutdown?
|
40
|
+
self.ns_auto_terminate = false
|
41
|
+
stop_event.set
|
42
|
+
ns_kill_execution
|
43
|
+
stopped_event.set
|
44
|
+
end
|
45
|
+
true
|
46
|
+
end
|
47
|
+
|
48
|
+
def wait_for_termination(timeout = nil)
|
49
|
+
stopped_event.wait(timeout)
|
50
|
+
end
|
51
|
+
|
52
|
+
private
|
53
|
+
|
54
|
+
def stop_event
|
55
|
+
@StopEvent
|
56
|
+
end
|
57
|
+
|
58
|
+
def stopped_event
|
59
|
+
@StoppedEvent
|
60
|
+
end
|
61
|
+
|
62
|
+
def ns_shutdown_execution
|
63
|
+
stopped_event.set
|
64
|
+
end
|
65
|
+
|
66
|
+
def ns_running?
|
67
|
+
!stop_event.set?
|
68
|
+
end
|
69
|
+
|
70
|
+
def ns_shuttingdown?
|
71
|
+
!(ns_running? || ns_shutdown?)
|
72
|
+
end
|
73
|
+
|
74
|
+
def ns_shutdown?
|
75
|
+
stopped_event.set?
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'concurrent/executor/ruby_thread_pool_executor'
|
2
|
+
|
3
|
+
module Concurrent
|
4
|
+
|
5
|
+
# @!macro single_thread_executor
|
6
|
+
# @!macro abstract_executor_service_public_api
|
7
|
+
# @!visibility private
|
8
|
+
class RubySingleThreadExecutor < RubyThreadPoolExecutor
|
9
|
+
|
10
|
+
# @!macro single_thread_executor_method_initialize
|
11
|
+
def initialize(opts = {})
|
12
|
+
super(
|
13
|
+
min_threads: 1,
|
14
|
+
max_threads: 1,
|
15
|
+
max_queue: 0,
|
16
|
+
idletime: DEFAULT_THREAD_IDLETIMEOUT,
|
17
|
+
fallback_policy: opts.fetch(:fallback_policy, :discard),
|
18
|
+
auto_terminate: opts.fetch(:auto_terminate, true)
|
19
|
+
)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|