concurrent-ruby 0.8.0.pre2-java → 0.9.0-java

Sign up to get free protection for your applications and to get access to all the features.
Files changed (145) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +114 -3
  3. data/README.md +111 -55
  4. data/lib/concurrent.rb +90 -14
  5. data/lib/concurrent/async.rb +143 -51
  6. data/lib/concurrent/atom.rb +131 -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 +34 -3
  19. data/lib/concurrent/atomic_reference/jruby.rb +6 -3
  20. data/lib/concurrent/atomic_reference/mutex_atomic.rb +17 -39
  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 +34 -0
  29. data/lib/concurrent/concern/dereferenceable.rb +88 -0
  30. data/lib/concurrent/concern/logging.rb +27 -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 +234 -109
  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 +19 -7
  38. data/lib/concurrent/exchanger.rb +25 -1
  39. data/lib/concurrent/executor/cached_thread_pool.rb +51 -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 +196 -23
  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_single_thread_executor.rb +17 -16
  46. data/lib/concurrent/executor/java_thread_pool_executor.rb +55 -102
  47. data/lib/concurrent/executor/ruby_single_thread_executor.rb +14 -16
  48. data/lib/concurrent/executor/ruby_thread_pool_executor.rb +250 -166
  49. data/lib/concurrent/executor/safe_task_executor.rb +5 -4
  50. data/lib/concurrent/executor/serialized_execution.rb +22 -18
  51. data/lib/concurrent/executor/{per_thread_executor.rb → simple_executor_service.rb} +29 -20
  52. data/lib/concurrent/executor/single_thread_executor.rb +32 -21
  53. data/lib/concurrent/executor/thread_pool_executor.rb +73 -60
  54. data/lib/concurrent/executor/timer_set.rb +96 -84
  55. data/lib/concurrent/executors.rb +1 -1
  56. data/lib/concurrent/future.rb +71 -38
  57. data/lib/concurrent/immutable_struct.rb +89 -0
  58. data/lib/concurrent/ivar.rb +152 -60
  59. data/lib/concurrent/lazy_register.rb +40 -20
  60. data/lib/concurrent/maybe.rb +226 -0
  61. data/lib/concurrent/mutable_struct.rb +227 -0
  62. data/lib/concurrent/mvar.rb +44 -43
  63. data/lib/concurrent/promise.rb +229 -136
  64. data/lib/concurrent/scheduled_task.rb +341 -43
  65. data/lib/concurrent/settable_struct.rb +127 -0
  66. data/lib/concurrent/synchronization.rb +17 -0
  67. data/lib/concurrent/synchronization/abstract_object.rb +163 -0
  68. data/lib/concurrent/synchronization/abstract_struct.rb +158 -0
  69. data/lib/concurrent/synchronization/condition.rb +53 -0
  70. data/lib/concurrent/synchronization/java_object.rb +34 -0
  71. data/lib/concurrent/synchronization/lock.rb +32 -0
  72. data/lib/concurrent/synchronization/monitor_object.rb +26 -0
  73. data/lib/concurrent/synchronization/mutex_object.rb +43 -0
  74. data/lib/concurrent/synchronization/object.rb +78 -0
  75. data/lib/concurrent/synchronization/rbx_object.rb +75 -0
  76. data/lib/concurrent/timer_task.rb +92 -103
  77. data/lib/concurrent/tvar.rb +42 -38
  78. data/lib/concurrent/utilities.rb +3 -1
  79. data/lib/concurrent/utility/at_exit.rb +97 -0
  80. data/lib/concurrent/utility/engine.rb +44 -0
  81. data/lib/concurrent/utility/monotonic_time.rb +59 -0
  82. data/lib/concurrent/utility/native_extension_loader.rb +56 -0
  83. data/lib/concurrent/utility/processor_counter.rb +156 -0
  84. data/lib/concurrent/utility/timeout.rb +18 -14
  85. data/lib/concurrent/utility/timer.rb +11 -6
  86. data/lib/concurrent/version.rb +2 -1
  87. data/lib/concurrent_ruby.rb +1 -0
  88. data/lib/concurrent_ruby_ext.jar +0 -0
  89. metadata +46 -66
  90. data/lib/concurrent/actor.rb +0 -103
  91. data/lib/concurrent/actor/behaviour.rb +0 -70
  92. data/lib/concurrent/actor/behaviour/abstract.rb +0 -48
  93. data/lib/concurrent/actor/behaviour/awaits.rb +0 -21
  94. data/lib/concurrent/actor/behaviour/buffer.rb +0 -54
  95. data/lib/concurrent/actor/behaviour/errors_on_unknown_message.rb +0 -12
  96. data/lib/concurrent/actor/behaviour/executes_context.rb +0 -18
  97. data/lib/concurrent/actor/behaviour/linking.rb +0 -45
  98. data/lib/concurrent/actor/behaviour/pausing.rb +0 -77
  99. data/lib/concurrent/actor/behaviour/removes_child.rb +0 -16
  100. data/lib/concurrent/actor/behaviour/sets_results.rb +0 -36
  101. data/lib/concurrent/actor/behaviour/supervised.rb +0 -59
  102. data/lib/concurrent/actor/behaviour/supervising.rb +0 -34
  103. data/lib/concurrent/actor/behaviour/terminates_children.rb +0 -13
  104. data/lib/concurrent/actor/behaviour/termination.rb +0 -54
  105. data/lib/concurrent/actor/context.rb +0 -154
  106. data/lib/concurrent/actor/core.rb +0 -217
  107. data/lib/concurrent/actor/default_dead_letter_handler.rb +0 -9
  108. data/lib/concurrent/actor/envelope.rb +0 -41
  109. data/lib/concurrent/actor/errors.rb +0 -27
  110. data/lib/concurrent/actor/internal_delegations.rb +0 -49
  111. data/lib/concurrent/actor/public_delegations.rb +0 -40
  112. data/lib/concurrent/actor/reference.rb +0 -81
  113. data/lib/concurrent/actor/root.rb +0 -37
  114. data/lib/concurrent/actor/type_check.rb +0 -48
  115. data/lib/concurrent/actor/utils.rb +0 -10
  116. data/lib/concurrent/actor/utils/ad_hoc.rb +0 -21
  117. data/lib/concurrent/actor/utils/balancer.rb +0 -42
  118. data/lib/concurrent/actor/utils/broadcast.rb +0 -52
  119. data/lib/concurrent/actor/utils/pool.rb +0 -59
  120. data/lib/concurrent/actress.rb +0 -3
  121. data/lib/concurrent/agent.rb +0 -209
  122. data/lib/concurrent/atomic.rb +0 -92
  123. data/lib/concurrent/atomic/copy_on_notify_observer_set.rb +0 -118
  124. data/lib/concurrent/atomic/copy_on_write_observer_set.rb +0 -117
  125. data/lib/concurrent/atomic/synchronization.rb +0 -51
  126. data/lib/concurrent/channel/buffered_channel.rb +0 -85
  127. data/lib/concurrent/channel/channel.rb +0 -41
  128. data/lib/concurrent/channel/unbuffered_channel.rb +0 -35
  129. data/lib/concurrent/channel/waitable_list.rb +0 -40
  130. data/lib/concurrent/channels.rb +0 -5
  131. data/lib/concurrent/collection/blocking_ring_buffer.rb +0 -71
  132. data/lib/concurrent/collection/ring_buffer.rb +0 -59
  133. data/lib/concurrent/collections.rb +0 -3
  134. data/lib/concurrent/dereferenceable.rb +0 -108
  135. data/lib/concurrent/executor/java_cached_thread_pool.rb +0 -32
  136. data/lib/concurrent/executor/java_fixed_thread_pool.rb +0 -31
  137. data/lib/concurrent/executor/ruby_cached_thread_pool.rb +0 -29
  138. data/lib/concurrent/executor/ruby_fixed_thread_pool.rb +0 -32
  139. data/lib/concurrent/executor/ruby_thread_pool_worker.rb +0 -73
  140. data/lib/concurrent/logging.rb +0 -20
  141. data/lib/concurrent/obligation.rb +0 -171
  142. data/lib/concurrent/observable.rb +0 -73
  143. data/lib/concurrent/options_parser.rb +0 -48
  144. data/lib/concurrent/utility/processor_count.rb +0 -152
  145. 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