concurrent-ruby 0.5.0 → 0.6.0.pre.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (90) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +88 -77
  3. data/lib/concurrent.rb +17 -2
  4. data/lib/concurrent/actor.rb +17 -0
  5. data/lib/concurrent/actor_context.rb +31 -0
  6. data/lib/concurrent/actor_ref.rb +39 -0
  7. data/lib/concurrent/agent.rb +12 -3
  8. data/lib/concurrent/async.rb +290 -0
  9. data/lib/concurrent/atomic.rb +5 -9
  10. data/lib/concurrent/cached_thread_pool.rb +39 -137
  11. data/lib/concurrent/channel/blocking_ring_buffer.rb +60 -0
  12. data/lib/concurrent/channel/buffered_channel.rb +83 -0
  13. data/lib/concurrent/channel/channel.rb +11 -0
  14. data/lib/concurrent/channel/probe.rb +19 -0
  15. data/lib/concurrent/channel/ring_buffer.rb +54 -0
  16. data/lib/concurrent/channel/unbuffered_channel.rb +34 -0
  17. data/lib/concurrent/channel/waitable_list.rb +38 -0
  18. data/lib/concurrent/configuration.rb +92 -0
  19. data/lib/concurrent/dataflow.rb +9 -3
  20. data/lib/concurrent/delay.rb +88 -0
  21. data/lib/concurrent/exchanger.rb +31 -0
  22. data/lib/concurrent/fixed_thread_pool.rb +28 -122
  23. data/lib/concurrent/future.rb +10 -5
  24. data/lib/concurrent/immediate_executor.rb +3 -2
  25. data/lib/concurrent/ivar.rb +2 -1
  26. data/lib/concurrent/java_cached_thread_pool.rb +45 -0
  27. data/lib/concurrent/java_fixed_thread_pool.rb +37 -0
  28. data/lib/concurrent/java_thread_pool_executor.rb +194 -0
  29. data/lib/concurrent/per_thread_executor.rb +23 -0
  30. data/lib/concurrent/postable.rb +2 -0
  31. data/lib/concurrent/processor_count.rb +125 -0
  32. data/lib/concurrent/promise.rb +42 -18
  33. data/lib/concurrent/ruby_cached_thread_pool.rb +37 -0
  34. data/lib/concurrent/ruby_fixed_thread_pool.rb +31 -0
  35. data/lib/concurrent/ruby_thread_pool_executor.rb +268 -0
  36. data/lib/concurrent/ruby_thread_pool_worker.rb +69 -0
  37. data/lib/concurrent/simple_actor_ref.rb +124 -0
  38. data/lib/concurrent/thread_local_var.rb +1 -1
  39. data/lib/concurrent/thread_pool_executor.rb +30 -0
  40. data/lib/concurrent/timer_task.rb +13 -10
  41. data/lib/concurrent/tvar.rb +212 -0
  42. data/lib/concurrent/utilities.rb +1 -0
  43. data/lib/concurrent/version.rb +1 -1
  44. data/spec/concurrent/actor_context_spec.rb +37 -0
  45. data/spec/concurrent/actor_ref_shared.rb +313 -0
  46. data/spec/concurrent/actor_spec.rb +9 -1
  47. data/spec/concurrent/agent_spec.rb +97 -96
  48. data/spec/concurrent/async_spec.rb +320 -0
  49. data/spec/concurrent/cached_thread_pool_shared.rb +137 -0
  50. data/spec/concurrent/channel/blocking_ring_buffer_spec.rb +149 -0
  51. data/spec/concurrent/channel/buffered_channel_spec.rb +151 -0
  52. data/spec/concurrent/channel/channel_spec.rb +37 -0
  53. data/spec/concurrent/channel/probe_spec.rb +49 -0
  54. data/spec/concurrent/channel/ring_buffer_spec.rb +126 -0
  55. data/spec/concurrent/channel/unbuffered_channel_spec.rb +132 -0
  56. data/spec/concurrent/configuration_spec.rb +134 -0
  57. data/spec/concurrent/dataflow_spec.rb +109 -27
  58. data/spec/concurrent/delay_spec.rb +77 -0
  59. data/spec/concurrent/exchanger_spec.rb +66 -0
  60. data/spec/concurrent/fixed_thread_pool_shared.rb +136 -0
  61. data/spec/concurrent/future_spec.rb +60 -51
  62. data/spec/concurrent/global_thread_pool_shared.rb +33 -0
  63. data/spec/concurrent/immediate_executor_spec.rb +4 -25
  64. data/spec/concurrent/ivar_spec.rb +36 -23
  65. data/spec/concurrent/java_cached_thread_pool_spec.rb +64 -0
  66. data/spec/concurrent/java_fixed_thread_pool_spec.rb +64 -0
  67. data/spec/concurrent/java_thread_pool_executor_spec.rb +71 -0
  68. data/spec/concurrent/obligation_shared.rb +32 -20
  69. data/spec/concurrent/{global_thread_pool_spec.rb → per_thread_executor_spec.rb} +9 -13
  70. data/spec/concurrent/processor_count_spec.rb +20 -0
  71. data/spec/concurrent/promise_spec.rb +29 -41
  72. data/spec/concurrent/ruby_cached_thread_pool_spec.rb +69 -0
  73. data/spec/concurrent/ruby_fixed_thread_pool_spec.rb +39 -0
  74. data/spec/concurrent/ruby_thread_pool_executor_spec.rb +183 -0
  75. data/spec/concurrent/simple_actor_ref_spec.rb +219 -0
  76. data/spec/concurrent/thread_pool_class_cast_spec.rb +40 -0
  77. data/spec/concurrent/thread_pool_executor_shared.rb +155 -0
  78. data/spec/concurrent/thread_pool_shared.rb +98 -36
  79. data/spec/concurrent/tvar_spec.rb +137 -0
  80. data/spec/spec_helper.rb +4 -0
  81. data/spec/support/functions.rb +4 -0
  82. metadata +85 -20
  83. data/lib/concurrent/cached_thread_pool/worker.rb +0 -91
  84. data/lib/concurrent/channel.rb +0 -63
  85. data/lib/concurrent/fixed_thread_pool/worker.rb +0 -54
  86. data/lib/concurrent/global_thread_pool.rb +0 -42
  87. data/spec/concurrent/cached_thread_pool_spec.rb +0 -101
  88. data/spec/concurrent/channel_spec.rb +0 -86
  89. data/spec/concurrent/fixed_thread_pool_spec.rb +0 -92
  90. data/spec/concurrent/uses_global_thread_pool_shared.rb +0 -64
