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

com.softicar.platform.common.core.thread.runner.LimitedThreadRunner Maven / Gradle / Ivy

Go to download

The SoftiCAR Platform is a lightweight, Java-based library to create interactive business web applications.

There is a newer version: 50.0.0
Show newest version
package com.softicar.platform.common.core.thread.runner;

import com.softicar.platform.common.core.thread.IRunnableThread;
import com.softicar.platform.common.core.thread.RunnableThread;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Deque;
import java.util.List;
import java.util.Objects;
import java.util.function.Function;

/**
 * Runs queued {@link Runnable}s, employing a limited number of concurrent
 * {@link Thread}s.
 *
 * @author Alexander Schmidt
 */
public class LimitedThreadRunner implements ILimitedThreadRunner {

	private final int limit;
	private final Deque runnables;
	private final List> startedThreads;
	private Function threadFactory;

	/**
	 * Creates a {@link LimitedThreadRunner}.
	 *
	 * @param limit
	 *            the maximum number of {@link Thread}s that will be run
	 *            concurrently, at any given point in time; clamped to [1,
	 *            {@link Integer#MAX_VALUE}]
	 */
	public LimitedThreadRunner(int limit) {

		this.limit = Math.min(Math.max(1, limit), Integer.MAX_VALUE);
		this.runnables = new ArrayDeque<>();
		this.startedThreads = new ArrayList<>();
		this.threadFactory = Thread::new;
	}

	/**
	 * Calls {@link #addRunnable(Runnable)} for all given {@link Runnable}
	 * objects.
	 *
	 * @param runnables
	 *            the {@link Runnable}s to be added (never null)
	 * @return this
	 */
	@SafeVarargs
	public final LimitedThreadRunner addRunnables(R...runnables) {

		Arrays.asList(runnables).forEach(this::addRunnable);
		return this;
	}

	@Override
	public void addRunnable(R runnable) {

		runnables.add(Objects.requireNonNull(runnable));
	}

	@Override
	public Collection> startThreads() {

		Collection> threads = new ArrayList<>();
		while (hasAvailableSlots() && !runnables.isEmpty()) {
			threads.add(startNextRunnable());
		}
		return threads;
	}

	@Override
	public boolean hasAvailableSlots() {

		return getAvailableSlots() > 0;
	}

	@Override
	public boolean isFinished() {

		return getStartedThreadCount() == 0 && runnables.isEmpty();
	}

	/**
	 * Allows for customization of the factory that creates {@link Thread}s from
	 * {@link Runnable}s.
	 * 

* The factory must never return null. * * @param threadFactory * creates a {@link Thread} from a {@link Runnable} (never null) * @return this {@link LimitedThreadRunner} */ public LimitedThreadRunner setThreadFactory(Function threadFactory) { this.threadFactory = Objects.requireNonNull(threadFactory); return this; } protected int getStartedThreadsCount() { return startedThreads.size(); } protected int getQueueRunnablesCount() { return runnables.size(); } private int getAvailableSlots() { return Math.max(0, limit - getStartedThreadCount()); } private int getStartedThreadCount() { removeTerminatedThreads(); return startedThreads.size(); } private RunnableThread startNextRunnable() { R nextRunnable = runnables.pollFirst(); if (nextRunnable != null) { return startRunnableThread(nextRunnable); } else { return null; } } private RunnableThread startRunnableThread(R runnable) { var runnableThread = new RunnableThread<>(runnable, threadFactory); startedThreads.add(runnableThread); runnableThread.start(); return runnableThread; } private void removeTerminatedThreads() { var iterator = startedThreads.iterator(); while (iterator.hasNext()) { RunnableThread runnableThread = iterator.next(); if (runnableThread.isTerminated()) { iterator.remove(); } } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy