I recently started messing with the java.util.concurrent, and I would like if someone could point out flaws or bad habits in my code.
The program runs until a time out is reached, then outputs all the tasks that completed.
Main Class
public class ConcurrentPackageTests {
private final ExecutorService executor;
public ConcurrentPackageTests() {
executor = Executors.newFixedThreadPool(2);
this.testCallable(4);
}
private void testCallable(int nInstances) {
long startTime = System.currentTimeMillis();
List<Future<Integer>> futures = null;
List<Integer> results = null;
ArrayList<exCallable> callables = new ArrayList<exCallable>(nInstances);
for (int id = 0; id < nInstances; id++) {callables.add(id, new exCallable(id,5));}
//get a list of the futures, monitor the futures outcome.
try { futures = executor.invokeAll(callables, 5, TimeUnit.SECONDS);}
catch (Exception e) { System.out.println("TIMED OUT");}
executor.shutdown(); //Stop accepting tasks.
System.out.println();
results = getFValues(futures); //gets all completed tasks
printOutValues(results, startTime);
}
/**
* get all integer values that terminated successfully.
* @param e
* @return Integer List of results
*/
private List<Integer> getFValues(List<Future<Integer>> e){
final ArrayList<Integer> list = new ArrayList<Integer>(e.size());
for (Future<Integer> f : e) {
if(!f.isCancelled()){
try { list.add(f.get(1, TimeUnit.SECONDS));}
catch (Exception e1) { System.out.println("Err");}
}
}
list.trimToSize();
return list;
}
private void printOutValues(List<Integer> results, long startTime){
for (Integer integer : results) {
System.out.println("Result: " + integer);
} System.out.println("Time: "+ ( System.currentTimeMillis() - startTime ));
}
Callable
public class exCallable implements Callable<Integer>{
private int n;
int result = 1;
final int ID;
public int getResult() {
return result;
}
public exCallable(int ID, int pN) {
this.ID = ID;
this.n = new Random().nextInt(pN)+ 1;
}
@Override
public Integer call() throws Exception{
for (int i = 0; i < n; i++) {
result *= 2;
Thread.sleep(500); //Simulate work.
}
System.out.println("Computation<" + ID + ">2^"+n+"="+result);
return result;
}
}
All the executor does with this collection is iterate through it and add them to its own queue. Therefore almost any collection should do (should you have thousands of tasks and use a collection that is very costly to iterate, then maybe it could be a problem but that's a very rare situation!).
I think your choice of class/method is fine. Can't think of a better suited class. There aren't really classes that are "more thread safe". Stuff are either thread safe or not. At most there are classes that make coding thread safe programs easier. In this case I think you are going with a suitable level of abstraction.
(1) You should avoid member fields like the pest, and use local variables if at all possible. In this case, you can make result
a local variable, so you should. When you have to use member fields, you should strive very hard to make them immutable. In this case, both ID
and n
can be immutable by making them both final fields.
(2) Creating a new Random
object per task is a good decision IMO. If you feel like it, you can use this common optimization:
ThreadLocal<Random> rng = new ThreadLocal<Random>(){
@Override
protected Random init(){
return new Random();
}
};
// afterwards...
Random r = rng.get();
In case of Random
you may not gain a lot, but this optimization can be highly effective when expensive objects (eg a JAXB parser) are involved.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.