All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.jenetics.internal.util.Concurrency Maven / Gradle / Ivy

There is a newer version: 3.6.0
Show newest version
/*
 * Java Genetic Algorithm Library (jenetics-3.1.0).
 * Copyright (c) 2007-2015 Franz Wilhelmstötter
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 * Author:
 *    Franz Wilhelmstötter ([email protected])
 */
package org.jenetics.internal.util;

import static java.util.Objects.requireNonNull;

import java.util.List;
import java.util.concurrent.CancellationException;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.ForkJoinTask;
import java.util.concurrent.Future;
import java.util.concurrent.FutureTask;

import org.jenetics.internal.collection.Stack;

/**
 * @author Franz Wilhelmstötter
 * @version 2.0
 * @since 2.0
 */
public abstract class Concurrency implements Executor, AutoCloseable {

	public static final int CORES = Runtime.getRuntime().availableProcessors();

	public static final Concurrency SERIAL_EXECUTOR = new SerialConcurrency();

	public abstract void execute(final List runnables);

	@Override
	public abstract void close();

	/**
	 * Return the underlying {@code Executor}, which is used for performing the
	 * actual task execution.
	 *
	 * @return the underlying {@code Executor} object
	 */
	public Executor getInnerExecutor() {
		return this;
	}

	/**
	 * Return an new Concurrency object from the given executor.
	 *
	 * @param executor the underlying Executor
	 * @return a new Concurrency object
	 */
	public static Concurrency with(final Executor executor) {
		if (executor instanceof ForkJoinPool) {
			return new ForkJoinPoolConcurrency((ForkJoinPool)executor);
		} else if (executor instanceof ExecutorService) {
			return new ExecutorServiceConcurrency((ExecutorService)executor);
		} else if (executor == SERIAL_EXECUTOR) {
			return SERIAL_EXECUTOR;
		} else {
			return new ExecutorConcurrency(executor);
		}
	}

	/**
	 * Return a new Concurrency object using the common ForkJoinPool.
	 *
	 * @return a new Concurrency object using the new ForkJoinPool
	 */
	public static Concurrency withCommonPool() {
		return with(ForkJoinPool.commonPool());
	}


	/**
	 * This Concurrency uses a ForkJoinPool.
	 */
	private static final class ForkJoinPoolConcurrency extends Concurrency {
		private final Stack> _tasks = new Stack<>();
		private final ForkJoinPool _pool;

		ForkJoinPoolConcurrency(final ForkJoinPool pool) {
			_pool = requireNonNull(pool);
		}

		@Override
		public void execute(final Runnable runnable) {
			_tasks.push(_pool.submit(runnable));
		}

		@Override
		public void execute(final List runnables) {
			_tasks.push(_pool.submit(new RunnablesAction(runnables)));
		}

		@Override
		public Executor getInnerExecutor() {
			return _pool;
		}

		@Override
		public void close() {
			for (ForkJoinTask t = _tasks.pop(); t != null; t = _tasks.pop()) {
				t.join();
			}
		}
	}

	/**
	 * This Concurrency uses an ExecutorService.
	 */
	private static final class ExecutorServiceConcurrency extends Concurrency {
		private final Stack> _futures = new Stack<>();
		private final ExecutorService _service;

		ExecutorServiceConcurrency(final ExecutorService service) {
			_service = requireNonNull(service);
		}

		@Override
		public void execute(final Runnable command) {
			_futures.push(_service.submit(command));
		}

		@Override
		public void execute(final List runnables) {
			final int[] parts = partition(runnables.size(), CORES + 1);
			for (int i = 0; i < parts.length - 1; ++i) {
				execute(new RunnablesRunnable(runnables, parts[i], parts[i + 1]));
			}
		}

		@Override
		public Executor getInnerExecutor() {
			return _service;
		}

		@Override
		public void close() {
			try {
				for (Future f = _futures.pop(); f != null; f = _futures.pop()) {
					f.get();
				}
			} catch (InterruptedException|ExecutionException e) {
				throw new CancellationException(e.getMessage());
			}
		}
	}

