concurrent-ruby 0.8.0 → 0.9.0.pre2

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 (144) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +97 -2
  3. data/README.md +103 -54
  4. data/lib/concurrent.rb +34 -14
  5. data/lib/concurrent/async.rb +164 -50
  6. data/lib/concurrent/atom.rb +171 -0
  7. data/lib/concurrent/atomic/atomic_boolean.rb +57 -107
  8. data/lib/concurrent/atomic/atomic_fixnum.rb +73 -101
  9. data/lib/concurrent/atomic/atomic_reference.rb +49 -0
  10. data/lib/concurrent/atomic/condition.rb +23 -12
  11. data/lib/concurrent/atomic/count_down_latch.rb +23 -21
  12. data/lib/concurrent/atomic/cyclic_barrier.rb +47 -47
  13. data/lib/concurrent/atomic/event.rb +33 -42
  14. data/lib/concurrent/atomic/read_write_lock.rb +252 -0
  15. data/lib/concurrent/atomic/semaphore.rb +64 -89
  16. data/lib/concurrent/atomic/thread_local_var.rb +130 -58
  17. data/lib/concurrent/atomic/thread_local_var/weak_key_map.rb +236 -0
  18. data/lib/concurrent/atomic_reference/direct_update.rb +3 -0
  19. data/lib/concurrent/atomic_reference/jruby.rb +6 -3
  20. data/lib/concurrent/atomic_reference/mutex_atomic.rb +10 -32
  21. data/lib/concurrent/atomic_reference/numeric_cas_wrapper.rb +3 -0
  22. data/lib/concurrent/atomic_reference/rbx.rb +4 -1
  23. data/lib/concurrent/atomic_reference/ruby.rb +6 -3
  24. data/lib/concurrent/atomics.rb +74 -4
  25. data/lib/concurrent/collection/copy_on_notify_observer_set.rb +115 -0
  26. data/lib/concurrent/collection/copy_on_write_observer_set.rb +119 -0
  27. data/lib/concurrent/collection/priority_queue.rb +300 -245
  28. data/lib/concurrent/concern/deprecation.rb +27 -0
  29. data/lib/concurrent/concern/dereferenceable.rb +88 -0
  30. data/lib/concurrent/concern/logging.rb +25 -0
  31. data/lib/concurrent/concern/obligation.rb +228 -0
  32. data/lib/concurrent/concern/observable.rb +85 -0
  33. data/lib/concurrent/configuration.rb +226 -112
  34. data/lib/concurrent/dataflow.rb +2 -3
  35. data/lib/concurrent/delay.rb +141 -50
  36. data/lib/concurrent/edge.rb +30 -0
  37. data/lib/concurrent/errors.rb +10 -0
  38. data/lib/concurrent/exchanger.rb +25 -1
  39. data/lib/concurrent/executor/cached_thread_pool.rb +46 -33
  40. data/lib/concurrent/executor/executor.rb +46 -299
  41. data/lib/concurrent/executor/executor_service.rb +521 -0
  42. data/lib/concurrent/executor/fixed_thread_pool.rb +206 -26
  43. data/lib/concurrent/executor/immediate_executor.rb +9 -9
  44. data/lib/concurrent/executor/indirect_immediate_executor.rb +4 -3
  45. data/lib/concurrent/executor/java_cached_thread_pool.rb +18 -16
  46. data/lib/concurrent/executor/java_fixed_thread_pool.rb +11 -18
  47. data/lib/concurrent/executor/java_single_thread_executor.rb +17 -16
  48. data/lib/concurrent/executor/java_thread_pool_executor.rb +55 -102
  49. data/lib/concurrent/executor/ruby_cached_thread_pool.rb +9 -18
  50. data/lib/concurrent/executor/ruby_fixed_thread_pool.rb +10 -21
  51. data/lib/concurrent/executor/ruby_single_thread_executor.rb +14 -16
  52. data/lib/concurrent/executor/ruby_thread_pool_executor.rb +250 -166
  53. data/lib/concurrent/executor/safe_task_executor.rb +5 -4
  54. data/lib/concurrent/executor/serialized_execution.rb +22 -18
  55. data/lib/concurrent/executor/{per_thread_executor.rb → simple_executor_service.rb} +29 -20
  56. data/lib/concurrent/executor/single_thread_executor.rb +32 -21
  57. data/lib/concurrent/executor/thread_pool_executor.rb +72 -60
  58. data/lib/concurrent/executor/timer_set.rb +96 -84
  59. data/lib/concurrent/executors.rb +1 -1
  60. data/lib/concurrent/future.rb +70 -38
  61. data/lib/concurrent/immutable_struct.rb +89 -0
  62. data/lib/concurrent/ivar.rb +152 -60
  63. data/lib/concurrent/lazy_register.rb +40 -20
  64. data/lib/concurrent/maybe.rb +226 -0
  65. data/lib/concurrent/mutable_struct.rb +227 -0
  66. data/lib/concurrent/mvar.rb +44 -43
  67. data/lib/concurrent/promise.rb +208 -134
  68. data/lib/concurrent/scheduled_task.rb +339 -43
  69. data/lib/concurrent/settable_struct.rb +127 -0
  70. data/lib/concurrent/synchronization.rb +17 -0
  71. data/lib/concurrent/synchronization/abstract_object.rb +163 -0
  72. data/lib/concurrent/synchronization/abstract_struct.rb +158 -0
  73. data/lib/concurrent/synchronization/condition.rb +53 -0
  74. data/lib/concurrent/synchronization/java_object.rb +35 -0
  75. data/lib/concurrent/synchronization/lock.rb +32 -0
  76. data/lib/concurrent/synchronization/monitor_object.rb +24 -0
  77. data/lib/concurrent/synchronization/mutex_object.rb +43 -0
  78. data/lib/concurrent/synchronization/object.rb +78 -0
  79. data/lib/concurrent/synchronization/rbx_object.rb +75 -0
  80. data/lib/concurrent/timer_task.rb +87 -100
  81. data/lib/concurrent/tvar.rb +42 -38
  82. data/lib/concurrent/utilities.rb +3 -1
  83. data/lib/concurrent/utility/at_exit.rb +97 -0
  84. data/lib/concurrent/utility/engine.rb +40 -0
  85. data/lib/concurrent/utility/monotonic_time.rb +59 -0
  86. data/lib/concurrent/utility/native_extension_loader.rb +56 -0
  87. data/lib/concurrent/utility/processor_counter.rb +156 -0
  88. data/lib/concurrent/utility/timeout.rb +18 -14
  89. data/lib/concurrent/utility/timer.rb +11 -6
  90. data/lib/concurrent/version.rb +2 -1
  91. data/lib/concurrent_ruby.rb +1 -0
  92. metadata +47 -83
  93. data/lib/concurrent/actor.rb +0 -103
  94. data/lib/concurrent/actor/behaviour.rb +0 -70
  95. data/lib/concurrent/actor/behaviour/abstract.rb +0 -48
  96. data/lib/concurrent/actor/behaviour/awaits.rb +0 -21
  97. data/lib/concurrent/actor/behaviour/buffer.rb +0 -54
  98. data/lib/concurrent/actor/behaviour/errors_on_unknown_message.rb +0 -12
  99. data/lib/concurrent/actor/behaviour/executes_context.rb +0 -18
  100. data/lib/concurrent/actor/behaviour/linking.rb +0 -45
  101. data/lib/concurrent/actor/behaviour/pausing.rb +0 -77
  102. data/lib/concurrent/actor/behaviour/removes_child.rb +0 -16
  103. data/lib/concurrent/actor/behaviour/sets_results.rb +0 -36
  104. data/lib/concurrent/actor/behaviour/supervised.rb +0 -59
  105. data/lib/concurrent/actor/behaviour/supervising.rb +0 -34
  106. data/lib/concurrent/actor/behaviour/terminates_children.rb +0 -13
  107. data/lib/concurrent/actor/behaviour/termination.rb +0 -54
  108. data/lib/concurrent/actor/context.rb +0 -154
  109. data/lib/concurrent/actor/core.rb +0 -217
  110. data/lib/concurrent/actor/default_dead_letter_handler.rb +0 -9
  111. data/lib/concurrent/actor/envelope.rb +0 -41
  112. data/lib/concurrent/actor/errors.rb +0 -27
  113. data/lib/concurrent/actor/internal_delegations.rb +0 -49
  114. data/lib/concurrent/actor/public_delegations.rb +0 -40
  115. data/lib/concurrent/actor/reference.rb +0 -81
  116. data/lib/concurrent/actor/root.rb +0 -37
  117. data/lib/concurrent/actor/type_check.rb +0 -48
  118. data/lib/concurrent/actor/utils.rb +0 -10
  119. data/lib/concurrent/actor/utils/ad_hoc.rb +0 -21
  120. data/lib/concurrent/actor/utils/balancer.rb +0 -42
  121. data/lib/concurrent/actor/utils/broadcast.rb +0 -52
  122. data/lib/concurrent/actor/utils/pool.rb +0 -59
  123. data/lib/concurrent/actress.rb +0 -3
  124. data/lib/concurrent/agent.rb +0 -209
  125. data/lib/concurrent/atomic.rb +0 -92
  126. data/lib/concurrent/atomic/copy_on_notify_observer_set.rb +0 -118
  127. data/lib/concurrent/atomic/copy_on_write_observer_set.rb +0 -117
  128. data/lib/concurrent/atomic/synchronization.rb +0 -51
  129. data/lib/concurrent/channel/buffered_channel.rb +0 -85
  130. data/lib/concurrent/channel/channel.rb +0 -41
  131. data/lib/concurrent/channel/unbuffered_channel.rb +0 -35
  132. data/lib/concurrent/channel/waitable_list.rb +0 -40
  133. data/lib/concurrent/channels.rb +0 -5
  134. data/lib/concurrent/collection/blocking_ring_buffer.rb +0 -71
  135. data/lib/concurrent/collection/ring_buffer.rb +0 -59
  136. data/lib/concurrent/collections.rb +0 -3
  137. data/lib/concurrent/dereferenceable.rb +0 -108
  138. data/lib/concurrent/executor/ruby_thread_pool_worker.rb +0 -73
  139. data/lib/concurrent/logging.rb +0 -20
  140. data/lib/concurrent/obligation.rb +0 -171
  141. data/lib/concurrent/observable.rb +0 -73
  142. data/lib/concurrent/options_parser.rb +0 -52
  143. data/lib/concurrent/utility/processor_count.rb +0 -152
  144. data/lib/extension_helper.rb +0 -37