@@ -0,0 +1,31 @@
1
+ module Concurrent
2
+ class Exchanger
3
+
4
+ EMPTY = Object.new
5
+
6
+ def initialize(opts = {})
7
+ @first = MVar.new(EMPTY, opts)
8
+ @second = MVar.new(MVar::EMPTY, opts)
9
+ end
10
+
11
+ def exchange(value, timeout = nil)
12
+ first = @first.take(timeout)
13
+ if first == MVar::TIMEOUT
14
+ nil
15
+ elsif first == EMPTY
16
+ @first.put value
17
+ second = @second.take timeout
18
+ if second == MVar::TIMEOUT
19
+ nil
20
+ else
21
+ second
22
+ end
23
+ else
24
+ @first.put EMPTY
25
+ @second.put value
26
+ first
27
+ end
28
+ end
29
+
30
+ end
31
+ end
@@ -1,128 +1,34 @@
1
- require 'thread'
2
-
3
- require 'concurrent/event'
4
- require 'concurrent/fixed_thread_pool/worker'
1
+ require 'concurrent/ruby_fixed_thread_pool'
5
2
 
6
3
  module Concurrent
7
4
 
8
- class FixedThreadPool
9
-
10
- MIN_POOL_SIZE = 1
11
- MAX_POOL_SIZE = 256
12
-
13
- attr_accessor :max_threads
14
-
15
- def initialize(size, opts = {})
16
- @max_threads = size || MAX_POOL_SIZE
17
- if @max_threads < MIN_POOL_SIZE || @max_threads > MAX_POOL_SIZE
18
- raise ArgumentError.new("size must be from #{MIN_POOL_SIZE} to #{MAX_POOL_SIZE}")
19
- end
20
-
21
- @state = :running
22
- @pool = []
23
- @terminator = Event.new
24
- @queue = Queue.new
25
- @mutex = Mutex.new
26
- end
27
-
28
- def running?
29
- return @state == :running
30
- end
31
-
32
- def wait_for_termination(timeout = nil)
33
- return @terminator.wait(timeout)
34
- end
35
-
36
- def post(*args, &block)
37
- raise ArgumentError.new('no block given') if block.nil?
38
- @mutex.synchronize do
39
- break false unless @state == :running
40
- @queue << [args, block]
41
- clean_pool
42
- fill_pool
43
- true
44
- end
45
- end
46
-
47
- def <<(block)
48
- self.post(&block)
49
- return self
50
- end
51
-
52
- def shutdown
53
- @mutex.synchronize do
54
- break unless @state == :running
55
- if @pool.empty?
56
- @state = :shutdown
57
- @terminator.set
58
- else
59
- @state = :shuttingdown
60
- @pool.length.times{ @queue << :stop }
61
- end
62
- end
63
- end
64
-
65
- def kill
66
- @mutex.synchronize do
67
- break if @state == :shutdown
68
- @state = :shutdown
69
- @queue.clear
70
- drain_pool
71
- @terminator.set
72
- end
73
- end
74
-
75
- def length
76
- @mutex.synchronize do
77
- @state == :running ? @pool.length : 0
78
- end
79
- end
80
-
81
- def create_worker_thread
82
- wrkr = Worker.new(@queue, self)
83
- Thread.new(wrkr, self) do |worker, parent|
84
- Thread.current.abort_on_exception = false
85
- worker.run
86
- parent.on_worker_exit(worker)
87
- end
88
- return wrkr
89
- end
90
-
91
- def fill_pool
92
- return unless @state == :running
93
- while @pool.length < @max_threads
94
- @pool << create_worker_thread
95
- end
96
- end
97
-
98
- def clean_pool
99
- @pool.reject! {|worker| worker.dead? }
100
- end
101
-
102
- def drain_pool
103
- @pool.each {|worker| worker.kill }
104
- @pool.clear
105
- end
106
-
107
- def on_start_task(worker)
108
- end
109
-
110
- def on_end_task(worker)
111
- @mutex.synchronize do
112
- break unless @state == :running
113
- clean_pool
114
- fill_pool
115
- end
116
- end
117
-
118
- def on_worker_exit(worker)
119
- @mutex.synchronize do
120
- @pool.delete(worker)
121
- if @pool.empty? && @state != :running
122
- @state = :shutdown
123
- @terminator.set
124
- end
125
- end
5
+ if RUBY_PLATFORM == 'java'
6
+ require 'concurrent/java_fixed_thread_pool'
7
+ # @!macro [attach] fixed_thread_pool
8
+ #
9
+ # A thread pool with a set number of threads. The number of threads in the pool
10
+ # is set on construction and remains constant. When all threads are busy new
11
+ # tasks +#post+ to the thread pool are enqueued until a thread becomes available.
12
+ # Should a thread crash for any reason the thread will immediately be removed
13
+ # from the pool and replaced.
14
+ #
15
+ # The API and behavior of this class are based on Java's +FixedThreadPool+
16
+ #
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
+ #
20
+ # @see Concurrent::RubyFixedThreadPool
21
+ # @see Concurrent::JavaFixedThreadPool
22
+ #
23
+ # @see http://docs.oracle.com/javase/tutorial/essential/concurrency/pools.html
24
+ # @see http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/Executors.html
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
+ class FixedThreadPool < JavaFixedThreadPool
28
+ end
29
+ else
30
+ # @!macro fixed_thread_pool
31
+ class FixedThreadPool < RubyFixedThreadPool
126
32
  end
