mmm....sai io non farei così.
E' cmq un argomento interessante perchè non ho mai fatto una cosa simile...
Guarda se ti torna, poi lascio il parere ai + esperti 
classe principale (nome omaggio alla vecchia gloria MSX!)
codice:
public class AthleticLand {
private static String[] corridori = {"Pippo","Pluto","Paperino" ,"Marco Cocco", "Topolino","Minnie", "Francesco Muià"};
public static final CyclicBarrier startLine = new CyclicBarrier(corridori.length);
private static boolean winner = false;
final static long LOWER_RANGE = 0;
final static long UPPER_RANGE = 1000;
public static long getRandomWait(){
Random random = new Random();
return LOWER_RANGE + (long)(random.nextDouble()*(UPPER_RANGE - LOWER_RANGE));
}
public static void main(String[] args) {
ExecutorService executorServiceJudge = Executors.newFixedThreadPool(corridori.length);
Set<Callable<String[]>> callables = new HashSet<Callable<String[]>>();
for(int a = 0; a <corridori.length; a++){
callables.add(new Corridore(corridori[a]));
}
List<Future<String[]>> futures = null;
System.out.println("\r\n===========Prontiiii...via!==========\r\n");
try {
futures = executorServiceJudge.invokeAll(callables);
} catch (InterruptedException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
Map mappa = new HashMap<String, Long>();
for(Future<String[]> future : futures){
try {
mappa.put(future.get()[1], Long.parseLong(future.get()[0]));
// ti interessa solo il primo...
} catch (ExecutionException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
executorServiceJudge.shutdown();
sortByValue(mappa);
}
public static synchronized void Giudice (String name) {
if(!winner){
System.out.println(" \r\n-------- Il vincitore è : " + name);
winner= true;
}
}
public static void sortByValue(Map unsortMap) {
List list = new LinkedList(unsortMap.entrySet());
Collections.sort(list, new Comparator() {
public int compare(Object o1, Object o2) {
return ((Comparable) ((Map.Entry) (o1)).getValue())
.compareTo(((Map.Entry) (o2)).getValue());
}
});
Map sortedMap = new LinkedHashMap();
for (Iterator it = list.iterator(); it.hasNext();) {
Map.Entry entry = (Map.Entry) it.next();
sortedMap.put(entry.getKey(), entry.getValue());
}
Iterator it = sortedMap.entrySet().iterator();
System.out.println("\r\n=========== Traguardi !!!==========\r\n");
while(it.hasNext()){
Map.Entry entry = (Map.Entry) it.next();
System.out.println(entry.getKey() + " " + entry.getValue());
}
}
}
e il corridore tipico:
codice:
public class Corridore implements Callable{
private long durataCorsa = 0;
private String name = null;
public Corridore ( String name){
this.durataCorsa =AthleticLand. getRandomWait();
this.name = name;
System.out.println("Corridore: " + name + " pronto alla linea di partenza! ci metterà-->" + durataCorsa);
}
@Override
public Object call() throws Exception {
AthleticLand.startLine.await();
System.out.println(name +" partito!");
Thread.sleep(durataCorsa*10);
AthleticLand.Giudice(name);
return new String[]{System.currentTimeMillis()+"", name};
}
}
Forse il risultato ancor + preciso si avrebbe sfruttando la differenza temporale data dall'effettivo start dello sleep del corridore e la restituzione del future relativo...tuttavia con il CyclicBarrier dovrei aver reso abbastanza bene l'idea...