-1

Need help in designing my executor service or use existing if these functionalities are available.

Let say, I have a total computational capacity up to 10. I'll assign each task some weightage (2,4,6). Submitted tasks should run based on weightage to use max 10. for example (5 thread of 2 weightage task, or 2,2,6 or 4,6).

yuvaraj
  • 149
  • 1
  • 1
  • 10
  • 2
    I'm not sure this is possible. Threads tend to be executed by the operating system, not by API code in the JVM. As such you'll get OS semantics for their weights, and the interpretation of those weights tend to vary *widely* by OS. For example, I think Windows is close to linear weight, whereas *nix is exponential. At best you'll end up with a poor fit to your requirements. At worst you'll break threading badly. Best just to let the threads pick their own execution and not mess with it. – markspace Mar 28 '21 at 21:25

1 Answers1

0

Maybe, it's implementation you need:

import java.util.Collection;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Queue;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.stream.Collectors;

interface WeightageTask extends Runnable {
    WeightageTask POISON = new WeightageTask() {};
    default void run() {}
    default int getWeightage() { return  0; }
}

public class WeightageExecutorService implements ExecutorService {

    private volatile boolean shutdown;
    private volatile boolean active;
    private final Thread[] threads;
    private final int numberOfThreads;
    private final Queue<Queue<WeightageTask>> taskQueues;
    private final Map<Integer, Queue<WeightageTask>> taskQueueByWeightage;
    private final Map<Integer, Integer> threadCountAllocation;

    protected WeightageExecutorService(Builder builder) {
        taskQueues = new LinkedList<>();
        taskQueueByWeightage = new HashMap<>();
        threadCountAllocation = builder.threadCountAllocation;
        numberOfThreads = threadCountAllocation.values()
                .stream()
                .reduce(0, Integer::sum);
        threads = new Thread[numberOfThreads];
        int threadIndex = 0;
        for (Integer weightage : threadCountAllocation.keySet()) {
            final int threadCount = threadCountAllocation.get(weightage);
            for(int i = 0 ; i < threadCount ; ++i) {
                threads[threadIndex] = new Thread(() -> {
                    while (true) {
                        try {
                            WeightageTask task = takeTask();
                            if (task == WeightageTask.POISON) {
                                break;
                            }
                            task.run();
                        }
                        catch (Throwable e) {
                            e.printStackTrace();
                        }
                    }
                });
                threads[threadIndex].setName("weightage-thread-" + weightage + "-" + (i + 1));
                ++ threadIndex;
            }
        }
        for(Thread thread : threads) {
            thread.start();
        }
    }

    public void execute(WeightageTask task) {
        final Integer weightage = task.getWeightage();
        if(task != WeightageTask.POISON && !threadCountAllocation.containsKey(weightage)) {
            throw new IllegalArgumentException("there is no allocated thread for weightage: " + weightage);
        }
        synchronized (taskQueues) {
            final Queue<WeightageTask> taskQueue = taskQueueByWeightage
                    .computeIfAbsent(weightage, k -> new LinkedList<>());
            final boolean addToQueue = taskQueue.isEmpty();
            taskQueue.offer(task);
            if (addToQueue) {
                taskQueues.offer(taskQueue);
            }
            active = true;
            taskQueues.notifyAll();
        }
    }

    @Override
    public void shutdown() {
        for(int i = 0 ; i < numberOfThreads ; ++i) {
            execute(WeightageTask.POISON);
        }
        shutdown = true;
    }

    @Override
    public List<Runnable> shutdownNow() {
        for(Thread thread : threads) {
            thread.interrupt();
        }
        shutdown = true;
        return taskQueues.stream()
                .flatMap(Queue::stream)
                .collect(Collectors.toList());
    }

    @Override
    public boolean isShutdown() {
        return shutdown;
    }

    @Override
    public boolean isTerminated() {
        return shutdown;
    }

    private WeightageTask takeTask() throws InterruptedException {
        synchronized (taskQueues) {
            while (!active) {
                taskQueues.wait();
            }
            final Queue<WeightageTask> taskQueue = taskQueues.poll();
            final WeightageTask task = taskQueue.poll();
            if (!taskQueue.isEmpty()) {
                taskQueues.offer(taskQueue);
            }
            active = !taskQueues.isEmpty();
            return task;
        }
    }

    public static Builder builder() {
        return new Builder();
    }

    @Override
    public void execute(Runnable command) {
        execute((WeightageTask) command);
    }

    @Override
    public boolean awaitTermination(long timeout, TimeUnit unit) throws InterruptedException {
        return false;
    }

    @Override
    public <T> Future<T> submit(Callable<T> task) {
        throw new UnsupportedOperationException("let implement by yourself");
    }

    @Override
    public <T> Future<T> submit(Runnable task, T result) {
        throw new UnsupportedOperationException("let implement by yourself");
    }

    @Override
    public Future<?> submit(Runnable task) {
        throw new UnsupportedOperationException("let implement by yourself");
    }

    @Override
    public <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks) throws InterruptedException {
        throw new UnsupportedOperationException("let implement by yourself");
    }

    @Override
    public <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks, long timeout, TimeUnit unit)
            throws InterruptedException {
        throw new UnsupportedOperationException("let implement by yourself");
    }

    @Override
    public <T> T invokeAny(Collection<? extends Callable<T>> tasks)
            throws InterruptedException, ExecutionException {
        throw new UnsupportedOperationException("let implement by yourself");
    }

    @Override
    public <T> T invokeAny(Collection<? extends Callable<T>> tasks, long timeout, TimeUnit unit)
            throws InterruptedException, ExecutionException, TimeoutException {
        throw new UnsupportedOperationException("let implement by yourself");
    }

    public static class Builder {
        private final Map<Integer, Integer> threadCountAllocation = new HashMap<>();

        public Builder allocateThreads(int weightage, int threadCount) {
            this.threadCountAllocation.put(weightage, threadCount);
            return this;
        }

        public WeightageExecutorService build() {
            return new WeightageExecutorService(this);
        }
    }

    public static void main(String[] args) throws Exception {
        ExecutorService executorService = WeightageExecutorService.builder()
                    .allocateThreads(2, 4)
                    .allocateThreads(3, 6)
                    .build();
        executorService.execute(new WeightageTask() {
            @Override
            public void run() {
                System.out.print("Hello ");
            }

            @Override
            public int getWeightage() {
                return 2;
            }
        });
        executorService.execute(new WeightageTask() {
            @Override
            public void run() {
                System.out.print("World ");
            }

            @Override
            public int getWeightage() {
                return 3;
            }
        });
        Thread.sleep(1000);
        executorService.shutdown();
    }

}
dung ta van
  • 988
  • 8
  • 13