# Since java.util.concurrent.ThreadPoolExecutor.submit has multiple signatures, # we force JRuby to use the one signature we want, and stop a warning from being emitted. java.util.concurrent.ThreadPoolExecutor.class_eval do java_alias :submit, :submit, [java.util.concurrent.Callable.java_class] end # Start the executor service. Note that this won't create any threads right away, # but will create new threads as the jobs are submitted, until it gets to 5 threads. # Then it will reuse the threads. executor = java.util.concurrent.Executors.new_fixed_thread_pool 5 # Submit jobs, get back java.util.concurrent.FutureTask objects. tasks = [1, 3, 4, 6].map do |s| executor.submit do # run database query on shard s # return query result end end # We get control back immediately, while the queries are being executed by the thread pool. # We can do some other things here while the queries run. # Get the results of all queries and combine them into an array. FutureTask.get will wait # for the task to complete if it's not completed yet, so it's safe to call this right away. # If for some reason we wanted to check if a task is complete, we can call t.done? . results = tasks.map do |t| begin t.get rescue java.util.concurrent.ExecutionException => e # Convert the exception to one actually thrown inside the task. raise e.cause.exception end end # Shut down the thread pool. executor.shutdown_now
Tuesday, May 14, 2013
Sometimes you need to execute long running tasks (like database queries on multiple shards) concurrently. JRuby can easily make use of Java's built-in Executor class for this purpose.