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

时间:2018-06-20 22:05:39

标签: java multithreading concurrency threadpool threadpoolexecutor

这是出于学习目的。

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

我想做的是:如果任务中要检查的数字不是素数,请从列表中删除我的未来/取消它。据我所知,只有执行者本身可以取消未来。 我要的是任务本身说“嘿,我知道我的结果对您没有用,所以在遍历列表时请忽略我”。 我不知道该怎么做。

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

 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();

一个工人在那里执行一个任务(是素数吗?)

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();
    }


}

1 个答案:

答案 0 :(得分:1)

  

我想做的是:如果任务中要检查的数字不是素数,请从列表中删除我的未来/取消它。据我所知,只有执行者本身可以取消未来。

在我看来,这似乎是不必要的优化。 Future在那里,任务可以返回一个值。一旦任务确定它不是素数并返回null,与Future关联的程序的“成本”就可以忽略不计。没有什么可以“取消”的。该任务已经完成,剩下的就是允许Future传回null或素数Long的内存。

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

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

希望这会有所帮助。