@@ -0,0 +1,521 @@
1
+ require 'concurrent/errors'
2
+ require 'concurrent/concern/deprecation'
3
+ require 'concurrent/concern/logging'
4
+ require 'concurrent/atomic/event'
5
+ require 'concurrent/synchronization'
6
+ require 'concurrent/utility/at_exit'
7
+
8
+ module Concurrent
9
+
10
+ # @!macro [new] executor_service_method_post
11
+ #
12
+ # Submit a task to the executor for asynchronous processing.
13
+ #
14
+ # @param [Array] args zero or more arguments to be passed to the task
15
+ #
16
+ # @yield the asynchronous task to perform
17
+ #
18
+ # @return [Boolean] `true` if the task is queued, `false` if the executor
19
+ # is not running
20
+ #
21
+ # @raise [ArgumentError] if no task is given
22
+
23
+ # @!macro [new] executor_service_method_left_shift
24
+ #
25
+ # Submit a task to the executor for asynchronous processing.
26
+ #
27
+ # @param [Proc] task the asynchronous task to perform
28
+ #
29
+ # @return [self] returns itself
30
+
31
+ # @!macro [new] executor_service_method_can_overflow_question
32
+ #
33
+ # Does the task queue have a maximum size?
34
+ #
35
+ # @return [Boolean] True if the task queue has a maximum size else false.
36
+
37
+ # @!macro [new] executor_service_method_serialized_question
38
+ #
39
+ # Does this executor guarantee serialization of its operations?
40
+ #
41
+ # @return [Boolean] True if the executor guarantees that all operations
42
+ # will be post in the order they are received and no two operations may
43
+ # occur simultaneously. Else false.
44
+
45
+
46
+
47
+
48
+
49
+ # @!macro [new] executor_service_public_api
50
+ #
51
+ # @!method post(*args, &task)
52
+ # @!macro executor_service_method_post
53
+ #
54
+ # @!method <<(task)
55
+ # @!macro executor_service_method_left_shift
56
+ #
57
+ # @!method can_overflow?
58
+ # @!macro executor_service_method_can_overflow_question
59
+ #
60
+ # @!method serialized?
61
+ # @!macro executor_service_method_serialized_question
62
+
63
+
64
+
65
+
66
+
67
+ # @!macro executor_service_public_api
68
+ # @!visibility private
69
+ module ExecutorService
70
+ include Concern::Logging
71
+ include Concern::Deprecation
72
+
73
+ # @!macro executor_service_method_post
74
+ def post(*args, &task)
75
+ raise NotImplementedError
76
+ end
77
+
78
+ # @!macro executor_service_method_left_shift
79
+ def <<(task)
80
+ post(&task)
81
+ self
82
+ end
83
+
84
+ # @!macro executor_service_method_can_overflow_question
85
+ #
86
+ # @note Always returns `false`
87
+ def can_overflow?
88
+ false
89
+ end
90
+
91
+ # @!macro executor_service_method_serialized_question
92
+ #
93
+ # @note Always returns `false`
94
+ def serialized?
95
+ false
96
+ end
97
+ end
98
+
99
+ # Indicates that the including `ExecutorService` guarantees
100
+ # that all operations will occur in the order they are post and that no
101
+ # two operations may occur simultaneously. This module provides no
102
+ # functionality and provides no guarantees. That is the responsibility
103
+ # of the including class. This module exists solely to allow the including
104
+ # object to be interrogated for its serialization status.
105
+ #
106
+ # @example
107
+ # class Foo
108
+ # include Concurrent::SerialExecutor
109
+ # end
110
+ #
111
+ # foo = Foo.new
112
+ #
113
+ # foo.is_a? Concurrent::ExecutorService #=> true
114
+ # foo.is_a? Concurrent::SerialExecutor #=> true
115
+ # foo.serialized? #=> true
116
+ #
117
+ # @!visibility private
118
+ module SerialExecutorService
119
+ include ExecutorService
120
+
121
+ # @!macro executor_service_method_serialized_question
122
+ #
123
+ # @note Always returns `true`
124
+ def serialized?
125
+ true
126
+ end
127
+ end
128
+
129
+
130
+
131
+
132
+
133
+ # @!macro [new] executor_service_attr_reader_fallback_policy
134
+ # @return [Symbol] The fallback policy in effect. Either `:abort`, `:discard`, or `:caller_runs`.
135
+
136
+ # @!macro [new] executor_service_method_shutdown
137
+ #
138
+ # Begin an orderly shutdown. Tasks already in the queue will be executed,
139
+ # but no new tasks will be accepted. Has no additional effect if the
140
+ # thread pool is not running.
141
+
142
+ # @!macro [new] executor_service_method_kill
143
+ #
144
+ # Begin an immediate shutdown. In-progress tasks will be allowed to
145
+ # complete but enqueued tasks will be dismissed and no new tasks
146
+ # will be accepted. Has no additional effect if the thread pool is
147
+ # not running.
148
+
149
+ # @!macro [new] executor_service_method_wait_for_termination
150
+ #
151
+ # Block until executor shutdown is complete or until `timeout` seconds have
152
+ # passed.
153
+ #
154
+ # @note Does not initiate shutdown or termination. Either `shutdown` or `kill`
155
+ # must be called before this method (or on another thread).
156
+ #
157
+ # @param [Integer] timeout the maximum number of seconds to wait for shutdown to complete
158
+ #
159
+ # @return [Boolean] `true` if shutdown complete or false on `timeout`
160
+
161
+ # @!macro [new] executor_service_method_running_question
162
+ #
163
+ # Is the executor running?
164
+ #
165
+ # @return [Boolean] `true` when running, `false` when shutting down or shutdown
166
+
167
+ # @!macro [new] executor_service_method_shuttingdown_question
168
+ #
169
+ # Is the executor shuttingdown?
170
+ #
171
+ # @return [Boolean] `true` when not running and not shutdown, else `false`
172
+
173
+ # @!macro [new] executor_service_method_shutdown_question
174
+ #
175
+ # Is the executor shutdown?
176
+ #
177
+ # @return [Boolean] `true` when shutdown, `false` when shutting down or running
178
+
179
+ # @!macro [new] executor_service_method_auto_terminate_question
180
+ #
181
+ # Is the executor auto-terminate when the application exits?
182
+ #
183
+ # @return [Boolean] `true` when auto-termination is enabled else `false`.
184
+
185
+ # @!macro [new] executor_service_method_auto_terminate_setter
186
+ #
187
+ # Set the auto-terminate behavior for this executor.
188
+ #
189
+ # @param [Boolean] value The new auto-terminate value to set for this executor.
190
+ #
191
+ # @return [Boolean] `true` when auto-termination is enabled else `false`.
192
+
193
+
194
+
195
+
196
+
197
+ # @!macro [new] abstract_executor_service_public_api
198
+ #
199
+ # @!macro executor_service_public_api
200
+ #
201
+ # @!attribute [r] fallback_policy
202
+ # @!macro executor_service_attr_reader_fallback_policy
203
+ #
204
+ # @!method shutdown
205
+ # @!macro executor_service_method_shutdown
206
+ #
207
+ # @!method kill
208
+ # @!macro executor_service_method_kill
209
+ #
210
+ # @!method wait_for_termination(timeout = nil)
211
+ # @!macro executor_service_method_wait_for_termination
212
+ #
213
+ # @!method running?
214
+ # @!macro executor_service_method_running_question
215
+ #
216
+ # @!method shuttingdown?
217
+ # @!macro executor_service_method_shuttingdown_question
218
+ #
219
+ # @!method shutdown?
220
+ # @!macro executor_service_method_shutdown_question
221
+ #
222
+ # @!method auto_terminate?
223
+ # @!macro executor_service_method_auto_terminate_question
224
+ #
225
+ # @!method auto_terminate=(value)
226
+ # @!macro executor_service_method_auto_terminate_setter
227
+
228
+
229
+
230
+
231
+
232
+ # @!macro abstract_executor_service_public_api
233
+ # @!visibility private
234
+ class AbstractExecutorService < Synchronization::Object
235
+ include ExecutorService
236
+
237
+ # The set of possible fallback policies that may be set at thread pool creation.
238
+ FALLBACK_POLICIES = [:abort, :discard, :caller_runs].freeze
239
+
240
+ # @!macro [attach] executor_service_attr_reader_fallback_policy
241
+ attr_reader :fallback_policy
242
+
243
+ # Create a new thread pool.
244
+ def initialize(*args, &block)
245
+ super(&nil)
246
+ synchronize { ns_initialize(*args, &block) }
247
+ end
248
+
249
+ # @!macro [attach] executor_service_method_shutdown
250
+ def shutdown
251
+ raise NotImplementedError
252
+ end
253
+
254
+ # @!macro [attach] executor_service_method_kill
255
+ def kill
256
+ raise NotImplementedError
257
+ end
258
+
259
+ # @!macro [attach] executor_service_method_wait_for_termination
260
+ def wait_for_termination(timeout = nil)
261
+ raise NotImplementedError
262
+ end
263
+
264
+ # @!macro [attach] executor_service_method_running_question
265
+ def running?
266
+ synchronize { ns_running? }
267
+ end
268
+
269
+ # @!macro [attach] executor_service_method_shuttingdown_question
270
+ def shuttingdown?
271
+ synchronize { ns_shuttingdown? }
272
+ end
273
+
274
+ # @!macro [attach] executor_service_method_shutdown_question
275
+ def shutdown?
276
+ synchronize { ns_shutdown? }
277
+ end
278
+
279
+ # @!macro [attach] executor_service_method_auto_terminate_question
280
+ def auto_terminate?
281
+ synchronize { ns_auto_terminate? }
282
+ end
283
+
284
+ # @!macro [attach] executor_service_method_auto_terminate_setter
285
+ def auto_terminate=(value)
286
+ synchronize { self.ns_auto_terminate = value }
287
+ end
288
+
289
+ protected
290
+
291
+ # Handler which executes the `fallback_policy` once the queue size
292
+ # reaches `max_queue`.
293
+ #
294
+ # @param [Array] args the arguments to the task which is being handled.
295
+ #
296
+ # @!visibility private
297
+ def handle_fallback(*args)
298
+ case fallback_policy
299
+ when :abort
300
+ raise RejectedExecutionError
301
+ when :discard
302
+ false
303
+ when :caller_runs
304
+ begin
305
+ yield(*args)
306
+ rescue => ex
307
+ # let it fail
308
+ log DEBUG, ex
309
+ end
310
+ true
311
+ else
312
+ fail "Unknown fallback policy #{fallback_policy}"
313
+ end
314
+ end
315
+
316
+ def execute(*args, &task)
317
+ raise NotImplementedError
318
+ end
319
+
320
+ # @!macro [attach] executor_service_method_shutdown_execution
321
+ #
322
+ # Callback method called when an orderly shutdown has completed.
323
+ # The default behavior is to signal all waiting threads.
324
+ def shutdown_execution
325
+ # do nothing
326
+ end
327
+
328
+ # @!macro [attach] executor_service_method_kill_execution
329
+ #
330
+ # Callback method called when the executor has been killed.
331
+ # The default behavior is to do nothing.
332
+ def kill_execution
333
+ # do nothing
334
+ end
335
+
336
+ protected
337
+
338
+ def ns_auto_terminate?
339
+ !!@auto_terminate
340
+ end
341
+
342
+ def ns_auto_terminate=(value)
343
+ case value
344
+ when true
345
+ AtExit.add(self) { terminate_at_exit }
346
+ @auto_terminate = true
347
+ when false
348
+ AtExit.delete(self)
349
+ @auto_terminate = false
350
+ else
351
+ raise ArgumentError
352
+ end
353
+ end
354
+
355
+ def terminate_at_exit
356
+ kill # TODO be gentle first
357
+ wait_for_termination(10)
358
+ end
359
+ end
360
+
361
+ # @!macro abstract_executor_service_public_api
362
+ # @!visibility private
363
+ class RubyExecutorService < AbstractExecutorService
364
+
365
+ def initialize(*args, &block)
366
+ super
367
+ @stop_event = Event.new
368
+ @stopped_event = Event.new
369
+ ensure_ivar_visibility!
370
+ end
371
+
372
+ def post(*args, &task)
373
+ raise ArgumentError.new('no block given') unless block_given?
374
+ synchronize do
375
+ # If the executor is shut down, reject this task
376
+ return handle_fallback(*args, &task) unless running?
377
+ execute(*args, &task)
378
+ true
379
+ end
380
+ end
381
+
382
+ def shutdown
383
+ synchronize do
384
+ break unless running?
385
+ self.ns_auto_terminate = false
386
+ stop_event.set
387
+ shutdown_execution
388
+ end
389
+ true
390
+ end
391
+
392
+ def kill
393
+ synchronize do
394
+ break if shutdown?
395
+ self.ns_auto_terminate = false
396
+ stop_event.set
397
+ kill_execution
398
+ stopped_event.set
399
+ end
400
+ true
401
+ end
402
+
403
+ def wait_for_termination(timeout = nil)
404
+ stopped_event.wait(timeout)
405
+ end
406
+
407
+ protected
408
+
409
+ attr_reader :stop_event, :stopped_event
410
+
411
+ def shutdown_execution
412
+ stopped_event.set
413
+ end
414
+
415
+ def ns_running?
416
+ !stop_event.set?
417
+ end
418
+
419
+ def ns_shuttingdown?
420
+ !(ns_running? || ns_shutdown?)
421
+ end
422
+
423
+ def ns_shutdown?
424
+ stopped_event.set?
425
+ end
426
+ end
427
+
428
+ if Concurrent.on_jruby?
429
+
430
+ # @!macro abstract_executor_service_public_api
431
+ # @!visibility private
432
+ class JavaExecutorService < AbstractExecutorService
433
+ java_import 'java.lang.Runnable'
434
+
435
+ FALLBACK_POLICY_CLASSES = {
436
+ abort: java.util.concurrent.ThreadPoolExecutor::AbortPolicy,
437
+ discard: java.util.concurrent.ThreadPoolExecutor::DiscardPolicy,
438
+ caller_runs: java.util.concurrent.ThreadPoolExecutor::CallerRunsPolicy
439
+ }.freeze
440
+ private_constant :FALLBACK_POLICY_CLASSES
441
+
442
+ def initialize(*args, &block)
443
+ super
444
+ ns_make_executor_runnable
445
+ end
446
+
447
+ def post(*args, &task)
448
+ raise ArgumentError.new('no block given') unless block_given?
449
+ return handle_fallback(*args, &task) unless running?
450
+ @executor.submit_runnable Job.new(args, task)
451
+ true
452
+ rescue Java::JavaUtilConcurrent::RejectedExecutionException
453
+ raise RejectedExecutionError
454
+ end
455
+
456
+ def wait_for_termination(timeout = nil)
457
+ if timeout.nil?
458
+ ok = @executor.awaitTermination(60, java.util.concurrent.TimeUnit::SECONDS) until ok
459
+ true
460
+ else
461
+ @executor.awaitTermination(1000 * timeout, java.util.concurrent.TimeUnit::MILLISECONDS)
462
+ end
463
+ end
464
+
465
+ def shutdown
466
+ synchronize do
467
+ self.ns_auto_terminate = false
468
+ @executor.shutdown
469
+ nil
470
+ end
471
+ end
472
+
473
+ def kill
474
+ synchronize do
475
+ self.ns_auto_terminate = false
476
+ @executor.shutdownNow
477
+ nil
478
+ end
479
+ end
480
+
481
+ protected
482
+
483
+ def ns_running?
484
+ !(ns_shuttingdown? || ns_shutdown?)
485
+ end
486
+
487
+ def ns_shuttingdown?
488
+ if @executor.respond_to? :isTerminating
489
+ @executor.isTerminating
490
+ else
491
+ false
492
+ end
493
+ end
494
+
495
+ def ns_shutdown?
496
+ @executor.isShutdown || @executor.isTerminated
497
+ end
498
+
499
+ def ns_make_executor_runnable
500
+ if !defined?(@executor.submit_runnable)
501
+ @executor.class.class_eval do
502
+ java_alias :submit_runnable, :submit, [java.lang.Runnable.java_class]
503
+ end
504
+ end
505
+ end
506
+
507
+ class Job
508
+ include Runnable
509
+ def initialize(args, block)
510
+ @args = args
511
+ @block = block
512
+ end
513
+
514
+ def run
515
+ @block.call(*@args)
516
+ end
517
+ end
518
+ private_constant :Job
519
+ end
520
+ end
521
+ end