127
33
  end
128
34
  end
@@ -1,7 +1,7 @@
1
1
  require 'thread'
2
2
 
3
+ require 'concurrent/configuration'
3
4
  require 'concurrent/obligation'
4
- require 'concurrent/global_thread_pool'
5
5
  require 'concurrent/safe_task_executor'
6
6
 
7
7
  module Concurrent
@@ -41,13 +41,18 @@ module Concurrent
41
41
  # @see http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/Future.html java.util.concurrent.Future
42
42
  class Future < IVar
43
43
  include Obligation
44
- include UsesGlobalThreadPool
44
+ include OptionsParser
45
45
 
46
46
  # Create a new +Future+ in the +:unscheduled+ state.
47
47
  #
48
48
  # @yield the asynchronous operation to perform
49
49
  #
50
50
  # @param [Hash] opts the options to create a message with
51
+ # @option opts [Boolean] :operation (false) when +true+ will execute the future on the global
52
+ # operation pool (for long-running operations), when +false+ will execute the future on the
53
+ # global task pool (for short-running tasks)
54
+ # @option opts [object] :executor when provided will run all operations on
55
+ # this executor rather than the global thread pool (overrides :operation)
51
56
  # @option opts [String] :dup_on_deref (false) call +#dup+ before returning the data
52
57
  # @option opts [String] :freeze_on_deref (false) call +#freeze+ before returning the data
