BigPino
BigPino

Reputation: 113

Improve ExecutorService to execute process on more then 1 cpu

When I run the code below, it seems like only one core is uses by javaw.exe.

int cores = Runtime.getRuntime().availableProcessors();
System.out.println("Number of cores: " + cores); //8 cores

int partitionSize = alphabet.length / cores;
ExecutorService service = Executors.newFixedThreadPool(cores);
List<Future> futures = new ArrayList<Future>();

for (int c = 0; c < cores; c++) {

    char[] part = Arrays.copyOfRange(alphabet, c * partitionSize, (c + 1) * partitionSize);
    futures.add(service.submit(new BruteWorker(part) ));

}

for(Future f : futures)
    f.get();

According to this image from ProcessExplorer, am I right to think that my app only use 1 CPU ? If yes, how can I do to use all my 8 cores? The total CPU utilization is 12.5 which correspond with 100% / 8cores

processexplorer

Here is what I get from some println :

Number of cores: 8
New thread (id = 11)
New thread (id = 12)
New thread (id = 13)
New thread (id = 14)
New thread (id = 16)
New thread (id = 15)
New thread (id = 17)
New thread (id = 18)
10000000 tries on thread id = 12
20000000 tries on thread id = 12
30000000 tries on thread id = 12
40000000 tries on thread id = 12
50000000 tries on thread id = 12
60000000 tries on thread id = 12

enter image description here

Why other threads are doing nothing ?

BruteWorker class :

public class BruteWorker implements Runnable {
    private static final char[] alphabet = "eaistnrulodmpcvqgbfjhzxykw0123456789!@#$%&*".toCharArray();
    private static final int maxLength = 8;
    private static Map<String, String> hashes;
    private static MessageDigest md ;
    private char[] partition;
    private long nbTries = 0;

    BruteWorker(char[] partition, Map<String, String> hashes) {
        this.partition = partition;
        this.hashes = hashes;
    }

    public void run() {
        System.out.println("New thread (id = "+ Thread.currentThread().getId() +")");
        try {
            md = MessageDigest.getInstance("MD5");
            for(char c : this.partition){
                stringPossibilities(String.valueOf(c), maxLength);
            }
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
        System.out.println("End of thread (id = "+ Thread.currentThread().getId() +")");
    }

    //Recursive class
    private void stringPossibilities(String prefix, int length) {
        nbTries++;
        if((nbTries % 10000000) == 0){
            System.out.println(nbTries + " tries on thread id = "+ Thread.currentThread().getId());
        }
        md.update(prefix.getBytes());
        byte[] bytes = md.digest();
        String md5 = getMd5Hash(prefix);

        if (hashes.containsKey(md5)){
            System.out.println(prefix + " = " + md5);
        }


        if (prefix.length() < length){
            for (int i = 0; i < alphabet.length; i++){
                char c = alphabet[i];
                stringPossibilities(prefix + c, length);
            }
        }
    }

    private String getMd5Hash(String prefix){
        md.update(prefix.getBytes());
        byte[] bytes = md.digest();
        StringBuilder md5 = new StringBuilder();
        for(int j =0; j < bytes.length; j++){
            md5.append(Integer.toString((bytes[j] & 0xff) + 0x100, 16).substring(1));
        }
        return md5.toString();
    }

}

Upvotes: 1

Views: 1725

Answers (1)

Gareth Davis
Gareth Davis

Reputation: 28059

Struggling to see what exactly is going on here as the following, works and runs concurrently just fine:

public class Main {
    private static final char[] alphabet = "eaistnrulodmpcvqgbfjhzxykw0123456789!@#$%&*".toCharArray();
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        int cores = Runtime.getRuntime().availableProcessors();
        System.out.println("Number of cores: " + cores); //8 cores

        int partitionSize = alphabet.length / cores;
        ExecutorService service = Executors.newFixedThreadPool(cores);
        List<Future> futures = new ArrayList<Future>();

        for (int c = 0; c < cores; c++) {

            char[] part = Arrays.copyOfRange(alphabet, c * partitionSize, (c + 1) * partitionSize);
            futures.add(service.submit(new BruteWorker(part)));

        }

        for(Future f : futures)
            f.get();

        service.shutdown();
        System.out.println("Completed normally");
    }
    public static class BruteWorker implements Runnable {
        private char[] partition;


        BruteWorker(char[] partition) {
            this.partition = partition;
        }

        public void run() {
            System.out.println("New thread (id = "+ Thread.currentThread().getId() +")");
            for (long nbTries = 0; nbTries < 1_000_000_000L; nbTries ++ ) {
                if((nbTries % 10_000_000) == 0){
                    System.out.println(nbTries + " tries on thread id = "+ Thread.currentThread().getId());
                }
            }
            System.out.println("End of thread (id = "+ Thread.currentThread().getId() +")");
        }
    }    
}

Also available (with output) as a gist.

note it's a chopped up hack of your code.

I did notice that your code does appear to use a static reference to a MessageDigest and Map<String,String>. It's possible that your task is actually failing on the other threads and your just not discovering this as your blocked on waiting one of the other long running tasks.

Try catching all Exceptions in your run method and dumping the stack trace, it might be enlightening:

public void run() {
    System.out.println("New thread (id = "+ Thread.currentThread().getId() +")");
    try {
        md = MessageDigest.getInstance("MD5");
        for(char c : this.partition){
            stringPossibilities(String.valueOf(c), maxLength);
        }
    } catch (Exception e) {
        e.printStackTrace();
    } finally {
        System.out.println("End of thread (id = "+ Thread.currentThread().getId() +")");
    }
}

Upvotes: 2

Related Questions