How do I implement task prioritization using an ExecutorService in Java 5?

前端 未结 6 1929
粉色の甜心
粉色の甜心 2020-11-27 03:51

I am implementing a thread pooling mechanism in which I\'d like to execute tasks of varying priorities. I\'d like to have a nice mechanism whereby I can submit a high prior

6条回答
  •  不知归路
    2020-11-27 04:06

    My solution preserves submition order of tasks for same priorities. It's an improvement of this answer

    Task execution order is based on:

    1. Priority
    2. Submit order (within same priority)

    Tester class:

    public class Main {
    
        public static void main(String[] args) throws InterruptedException, ExecutionException {
    
            ExecutorService executorService = PriorityExecutors.newFixedThreadPool(1);
    
            //Priority=0
            executorService.submit(newCallable("A1", 200));     //Defaults to priority=0 
            executorService.execute(newRunnable("A2", 200));    //Defaults to priority=0
            executorService.submit(PriorityCallable.of(newCallable("A3", 200), 0));
            executorService.submit(PriorityRunnable.of(newRunnable("A4", 200), 0));
            executorService.execute(PriorityRunnable.of(newRunnable("A5", 200), 0));
            executorService.submit(PriorityRunnable.of(newRunnable("A6", 200), 0));
            executorService.execute(PriorityRunnable.of(newRunnable("A7", 200), 0));
            executorService.execute(PriorityRunnable.of(newRunnable("A8", 200), 0));
    
            //Priority=1
            executorService.submit(PriorityRunnable.of(newRunnable("B1", 200), 1));
            executorService.submit(PriorityRunnable.of(newRunnable("B2", 200), 1));
            executorService.submit(PriorityCallable.of(newCallable("B3", 200), 1));
            executorService.execute(PriorityRunnable.of(newRunnable("B4", 200), 1));
            executorService.submit(PriorityRunnable.of(newRunnable("B5", 200), 1));
    
            executorService.shutdown();
    
        }
    
        private static Runnable newRunnable(String name, int delay) {
            return new Runnable() {
                @Override
                public void run() {
                    System.out.println(name);
                    sleep(delay);
                }
            };
        }
    
        private static Callable newCallable(String name, int delay) {
            return new Callable() {
                @Override
                public Integer call() throws Exception {
                    System.out.println(name);
                    sleep(delay);
                    return 10;
                }
            };
        }
    
        private static void sleep(long millis) {
            try {
                Thread.sleep(millis);
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
                throw new RuntimeException(e);
            }
        }
    
    }
    

    Result:

    A1 B1 B2 B3 B4 B5 A2 A3 A4 A5 A6 A7 A8

    First task is A1 because there were no higher priority in the queue when it was inserted. B tasks are 1 priority so executed earlier, A tasks are 0 priority so executed later, but execution order is follows submition order: B1, B2, B3, ... A2, A3, A4 ...

    The solution:

    public class PriorityExecutors {
    
        public static ExecutorService newFixedThreadPool(int nThreads) {
            return new PriorityExecutor(nThreads, nThreads, 0L, TimeUnit.MILLISECONDS);
        }
    
        private static class PriorityExecutor extends ThreadPoolExecutor {
            private static final int DEFAULT_PRIORITY = 0;
            private static AtomicLong instanceCounter = new AtomicLong();
    
            @SuppressWarnings({"unchecked"})
            public PriorityExecutor(int corePoolSize, int maximumPoolSize,
                    long keepAliveTime, TimeUnit unit) {
                super(corePoolSize, maximumPoolSize, keepAliveTime, unit, (BlockingQueue) new PriorityBlockingQueue(10,
                        ComparableTask.comparatorByPriorityAndSequentialOrder()));
            }
    
            @Override
            public void execute(Runnable command) {
                // If this is ugly then delegator pattern needed
                if (command instanceof ComparableTask) //Already wrapped
                    super.execute(command);
                else {
                    super.execute(newComparableRunnableFor(command));
                }
            }
    
            private Runnable newComparableRunnableFor(Runnable runnable) {
                return new ComparableRunnable(ensurePriorityRunnable(runnable));
            }
    
            @Override
            protected  RunnableFuture newTaskFor(Callable callable) {
                return new ComparableFutureTask<>(ensurePriorityCallable(callable));
            }
    
            @Override
            protected  RunnableFuture newTaskFor(Runnable runnable, T value) {
                return new ComparableFutureTask<>(ensurePriorityRunnable(runnable), value);
            }
    
            private  PriorityCallable ensurePriorityCallable(Callable callable) {
                return (callable instanceof PriorityCallable) ? (PriorityCallable) callable
                        : PriorityCallable.of(callable, DEFAULT_PRIORITY);
            }
    
            private PriorityRunnable ensurePriorityRunnable(Runnable runnable) {
                return (runnable instanceof PriorityRunnable) ? (PriorityRunnable) runnable
                        : PriorityRunnable.of(runnable, DEFAULT_PRIORITY);
            }
    
            private class ComparableFutureTask extends FutureTask implements ComparableTask {
                private Long sequentialOrder = instanceCounter.getAndIncrement();
                private HasPriority hasPriority;
    
                public ComparableFutureTask(PriorityCallable priorityCallable) {
                    super(priorityCallable);
                    this.hasPriority = priorityCallable;
                }
    
                public ComparableFutureTask(PriorityRunnable priorityRunnable, T result) {
                    super(priorityRunnable, result);
                    this.hasPriority = priorityRunnable;
                }
    
                @Override
                public long getInstanceCount() {
                    return sequentialOrder;
                }
    
                @Override
                public int getPriority() {
                    return hasPriority.getPriority();
                }
            }
    
            private static class ComparableRunnable implements Runnable, ComparableTask {
                private Long instanceCount = instanceCounter.getAndIncrement();
                private HasPriority hasPriority;
                private Runnable runnable;
    
                public ComparableRunnable(PriorityRunnable priorityRunnable) {
                    this.runnable = priorityRunnable;
                    this.hasPriority = priorityRunnable;
                }
    
                @Override
                public void run() {
                    runnable.run();
                }
    
                @Override
                public int getPriority() {
                    return hasPriority.getPriority();
                }
    
                @Override
                public long getInstanceCount() {
                    return instanceCount;
                }
            }
    
            private interface ComparableTask extends Runnable {
                int getPriority();
    
                long getInstanceCount();
    
                public static Comparator comparatorByPriorityAndSequentialOrder() {
                    return (o1, o2) -> {
                        int priorityResult = o2.getPriority() - o1.getPriority();
                        return priorityResult != 0 ? priorityResult
                                : (int) (o1.getInstanceCount() - o2.getInstanceCount());
                    };
                }
    
            }
    
        }
    
        private static interface HasPriority {
            int getPriority();
        }
    
        public interface PriorityCallable extends Callable, HasPriority {
    
            public static  PriorityCallable of(Callable callable, int priority) {
                return new PriorityCallable() {
                    @Override
                    public V call() throws Exception {
                        return callable.call();
                    }
    
                    @Override
                    public int getPriority() {
                        return priority;
                    }
                };
            }
        }
    
        public interface PriorityRunnable extends Runnable, HasPriority {
    
            public static PriorityRunnable of(Runnable runnable, int priority) {
                return new PriorityRunnable() {
                    @Override
                    public void run() {
                        runnable.run();
                    }
    
                    @Override
                    public int getPriority() {
                        return priority;
                    }
                };
            }
        }
    
    }
    

提交回复
热议问题