如何让 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 null
与 Future
关联的程序的 "cost" 可以忽略不计。 "cancel"没什么。该任务已经完成,剩下的就是允许 Future
传回 null
或质数 Long
.
的内存
由于我们谈论的是学习,在许多情况下,程序员过快地担心性能,我们经常花时间优化应用程序的某些部分,而这实际上不是问题所在。如果我使用某些 JVM 监视器(可能是 jconsole)看到应用程序 运行 内存不足,那么我可能会担心 Futures
的列表,否则我会编写干净且易于维护的代码。
如果您真的担心 Future
,那么根本不要将它们保存在列表中,只需在素数检查任务和主线程之间共享一个 BlockingQueue<Long>
。主要检查作业将 add(...)
放入队列,主线程将 take()
。您应该考虑将 null
s 放入列表中,否则除非您计算结果,否则您将不知道主要任务是否已完成。您想要检查 X 个随机数,然后当从 BlockingQueue<Long>
.
中获取 X 个结果(空值或数字)时,您就会知道它已完成
希望这对您有所帮助。
这是为了学习目的。
假设我想计算质数并使用 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 null
与 Future
关联的程序的 "cost" 可以忽略不计。 "cancel"没什么。该任务已经完成,剩下的就是允许 Future
传回 null
或质数 Long
.
由于我们谈论的是学习,在许多情况下,程序员过快地担心性能,我们经常花时间优化应用程序的某些部分,而这实际上不是问题所在。如果我使用某些 JVM 监视器(可能是 jconsole)看到应用程序 运行 内存不足,那么我可能会担心 Futures
的列表,否则我会编写干净且易于维护的代码。
如果您真的担心 Future
,那么根本不要将它们保存在列表中,只需在素数检查任务和主线程之间共享一个 BlockingQueue<Long>
。主要检查作业将 add(...)
放入队列,主线程将 take()
。您应该考虑将 null
s 放入列表中,否则除非您计算结果,否则您将不知道主要任务是否已完成。您想要检查 X 个随机数,然后当从 BlockingQueue<Long>
.
希望这对您有所帮助。