53
58
  # @option opts [String] :copy_on_deref (nil) call the given +Proc+ passing the internal value and
@@ -59,6 +64,7 @@ module Concurrent
59
64
  super(IVar::NO_VALUE, opts)
60
65
  @state = :unscheduled
61
66
  @task = block
67
+ @executor = get_executor_from(opts)
62
68
  end
63
69
 
64
70
  # Execute an +:unscheduled+ +Future+. Immediately sets the state to +:pending+ and
@@ -80,7 +86,7 @@ module Concurrent
80
86
  # @since 0.5.0
81
87
  def execute
82
88
  if compare_and_set_state(:pending, :unscheduled)
83
- Future.thread_pool.post { work }
89
+ @executor.post{ work }
84
90
  self
85
91
  end
86
92
  end
@@ -105,7 +111,7 @@ module Concurrent
105
111
  #
106
112
  # @since 0.5.0
107
113
  def self.execute(opts = {}, &block)
108
- return Future.new(opts, &block).execute
114
+ Future.new(opts, &block).execute
109
115
  end
110
116
 
111
117
  protected :set, :fail, :complete
@@ -117,6 +123,5 @@ module Concurrent
117
123
  success, val, reason = SafeTaskExecutor.new(@task).execute
118
124
  complete(success, val, reason)
119
125
  end
120
-
121
126
  end
122
127
  end
@@ -2,13 +2,14 @@ module Concurrent
2
2
  class ImmediateExecutor
3
3
 
4
4
  def post(*args, &block)
5
+ raise ArgumentError.new('no block given') unless block_given?
5
6
  block.call(*args)
7
+ return true
6
8
  end
7
9
 
8
10
  def <<(block)
9
11
  post(&block)
10
12
  self
11
13
  end
12
-
13
14
  end
14
- end
15
+ end
@@ -60,7 +60,7 @@ module Concurrent
60
60
  complete(true, value, nil)
61
61
  end
62
62
 
63
- def fail(reason = nil)
63
+ def fail(reason = StandardError.new)
64
64
  complete(false, nil, reason)
65
65
  end
66
66
 
@@ -73,6 +73,7 @@ module Concurrent
73
73
 
74
74
  time = Time.now
75
75
  @observers.notify_and_delete_observers{ [time, self.value, reason] }
76
+ self
76
77
  end
77
78
  end
78
79
  end
