I am trying to implement "TaskExecutor" with generics (my first attempt to use generics) and using ExecutorService.
Here is my "TaskExecutor" class:
public class ExecuteAlerterTask<T> {
public List<T> process(String executorName, Callable<T> task) throws ExecutionException, InterruptedException {
final ThreadFactory threadFactory = new ThreadFactoryBuilder()
.setNameFormat(executorName + "-%d")
.setDaemon(true)
.build();
ExecutorService executor = Executors.newFixedThreadPool(10, threadFactory);
Collection<Future<T>> futures = new ArrayList<>();
IntStream.range(1, 10).forEach(i -> {
Future<T> future = executor.submit(task);
futures.add(future);
});
List<T> result = new ArrayList<>();
for (Future<T> f : futures) {
result.add(f.get());
}
executor.shutdown();
return result;
}
}
Here is my way to run it:
@Test
public void process() throws Exception {
Callable<String> callable = () -> "Do something on ";
ExecuteAlerterTask<String> executeAlerterTask = new ExecuteAlerterTask<>();
List<String> result = executeAlerterTask.process("TaskName", callable);
result.forEach(System.out::println);
}
And here is my question: How to write my Callable that it would accept argument i at a line:
Future<T> future = executor.submit(task);
E.g. desired result would be:
Do something on 1
Do something on 3
Do something on 7
Do something on 2
<...etc...>
If something else is wrong with my code - please let me know.
EDIT
Removed implements Callable
Code above is abstraction of what I really want to do:
EDIT2
After all suggestions I have following solution:
public class ExecuteAlerterTask<T> {
public List<T> process(String executorName, Collection<Callable<T>> task) throws ExecutionException, InterruptedException {
final ThreadFactory threadFactory = new ThreadFactoryBuilder()
.setNameFormat(executorName + "-%d")
.setDaemon(true)
.build();
ExecutorService executor = Executors.newFixedThreadPool(10, threadFactory);
Collection<Future<T>> futures = executor.invokeAll(task);
List<T> result = new ArrayList<>();
for (Future<T> f : futures) {
result.add(f.get());
}
executor.shutdown();
return result;
}
}
And way to run it:
@Test
public void process() throws Exception {
Collection<Callable<String>> tasks = new ArrayList<>();
IntStream.range(1, 10).forEach(i -> {
tasks.add(new Task(i).callable);
});
ExecuteAlerterTask<String> executeAlerterTask = new ExecuteAlerterTask<>();
List<String> result = executeAlerterTask.process("TaskName", tasks);
result.forEach(System.out::println);
}
private class Task {
private int i;
private Callable<String> callable = () -> "Doing something on i: " + i;
private Task(int i) {
this.i = i;
}
}
EDIT3
Even simpler way to run it:
@Test
public void process() throws Exception {
Collection<Callable<String>> tasks = new ArrayList<>();
IntStream.range(1, 10).forEach(i -> {
tasks.add(() -> "Do something on i: " + i * 2);
});
ExecuteAlerterTask<String> executeAlerterTask = new ExecuteAlerterTask<>();
List<String> result = executeAlerterTask.process("TaskName", tasks);
result.forEach(System.out::println);
}
I guess I quite happy with final solution. Thanks all!
Firstly, you don't need call()
at all, neither do you need to implement Callable<T>
in this class because you never use it as such.
To create a callable the way you want, you couldd do
Callable<String> task; // from the parameter
int i; // from the loop
Callable<String> wrapper = () -> { return task.call() + " on " + i; }
executor.submit(wrapper);
You're essentially giving the lambda the outside variable i
as a parameter.