I have an API call that can only accept 5 subrequests at a time. So I need to chunkify if more than 10 subrequests come in and then send them in parallel as per the SLA.
Below is a nonparallel chunkified code and I am looking to parallelize this call invokeService(bulkRequestChunk)
int BULK_SUBREQUEST_SIZE = 5;
// infoRequestList size = 7
for (int i = 0; i < numOfSubRequests; i += BULK_SUBREQUEST_SIZE) {
List<InfoRequest> infoRequestChunk;
if (i + BULK_SUBREQUEST_SIZE >= numOfSubRequests) {
infoRequestChunk = infoRequestList.subList(i, numOfSubRequests);
} else {
infoRequestChunk = infoRequestList.subList(i, i + BULK_SUBREQUEST_SIZE);
}
BulkRequest bulkRequestChunk = new BulkRequest();
bulkRequestChunk.setRequests(infoRequestChunk);
BulkResponse bulkResponseChunk = invokeService(bulkRequestChunk);
// output list to capture all chunked requests
bulkResponseList.add(bulkResponseChunk);
}
Use an ExecutorService and submit it tasks to run in parallel:
ExecutorService execServ = Executors.newFixedThreadPool(numThreads);
final List<BulkResponse> bulkResponseList = new ArrayList<>();
int BULK_SUBREQUEST_SIZE = 5;
for (int i = 0; i < numOfSubRequests; i += BULK_SUBREQUEST_SIZE) {
List<InfoRequest> infoRequestChunk;
if (i + BULK_SUBREQUEST_SIZE >= numOfSubRequests) {
infoRequestChunk = infoRequestList.subList(i, numOfSubRequests);
} else {
infoRequestChunk = infoRequestList.subList(i, i + BULK_SUBREQUEST_SIZE);
}
BulkRequest bulkRequestChunk = new BulkRequest();
bulkRequestChunk.setRequests(infoRequestChunk);
execServ.submit(() -> {
BulkResponse bulkResponseChunk = invokeService(bulkRequestChunk);
bulkResponseList.add(bulkResponseChunk);
});
}
execServ.shutdown();
try {
execServ.awaitTermination(Long.MAX_VALUE, TimeUnit.DAYS);
} catch (InterruptedException e) {
}
This question already has answers here:
How to wait for all threads to finish, using ExecutorService?
(27 answers)
Closed 4 years ago.
I am using executor service to run my 10 tasks with 2 tasks at a time.
ExecutorService executor = Executors.newFixedThreadPool(2);
for (int i = 0; i < 10; i++) {
String name = "NamePrinter " + i;
Runnable runner = new TaskPrint(name, 1000);
System.out.println("Adding: " + name + " / " + 1000);
executor.execute(runner);
}
How can I wait for all tasks to complete
Use java 8 CompleteableFuture with join method to wait:
ExecutorService executor = Executors.newFixedThreadPool(2);
CompletableFuture[] futures = new CompletableFuture[10];
for (int i = 0; i < 10; i++) {
String name = "NamePrinter " + i;
Runnable runner = new TaskPrint(name, 1000);
System.out.println("Adding: " + name + " / " + 1000);
futures[i] = CompletableFuture.runAsync(runner, executor);
}
CompletableFuture.allOf(futures).join(); // THis will wait until all future ready.
Assign your callables to futures and check that you can get results from each future.
Future future = workerExecutor.submit(new Callable() {
#Override
public Object call() throws Exception {
try {
System.out.println("MyItemTree.TimedRunnable");
ReturnInterface returnInterface = (ReturnInterface) commandInterface.call();
returnInterface.submitResult();
} catch (Exception ex) {
ex.printStackTrace();
throw new RuntimeException(ex);
}
return null;
}
});
try {
Object get = future.get();
} catch (InterruptedException | ExecutionException ex) {
Throwable cause = ex.getCause();
ex.printStackTrace();
cause.printStackTrace();
Throwable cause1 = cause.getCause();
if (cause1 instanceof CommandInterfaceException) {
System.out.println("[MyItemTree].scheduleTask Cause 1= COMMANDINTERFACE EXCEPTION");
this.componentInterface.getAlertList().addAlert(((CommandInterfaceException) cause1).getResolverFormInterface());
}
}
}
ExecutorService serv = Executors.newFixedThreadPool(5);
CompletionService<Integer> servive = new ExecutorCompletionService<>(serv);
for (int i = 0; i < 5; i++) {
servive.submit(new MyTask(i));
}
for (int i = 0; i < 5; i++) {
Future<Integer> f = null;
try {
f = servive.take();
} catch (InterruptedException e) {
e.printStackTrace();
}
//f.get()
}
I want to know which task or callable was completed in the first result(f.get())
How do I do that, or what other functions?
Well, its totally depends upon JVM and task how its going to be handle by JVM.
I have a huge loop that I wanted to split up into 4 threads. I've done so using a little bit noobish method(or maybe not?) and split up the counter of the for loops into 4 intervals, created a new Printwriter, and CrucibleOptimizer for each thread so that there are no conflicts, like this:
public static void main(String[] args) {
Runnable run1 = new Runnable() {
#Override
public void run() {
PrintWriter writer1;
try {
writer1 = new PrintWriter("test_result1.txt");
CrucibleOptimizer optimizer1 = new CrucibleOptimizer();
int[] loop1boundries = new int[]{1, 7};
opt(optimizer1, writer1, loop1boundries[0], loop1boundries[1]);
} catch (FileNotFoundException e) {
System.out.println("File not found");
e.printStackTrace();
}
}
};
Runnable run2 = new Runnable() {
#Override
public void run() {
PrintWriter writer2;
try {
writer2 = new PrintWriter("test_result2.txt");
CrucibleOptimizer optimizer2 = new CrucibleOptimizer();
int[] loop2boundries = new int[]{8, 14};
opt(optimizer2, writer2, loop2boundries[0], loop2boundries[1]);
} catch (FileNotFoundException e) {
System.out.println("File not found");
e.printStackTrace();
}
}
};
Runnable run3 = new Runnable() {
#Override
public void run() {
PrintWriter writer3;
try {
writer3 = new PrintWriter("test_result3.txt");
CrucibleOptimizer optimizer3 = new CrucibleOptimizer();
int[] loop3boundries = new int[]{15, 22};
opt(optimizer3, writer3, loop3boundries[0], loop3boundries[1]);
} catch (FileNotFoundException e) {
System.out.println("File not found");
e.printStackTrace();
}
}
};
Runnable run4 = new Runnable() {
#Override
public void run() {
PrintWriter writer4;
try {
writer4 = new PrintWriter("test_result4.txt");
CrucibleOptimizer optimizer4 = new CrucibleOptimizer();
int[] loop4boundries = new int[]{23, 30};
opt(optimizer4, writer4, loop4boundries[0], loop4boundries[1]);
} catch (FileNotFoundException e) {
System.out.println("File not found");
e.printStackTrace();
}
}
};
Thread[] threads = new Thread[]{new Thread(run1), new Thread(run2), new Thread(run3), new Thread(run4)};
for (Thread thr : threads){
thr.start();
}
}
And this is the method that I'm asking about. I don't know if its thread safe. I've been reading around and google says that as far as I don't have any local variables, I'm fine, but what concerns me is the multiple counters in those loops:
public static void opt(CrucibleOptimizer opt, PrintWriter writer, int minIncluded, int maxIncluded){
//more than this is never used
final int oreMaterialsMaximum = 100;//100
final int ingotMaterialMaximum = 30;//30
//test for every possible material combination
for (int a = minIncluded; a <= maxIncluded; a++){//for amount of ingots
System.out.println("Testing for ingot number: " + a);
double ratioMin = (Reference.UNITS_IMPOSSIBLE / (double)(a * Reference.UNITS_INGOT));
for (int i = 0; i <= (int)(100 / Reference.UNITS_IMPOSSIBLE); i++){//for every ratio possible
double currentRatio = round(i * ratioMin, 6);
System.out.println("Testing for ratio: " + currentRatio);
for (int b = 0; b <= ingotMaterialMaximum; b++){//with every amount of ingots
for (int c = 0; c <= oreMaterialsMaximum; c++){//with every amount of rich ore
for (int d = 0; d <= oreMaterialsMaximum; d++){//with every amount of normal ore
for (int e = 0; e <= oreMaterialsMaximum; e++){//with every amount of poor ore
for (int f = 0; f <= oreMaterialsMaximum; f++){//with every amount of small ore
opt.set(null, null, null, a); //only the ingots are passed in this way
int[] res = opt.optimizeMaterial(new int[]{c, d, e, f, b}, currentRatio);
if (res != null){
int units = 0;
for (int j = 0; j < res.length; j++)
units += res[j] * Reference.MATERIAL_UNITS[j];
double unitsRight = Math.round(a * Reference.UNITS_INGOT * currentRatio);
if (units != (int)unitsRight){ //if the units are not correct, log
writer.println("I: " + a + " Rat: " + currentRatio + " I_av: " + b + " O_Ri: " + c + " O_No: " + d +
" O_Po: " + e + " O_Sm: " + f + " units_wrong: " + units + " units_right: " + (int)unitsRight);
}
}
}
}
}
}
}
}
}
System.out.println("Testing done");
writer.close();
}
The "do not use static variables" advise is indeed too simplistic: the other requirement is to not pass shared objects to static methods running in different threads.
Loop counters and other primitive local variables are thread-safe. The only thing that could make a method non-thread safe is shared state. It appears that you have successfully avoided that by creating separate CrucibleOptimizer and PrintWriter objects.
One refactoring that I would attempt is combining your Runnables. Make a named class that takes loop boundaries, and make four instances of that class in your main. This would work better than four separate anonymous classes that have very few differences:
private static class ThreadRunnable implements Runnable {
final String fileName;
final int[] loopBoundaries;
public ThreadRunnable(String fn, int[] lb) {
fileName = fn;
loopBoundaries = lb;
}
#Override
public void run() {
PrintWriter pw;
try {
pw = new PrintWriter(fileName);
CrucibleOptimizer co = new CrucibleOptimizer();
opt(co, pw, loop4boundries[0], loop4boundries[1]);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
}
Now you can make four ThreadRunnable instances which share identical code.
Loops in of themselves are thread safe, so no you don't need to worry about that.
The only thing you need to worry about is anything that might be accessed by multiple threads at once.
However your entire architecture really needs some work.
For example why have 4 separate implementations for the runables rather than having one implementation and passing parameters into it to say which chunk to work on.
I also don't know what you are trying to do with all the loops but it's highly unlikely you really need any structure like that.
I want to try 3 times when error happened.
What I have done so far....
public class TryTest {
public static void main(String[] args) {
TryTest test = new TryTest();
test.tryThis();
}
public void tryThis() {
int a = 10;
int x = 0;
int count = 1;
try {
System.out.println("Test " + count);
a = a / x;
System.out.println("Success !");
} catch (Exception e) {
if (count <= 3) {
// I want to try again with new x value
count++;
x++;
}
System.out.println("ERROR:\t" + e);
} finally {
System.out.println("Finish");
}
}
}
How can I do this?
Use a loop, which loops using you have a done values [0, 3)
for(int i = 0; i < 3; i++) {
try {
System.out.println("Test " + count);
int a = 10 / i;
System.out.println("Success !");
break;
} catch (Exception e) {
System.out.println("ERROR:\t" + e);
}
}
System.out.println("Finish");