Java执行者:如何设置任务优先级?

Java执行者:如何设置任务优先级?,java,multithreading,concurrency,executor,thread-priority,Java,Multithreading,Concurrency,Executor,Thread Priority,是否有可能为执行者执行的任务设置优先级?我在JCIP中找到了一些关于这是可能的声明,但我找不到任何示例,也找不到文档中的任何相关内容 来自JCIP: 执行策略指定 任务的“什么、在哪里、何时和如何” 执行,包括: 任务应按什么顺序执行(先进先出、后进先出、优先级顺序) UPD:我意识到我问的并不是我想问的。我真正想要的是: 如何在executors框架中使用/模拟设置线程优先级(即thread.setPriority()) 目前唯一的具体实现是和 应该使用构造函数创建实例,而不是使用实用

是否有可能为执行者执行的任务设置优先级?我在JCIP中找到了一些关于这是可能的声明,但我找不到任何示例,也找不到文档中的任何相关内容

来自JCIP:

执行策略指定 任务的“什么、在哪里、何时和如何” 执行,包括:

  • 任务应按什么顺序执行(先进先出、后进先出、优先级顺序)
UPD:我意识到我问的并不是我想问的。我真正想要的是:


如何在executors框架中使用/模拟设置线程优先级(即
thread.setPriority()

目前唯一的具体实现是和

应该使用构造函数创建实例,而不是使用实用程序/工厂类

您可以向ThreadPoolExecutor的构造函数传递


BlockingQueue的一种实现,允许您将比较器传递给构造函数,这样您就可以决定执行顺序。

您可以将ThreadPoolExecutor与优先级阻塞队列一起使用

请注意,setPriority(..)通常在Linux下不起作用。有关详细信息,请参见以下链接:

您可以在
ThreadPoolExecutor
构造函数(或
Executors
工厂方法)中指定。这允许您为执行器提供具有给定线程优先级的线程


要为不同的作业获取不同的线程优先级,您需要将它们发送给具有不同线程工厂的执行器。

这里的想法是在执行器中使用PriorityBlockingQueue。为此:

  • 创建一个比较工具,比较我们的未来
  • 为未来创建一个代理以保持优先级
  • 重写“newTaskFor”,以便在代理中包装每个未来
首先,你需要优先考虑你的未来:

    class PriorityFuture<T> implements RunnableFuture<T> {

    private RunnableFuture<T> src;
    private int priority;

    public PriorityFuture(RunnableFuture<T> other, int priority) {
        this.src = other;
        this.priority = priority;
    }

    public int getPriority() {
        return priority;
    }

    public boolean cancel(boolean mayInterruptIfRunning) {
        return src.cancel(mayInterruptIfRunning);
    }

    public boolean isCancelled() {
        return src.isCancelled();
    }

    public boolean isDone() {
        return src.isDone();
    }

    public T get() throws InterruptedException, ExecutionException {
        return src.get();
    }

    public T get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException {
        return src.get();
    }

    public void run() {
        src.run();
    }
}

我只想在这次讨论中加入我的一点贡献。我实现这一点是为了一个非常特殊的目的,即能够在我需要的时候显式地将阻塞队列(在本例中为LinkedBlockingDeque)置于执行者的阻塞队列的前端,而不必处理优先级(这可能导致死锁,而且无论如何都是固定的)

我用它来管理(在Android应用程序中)我必须下载在长列表视图中显示的许多图像的情况。每当用户快速向下滚动时,executor队列就会收到大量的图像下载请求:通过将最新的图像移动到队列顶部,我在加载屏幕上的图像时获得了更好的性能,延迟了以后可能需要的图像的下载。请注意,我使用一个内部并发映射键(可以像图像URL字符串一样简单)将任务添加到执行器中,以便稍后检索它们以进行重新排序

有很多其他的方法可以做到这一点,也许它过于复杂了,但它工作得很好,而且他的Android SDK中的Facebook也在自己的工作线程队列中做着类似的事情


请随意查看代码并给我一些建议,它在Android项目中,但是去掉一些日志和注释会使该类成为纯Java 6。

您可以实现自己的ThreadFactory并在ThreadPoolExecutor中设置它,如下所示:

class LenthyJob implements Callable<Long> {
    private int priority;

    public LenthyJob(int priority) {
        this.priority = priority;
    }

    public Long call() throws Exception {
        System.out.println("Executing: " + priority);
        long num = 1000000;
        for (int i = 0; i < 1000000; i++) {
            num *= Math.random() * 1000;
            num /= Math.random() * 1000;
            if (num == 0)
                num = 1000000;
        }
        return num;
    }

    public int getPriority() {
        return priority;
    }
}
ThreadPoolExecutor threadPool = new ThreadPoolExecutor(1, numOfWorkerThreads, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>());
threadPool.setThreadFactory(new OpJobThreadFactory(Thread.NORM_PRIORITY-2));

如果这只是一个试图偏袒一个线程而不是保证任何订单的情况。 在传入的可调用线程上,在call()方法的开头设置线程优先级:


仍然依赖于底层实现来尊重线程优先级,尽管要走的路是+1优先级阻塞队列。您可以实现一个比较器,或者使任务本身具有可比性;答案就是答案。评论不是答案。答案不是评论。如果它没有回答被问到的问题,它实际上是一个评论。+1@Nick-Ha-Ha,爱死它了!既然你可以用一个冗长、尖刻的评论,为什么还要用一个词呢。好的观点和好的(厚颜无耻的)回答。虽然被接受的答案确实回答了这个问题,但这一个提供了一个有效的解决方案。非常感谢。谢谢你的回答。是否可以将此方法用于ExecutorCompletionService?我试图在ExecutorCompletionService构造函数中传入your ExecutorService对象,但无法在comparator中将结果转换为PriorityFuture。我在我的计算机上进行了测试。这是不对的。在我的机器上,我在执行3之前执行了72,这显然是错误的。这是我能为可调用作业找到的最干净的解决方案,谢谢。您好,我在使用上述代码时遇到类型转换错误<代码>intp1=((PriorityFuture)o1.getPriority()java.util.concurrent.FutureTask无法转换为com.i2c.loyalty.handlers.datasynchandler.utils.InstancePriorityFuture此
InstancePriorityFuture
实现
RunnableFuture
请有人帮忙吗?感谢您发现此@Robert,我已经更新了指向正确URL的链接
public class TestPQ {

    public static void main(String[] args) throws InterruptedException, ExecutionException {
        int nThreads = 2;
        int qInitialSize = 10;

        ExecutorService exec = new ThreadPoolExecutor(nThreads, nThreads, 0L, TimeUnit.MILLISECONDS,
                new PriorityBlockingQueue<Runnable>(qInitialSize, new PriorityFutureComparator())) {

            protected <T> RunnableFuture<T> newTaskFor(Callable<T> callable) {
                RunnableFuture<T> newTaskFor = super.newTaskFor(callable);
                return new PriorityFuture<T>(newTaskFor, ((LenthyJob) callable).getPriority());
            }
        };

        for (int i = 0; i < 20; i++) {
            int priority = (int) (Math.random() * 100);
            System.out.println("Scheduling: " + priority);
            LenthyJob job = new LenthyJob(priority);
            exec.submit(job);
        }
    }
}
Scheduling: 39
Scheduling: 90
Scheduling: 88
Executing: 39
Scheduling: 75
Executing: 90
Scheduling: 15
Scheduling: 2
Scheduling: 5
Scheduling: 24
Scheduling: 82
Scheduling: 81
Scheduling: 3
Scheduling: 23
Scheduling: 7
Scheduling: 40
Scheduling: 77
Scheduling: 49
Scheduling: 34
Scheduling: 22
Scheduling: 97
Scheduling: 33
Executing: 2
Executing: 3
Executing: 5
Executing: 7
Executing: 15
Executing: 22
Executing: 23
Executing: 24
Executing: 33
Executing: 34
Executing: 40
Executing: 49
Executing: 75
Executing: 77
Executing: 81
Executing: 82
Executing: 88
Executing: 97
ThreadPoolExecutor threadPool = new ThreadPoolExecutor(1, numOfWorkerThreads, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>());
threadPool.setThreadFactory(new OpJobThreadFactory(Thread.NORM_PRIORITY-2));
public final static class OpJobThreadFactory implements ThreadFactory {
   private int priority;
   private boolean daemon;
   private final String namePrefix;
   private static final AtomicInteger poolNumber = new AtomicInteger(1);
   private final AtomicInteger threadNumber = new AtomicInteger(1);

   public OpJobThreadFactory(int priority) {
      this(priority, true);
   }

   public OpJobThreadFactory(int priority, boolean daemon) {
      this.priority = priority;
      this.daemon = daemon;
      namePrefix = "jobpool-" +poolNumber.getAndIncrement() + "-thread-";
   }

   @Override
   public Thread newThread(Runnable r) {
      Thread t = new Thread(r, namePrefix + threadNumber.getAndIncrement());
      t.setDaemon(daemon);
      t.setPriority(priority);
      return t;
   }
}
private int priority;

MyCallable(int priority){
this.priority=priority;
}

public String call() {

     logger.info("running callable with priority {}", priority);
     Thread.currentThread().setPriority(priority);

// do stuff

     return "something";
}