@@ -0,0 +1,45 @@
1
+ if RUBY_PLATFORM == 'java'
2
+
3
+ require 'concurrent/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 [Integer] :max_threads (+DEFAULT_MAX_POOL_SIZE+) maximum number
14
+ # of threads which may be created in the pool
15
+ # @option opts [Integer] :idletime (+DEFAULT_THREAD_IDLETIMEOUT+) maximum
16
+ # number of seconds a thread may be idle before it is reclaimed
17
+ # @option opts [Symbol] :overflow_policy (+:abort+) the overflow policy
18
+ #
19
+ # @raise [ArgumentError] if +max_threads+ is less than or equal to zero
20
+ # @raise [ArgumentError] if +idletime+ is less than or equal to zero
21
+ # @raise [ArgumentError] if +overflow_policy+ is not a known policy
22
+ #
23
+ # @see http://docs.oracle.com/javase/8/docs/api/java/util/concurrent/Executors.html#newCachedThreadPool--
24
+ def initialize(opts = {})
25
+ max_length = opts.fetch(:max_threads, DEFAULT_MAX_POOL_SIZE).to_i
26
+ idletime = opts.fetch(:idletime, DEFAULT_THREAD_IDLETIMEOUT).to_i
27
+ @overflow_policy = opts.fetch(:overflow_policy, :abort)
28
+ @max_queue = 0
29
+
30
+ raise ArgumentError.new('idletime must be greater than zero') if idletime <= 0
31
+ raise ArgumentError.new('max_threads must be greater than zero') if max_length <= 0
32
+ raise ArgumentError.new("#{@overflow_policy} is not a valid overflow policy") unless OVERFLOW_POLICIES.keys.include?(@overflow_policy)
33
+
34
+ @executor = java.util.concurrent.ThreadPoolExecutor.new(
35
+ @max_queue, max_length,
36
+ idletime, java.util.concurrent.TimeUnit::SECONDS,
37
+ java.util.concurrent.SynchronousQueue.new,
38
+ OVERFLOW_POLICIES[@overflow_policy].new)
39
+
40
+ # without this the process may fail to exit
41
+ at_exit { self.kill }
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,37 @@
1
+ if RUBY_PLATFORM == 'java'
2
+
3
+ require 'concurrent/java_thread_pool_executor'
4
+
5
+ module Concurrent
6
+
7
+ # @!macro fixed_thread_pool
8
+ class JavaFixedThreadPool < 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 +num_threads+ is less than or equal to zero
16
+ # @raise [ArgumentError] if +overflow_policy+ is not a known policy
17
+ #
18
+ # @see http://docs.oracle.com/javase/8/docs/api/java/util/concurrent/Executors.html#newFixedThreadPool-int-
19
+ def initialize(num_threads, opts = {})
20
+ @overflow_policy = opts.fetch(:overflow_policy, :abort)
21
+ @max_queue = 0
22
+
23
+ raise ArgumentError.new('number of threads must be greater than zero') if num_threads < 1
24
+ raise ArgumentError.new("#{@overflow_policy} is not a valid overflow policy") unless OVERFLOW_POLICIES.keys.include?(@overflow_policy)
25
+
26
+ @executor = java.util.concurrent.ThreadPoolExecutor.new(
27
+ num_threads, num_threads,
28
+ @max_queue, java.util.concurrent.TimeUnit::SECONDS,
29
+ java.util.concurrent.LinkedBlockingQueue.new,
30
+ OVERFLOW_POLICIES[@overflow_policy].new)
31
+
32
+ # without this the process may fail to exit
33
+ at_exit { self.kill }
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,194 @@
1
+ if RUBY_PLATFORM == 'java'
2
+
3
+ module Concurrent
4
+
5
+ RejectedExecutionError = Class.new(StandardError) unless defined? RejectedExecutionError
6
+
7
+ # @!macro thread_pool_executor
8
+ class JavaThreadPoolExecutor
9
+
10
+ # The maximum number of threads that will be created in the pool
11
+ # (unless overridden during construction).
12
+ DEFAULT_MAX_POOL_SIZE = java.lang.Integer::MAX_VALUE # 2147483647
13
+
14
+ # The minimum number of threads that will be created in the pool
15
+ # (unless overridden during construction).
16
+ DEFAULT_MIN_POOL_SIZE = 0
17
+
18
+ DEFAULT_MAX_QUEUE_SIZE = 0
19
+
20
+ # The maximum number of seconds a thread in the pool may remain idle before
21
+ # being reclaimed (unless overridden during construction).
22
+ DEFAULT_THREAD_IDLETIMEOUT = 60
23
+
24
+ OVERFLOW_POLICIES = {
25
+ abort: java.util.concurrent.ThreadPoolExecutor::AbortPolicy,
26
+ discard: java.util.concurrent.ThreadPoolExecutor::DiscardPolicy,
27
+ caller_runs: java.util.concurrent.ThreadPoolExecutor::CallerRunsPolicy
28
+ }.freeze
29
+
30
+ # The maximum number of threads that may be created in the pool.
31
+ attr_reader :max_length
32
+
33
+ attr_reader :max_queue
34
+
35
+ attr_reader :overflow_policy
36
+
37
+ # Create a new thread pool.
38
+ #
39
+ # @see http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/ThreadPoolExecutor.html
40
+ def initialize(opts = {})
41
+ min_length = opts.fetch(:min_threads, DEFAULT_MIN_POOL_SIZE).to_i
42
+ max_length = opts.fetch(:max_threads, DEFAULT_MAX_POOL_SIZE).to_i
43
+ idletime = opts.fetch(:idletime, DEFAULT_THREAD_IDLETIMEOUT).to_i
44
+ @max_queue = opts.fetch(:max_queue, DEFAULT_MAX_QUEUE_SIZE).to_i
45
+ @overflow_policy = opts.fetch(:overflow_policy, :abort)
46
+
47
+ raise ArgumentError.new('max_threads must be greater than zero') if max_length <= 0
48
+ raise ArgumentError.new('min_threads cannot be less than zero') if min_length < 0
49
+ raise ArgumentError.new("#{@overflow_policy} is not a valid overflow policy") unless OVERFLOW_POLICIES.keys.include?(@overflow_policy)
50
+
51
+ if min_length == 0 && @max_queue == 0
52
+ queue = java.util.concurrent.SynchronousQueue.new
53
+ elsif @max_queue == 0
54
+ queue = java.util.concurrent.LinkedBlockingQueue.new
55
+ else
56
+ queue = java.util.concurrent.LinkedBlockingQueue.new(@max_queue)
57
+ end
58
+
59
+ @executor = java.util.concurrent.ThreadPoolExecutor.new(
60
+ min_length, max_length,
61
+ idletime, java.util.concurrent.TimeUnit::SECONDS,
62
+ queue, OVERFLOW_POLICIES[@overflow_policy].new)
63
+
64
+ # without this the process may fail to exit
65
+ at_exit { self.kill }
66
+ end
67
+
68
+ def min_length
69
+ @executor.getCorePoolSize
70
+ end
71
+
72
+ def max_length
73
+ @executor.getMaximumPoolSize
74
+ end
75
+
76
+ def length
77
+ @executor.getPoolSize
78
+ end
79
+ alias_method :current_length, :length
80
+
81
+ def largest_length
82
+ @executor.getLargestPoolSize
83
+ end
84
+
85
+ def scheduled_task_count
86
+ @executor.getTaskCount
87
+ end
88
+
89
+ def completed_task_count
90
+ @executor.getCompletedTaskCount
91
+ end
92
+
93
+ def idletime
94
+ @executor.getKeepAliveTime(java.util.concurrent.TimeUnit::SECONDS)
95
+ end
96
+
97
+ def queue_length
98
+ @executor.getQueue.size
99
+ end
100
+
101
+ def remaining_capacity
102
+ @max_queue == 0 ? -1 : @executor.getQueue.remainingCapacity
103
+ end
104
+
105
+ # This method is deprecated and will be removed soon.
106
+ # This method is supost to return the threads status, but Java API doesn't
107
+ # provide a way to get the thread status. So we return an empty Array instead.
108
+ def status
109
+ warn '[DEPRECATED] `status` is deprecated and will be removed soon.'
110
+ warn "Calls to `status` return an empty Array. Java ThreadPoolExecutor does not provide thread's status."
111
+ []
112
+ end
113
+
114
+ # Is the thread pool running?
115
+ #
116
+ # @return [Boolean] +true+ when running, +false+ when shutting down or shutdown
117
+ def running?
118
+ ! (@executor.isShutdown || @executor.isTerminated || @executor.isTerminating)
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
172
+ end
173
+
174
+ # Begin an orderly shutdown. Tasks already in the queue will be executed,
175
+ # but no new tasks will be accepted. Has no additional effect if the
176
+ # thread pool is not running.
177
+ def shutdown
178
+ @executor.shutdown
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
189
+ @executor.getQueue.clear
190
+ return nil
191
+ end
192
+ end
193
+ end
194
+ end