1

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();
    }

}
BigPino
  • 113
  • 1
  • 10
  • 2
    On the surface what you have there looks ok. So something else must be going on. Are you sure the `BruteWorker` are actually running concurrently (ie aren't just doing all their work in the constructor for example?). A couple of `println` at entry point and exit of the `run()` method should be enough to confirm. – Gareth Davis Feb 09 '16 at 13:51
  • You can also try running your application with a debugger (for example with "debug" in Eclipse) and see how many ExecutorService threads are running. – pkalinow Feb 09 '16 at 13:56
  • The title of your question is a little wonky. The `Future` object is not responsible for executing your code: It's the `ExecutorService` that does that. The `Future` objects are merely handles that you use to wait for and obtain the result of the computation. – Solomon Slow Feb 09 '16 at 16:20
  • I've updated with some println @GarethDavis – BigPino Feb 10 '16 at 01:51
  • @pkalinow ExecutorService has 8 threads running, I've updated the post with trace and screenshot. – BigPino Feb 10 '16 at 02:20
  • @BigPino seems reasonable, can you provide the source to `BruteWorker` because all that's left is there must be some sort of synchronisation – Gareth Davis Feb 10 '16 at 10:57
  • @GarethDavis I've just add the BruteWorker Class – BigPino Feb 10 '16 at 14:20

1 Answers1

2

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() +")");
    }
}
Gareth Davis
  • 27,701
  • 12
  • 73
  • 106
  • failing this I'm going to need to you post a complete, runnable example in order to debug the thing. – Gareth Davis Feb 10 '16 at 14:53
  • Oh Yes! Thank you! I've remove all static variable from my worker. I now use 100% of CPU – BigPino Feb 10 '16 at 15:04
  • I'd like to share an Integer value to all threads which I want to increase by 1 for all hash found. Once this integer hit 5, I want to stop all threads. How could I do this? – BigPino Feb 12 '16 at 13:27
  • That sounds like the start of a new question to me :) but you might want to have a look at 'AtomicInteger' it might help you out – Gareth Davis Feb 12 '16 at 16:52