如何让 Task 取消它自己的未来?

How to let Task cancel it's own future?

这是为了学习目的。

假设我想计算质数并使用 ThreadPoolExecutor 来计算。 下面你可以看到我当前的实现,这有点傻。 我的结构:
我生成一定范围内的数字。
对于每个生成的数字,创建一个任务来检查给定数字是否为质数。
如果是素数,则运算结果为数字,否则为null.
收集器遍历结果列表并检查是否有数字或 null。如果它是一个数字,将该数字写到某个文件中(此处:按位数排序)

我想做的是:如果任务中要检查的数字不是质数,请从 list/cancel 中删除我的未来。据我所知,只有 Executor 本身才能取消 Future。 我要的是任务本身说的"Hey, I know my result is no use to you, so please ignore me while iterating throught the list"。 我不知道该怎么做。

我现在在做什么(相关部分):

 final List<Future<Long>> resultList = new ArrayList<>();
        final BlockingQueue<Runnable> workingQueue = new ArrayBlockingQueue<>(CAPACITY);
        final ExecutorService exec = new ThreadPoolExecutor(
                Runtime.getRuntime().availableProcessors() - 2,
                Runtime.getRuntime().availableProcessors() - 1,
                5, TimeUnit.SECONDS,
                workingQueue,
                new ThreadPoolExecutor.CallerRunsPolicy()
        );


        for (long i = GENERATEFROM; i <= GENERATETO; i++) {
            Future<Long> result = exec.submit(new Worker(i));
            resultList.add(result);
        }
        Collector collector = new Collector(resultList,GENERATETO);
        collector.start();
        exec.shutdown();

一个Worker在那里执行一个任务(是质数吗?)

public class Worker implements Callable<Long> {

    private long number;

    public Worker(long number) {
        this.number = number;
    }


    //checks whether an int is prime or not.
    boolean isPrime(long n) {
        //check if n is a multiple of 2
        if (n % 2 == 0) return false;
        //if not, then just check the odds
        for (long i = 3; i * i <= n; i += 2) {
            if (n % i == 0)
                return false;
        }
        return true;
    }


    @Override
    public Long call() throws Exception {

        if (isPrime(number)) {
            return number;
        }
        return null;


    }
}

并且,为了完整起见,我的收藏家:

public class Collector {

    private List<Future<Long>> primeNumbers;
    private long maxNumberGenerated;
    private HashMap<Integer, PrintWriter> digitMap;
    private final long maxWaitTime;
    private final TimeUnit timeUnit;


    public Collector(List<Future<Long>> primeNumbers, long maxNumberGenerated) {
        this.primeNumbers = primeNumbers;
        this.maxNumberGenerated = maxNumberGenerated;
        this.digitMap = new HashMap<>();
        this.maxWaitTime = 1000;
        this.timeUnit = TimeUnit.MILLISECONDS;
    }


    public void start() {

        try {
            //create Files
            int filesToCreate = getDigits(maxNumberGenerated);
            for (int i = 1; i <= filesToCreate; i++) {
                File f = new File(System.getProperty("user.dir") + "/src/solutionWithExecutor/PrimeNumsWith_" + i +
                        "_Digits.txt");
                PrintWriter pw = new PrintWriter(f, "UTF-8");
                digitMap.put(i, pw);
            }


            for (Future<Long> future : primeNumbers) {
                Object possibleNumber = future.get();
                if (possibleNumber != null) {
                    long numberToTest = (long) possibleNumber;
                    int numOfDigits = getDigits(numberToTest);
                    PrintWriter correspondingFileWriter = digitMap.get(numOfDigits);
                    correspondingFileWriter.println(possibleNumber.toString());
                    correspondingFileWriter.flush();

                }
            }
            for (PrintWriter fw : digitMap.values()) {
                fw.close();
            }


        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
    }

    private int getDigits(long maxNumberGenerated) {

        return String.valueOf(maxNumberGenerated).length();
    }


}

What I would like to do instead: If the number to be checked in the task is not a prime, delete my future from the list/cancel it. As far as I know, only the Executor itself can cancel a Future.

对我来说,这似乎是一个不必要的优化。 Future 在那里,以便任务可以 return 一个值。一旦任务发现它不是素数并且 returns nullFuture 关联的程序的 "cost" 可以忽略不计。 "cancel"没什么。该任务已经完成,剩下的就是允许 Future 传回 null 或质数 Long.

的内存

由于我们谈论的是学习,在许多情况下,程序员过快地担心性能,我们经常花时间优化应用程序的某些部分,而这实际上不是问题所在。如果我使用某些 JVM 监视器(可能是 jconsole)看到应用程序 运行 内存不足,那么我可能会担心 Futures 的列表,否则我会编写干净且易于维护的代码。

如果您真的担心 Future,那么根本不要将它们保存在列表中,只需在素数检查任务和主线程之间共享一个 BlockingQueue<Long>。主要检查作业将 add(...) 放入队列,主线程将 take()。您应该考虑将 nulls 放入列表中,否则除非您计算结果,否则您将不知道主要任务是否已完成。您想要检查 X 个随机数,然后当从 BlockingQueue<Long>.

中获取 X 个结果(空值或数字)时,您就会知道它已完成

希望这对您有所帮助。