【问题标题】:Java executor with no ability to queue tasks无法对任务进行排队的 Java 执行器
【发布时间】:2016-01-14 15:18:13
【问题描述】:

如果其他任务正在处理,我需要一个拒绝任务的 Java 执行器。我想不可能操纵工作队列的大小。

有人可能想知道为什么我首先需要一个具有这种特征的执行者。我需要能够轻松更改策略并允许非零队列大小。

有什么想法吗?

【问题讨论】:

  • 那么你的执行者应该只执行一个任务吗?
  • 在给定时间一个。此外,如果正在等待执行,它应该拒绝其他提交。

标签: java multithreading concurrency executorservice executor


【解决方案1】:

使用ThreadPoolExecutor 和SynchronousQueue(复制自this answer)。

它似乎有效:

import java.util.concurrent.RejectedExecutionHandler;
import java.util.concurrent.Semaphore;
import java.util.concurrent.SynchronousQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

public class SingleTaskExecutor {

public static void main(String[] args) {

    try {
        new SingleTaskExecutor().runTest();
    } catch (Exception e) {
        e.printStackTrace();
    }
}

public void runTest() throws Exception {

    ThreadPoolExecutor tp = new ThreadPoolExecutor(1, 1,
            60L, TimeUnit.SECONDS,
            new SynchronousQueue<Runnable>());

    tp.setRejectedExecutionHandler(new RejectedTaskHandler());

    final Semaphore oneTaskDone = new Semaphore(0);
    tp.execute(new Runnable() {
        @Override public void run() { 
            System.out.println("Sleeping");
            try { Thread.sleep(300); } catch (Exception e) { e.printStackTrace();} 
            System.out.println("Done sleeping");
            oneTaskDone.release();
        }
    });
    tp.execute(new Runnable() {
        @Override public void run() { System.out.println("Never happends"); }
        @Override public String toString() { return "Rejected Runnable"; }
    });
    oneTaskDone.acquire();
    tp.execute(new Runnable() {
        @Override public void run() { System.out.println("Running"); }
    });
    tp.shutdown();
    tp.awaitTermination(100, TimeUnit.MILLISECONDS);
    System.out.println("Finished");
}

static class RejectedTaskHandler implements RejectedExecutionHandler {

    @Override public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
        System.out.println("Task rejected: " + r);
    }

}

}

【讨论】:

    【解决方案2】:

    根据你的说法

    在给定时间一个。此外,如果正在等待执行,它应该拒绝其他提交。

    我的结论是

    一次只处理一项任务并在当前任务处理期间拒绝其他任务是您的要求。在这种情况下,下面的代码应该可以完成这项工作。

    BlockingQueue queue = new ArrayBlockingQueue(1);
    ThreadPoolExecutor executor = new ThreadPoolExecutor(1, 1, 10, TimeUnit.SECONDS, queue, 
    ThreadPoolExecutor.DiscardPolicy);
    
    // Submit Your callable task
    executor.submit(yourCallableTask);
    

    【讨论】:

    • 我认为这是不正确的。它将执行一个任务,但允许您在第一个任务执行时将一个任务排入队列。应该是SynchronousQueue。
    【解决方案3】:

    使用ThreadPoolExecutor。在将任务提交给执行程序之前调用getActiveCount() 并检查它是否等于池大小(意味着所有线程都处于活动状态)。如果是,请不要提交任务。

    【讨论】:

    • 我必须使 getActiveCount() 和提交原子。没有这种锁定有可能吗?
    • 我认为没有锁定是不可能的。即使已经实现了这种功能,它仍然会使用锁定(以确保线程安全行为)。对 getActiveCount() + submit 使用同步块,你应该没问题。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-08-01
    • 1970-01-01
    • 1970-01-01
    • 2015-07-08
    • 2017-12-29
    相关资源
    最近更新 更多