	/**
	 * This Concurrency uses an Executor.
	 */
	private static final class ExecutorConcurrency extends Concurrency {
		private final Stack> _tasks = new Stack<>();
		private final Executor _executor;

		ExecutorConcurrency(final Executor executor) {
			_executor = requireNonNull(executor);
		}

		@Override
		public void execute(final Runnable command) {
			final FutureTask task = new FutureTask<>(command, null);
			_tasks.push(task);
			_executor.execute(task);
		}

		@Override
		public void execute(final List runnables) {
			final int[] parts = partition(runnables.size(), CORES + 1);
			for (int i = 0; i < parts.length - 1; ++i) {
				execute(new RunnablesRunnable(runnables, parts[i], parts[i + 1]));
			}
		}

		@Override
		public void close() {
			try {
				for (FutureTask t = _tasks.pop(); t != null; t = _tasks.pop()) {
					t.get();
				}
			} catch (InterruptedException|ExecutionException e) {
				throw new CancellationException(e.getMessage());
			}
		}
	}

	/**
	 * This Concurrency executes the runnables within the main thread.
	 */
	private static final class SerialConcurrency extends Concurrency {

		@Override
		public void execute(final Runnable command) {
			command.run();
		}

		@Override
		public void execute(final List runnables) {
			for (final Runnable runnable : runnables) {
				runnable.run();
			}
		}

		@Override
		public void close() {
		}
	}


	/**
	 * Return a array with the indexes of the partitions of an array with the
	 * given size. The length of the returned array is {@code min(size, prts) + 1}.
	 * 

* Some examples: *

	 * 	 partition(10, 3): [0, 3, 6, 10]
	 * 	 partition(15, 6): [0, 2, 4, 6, 9, 12, 15]
	 * 	 partition(5, 10): [0, 1, 2, 3, 4, 5]
	 * 
* * The following examples prints the start index (inclusive) and the end * index (exclusive) of the {@code partition(15, 6)}. *
{@code
	 * int[] parts = partition(15, 6);
	 * for (int i = 0; i < parts.length - 1; ++i) {
	 *     System.out.println(i + ": " + parts[i] + "\t" + parts[i + 1]);
	 * }
	 * }
*
	 * 	 0: 0 	2
	 * 	 1: 2 	4
	 * 	 2: 4 	6
	 * 	 3: 6 	9
	 * 	 4: 9 	12
	 * 	 5: 12	15
	 * 
* * This example shows how this can be used in an concurrent environment: *
{@code
	 * try (final Concurrency c = Concurrency.start()) {
	 *     final int[] parts = arrays.partition(population.size(), _maxThreads);
	 *
	 *     for (int i = 0; i < parts.length - 1; ++i) {
	 *         final int part = i;
	 *         c.execute(new Runnable() { @Override public void run() {
	 *             for (int j = parts[part + 1]; --j <= parts[part];) {
	 *                 population.get(j).evaluate();
	 *             }
	 *         }});
	 *     }
	 * }
	 * }
* * @param size the size of the array to partition. * @param parts the number of parts the (virtual) array should be partitioned. * @return the partition array with the length of {@code min(size, parts) + 1}. * @throws IllegalArgumentException if {@code size} or {@code p} is less than one. */ private static int[] partition(final int size, final int parts) { if (size < 1) { throw new IllegalArgumentException( "Size must greater than zero: " + size ); } if (parts < 1) { throw new IllegalArgumentException( "Number of partitions must greater than zero: " + parts ); } final int pts = Math.min(size, parts); final int[] partition = new int[pts + 1]; final int bulk = size/pts; final int rest = size%pts; assert ((bulk*pts + rest) == size); for (int i = 0, n = pts - rest; i < n; ++i) { partition[i] = i*bulk; } for (int i = 0, n = rest + 1; i < n; ++i) { partition[pts - rest + i] = (pts - rest)*bulk + i*(bulk + 1); } return partition; } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy