sifis
sifis

Reputation: 21

java multithreaded hashed ArrayList<String>

I want to do a hash on every item from an arraylist and basically return it on the main. But for example a have this:

import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;

public class hash extends Thread {

    private Thread t = null;
    private MessageDigest md = null;
    private StringBuffer sb = null;
    private String message = null;
    private ArrayList<String> list = null;
    private int count = 0;

    public hash(ArrayList<String> list) {
        this.list = list;
    }

    public final void mdstart() {

        for(String item:list){
            this.message=item;
            if(t==null){
                t = new Thread(this);
                t.start();
            }
            count++;
        }
        System.out.println("end: "+this.count);

    }

    @Override
    public final void run() {
        System.out.println("run: "+this.count);
        try {
            md = MessageDigest.getInstance("MD5");
            md.update(this.message.getBytes());

            byte[] digest = md.digest();
            sb = new StringBuffer();
            for (byte hash : digest) {
                sb.append(String.format("%02x", hash));
            }
            System.out.println(this.message + " : " + sb.toString());
        } catch (NoSuchAlgorithmException ex) {
            System.out.println("no such algorithm exception : md5");
            System.exit(1);
        }
    }

    public static void main(String args[]) {

        ArrayList<String> list = new ArrayList<>();
        for (int i = 0; i < 10; i++) {
            list.add("message" + i);
        }
        new hash(list).mdstart();      
    }
}

and the output is:

end: 10
run: 10
message9 : 99f72d2de922c1f14b0ba5e145f06544

which means that the program run only the last one thread from those I expect.

Upvotes: 0

Views: 177

Answers (2)

Sergey Kalinichenko
Sergey Kalinichenko

Reputation: 726809

The problem is that your code will start only one thread:

if(t==null){
    t = new Thread(this);
    t.start();
}

Once the first thread is started, t is no longer null, so no new threads would be created.

To fix this problem, make an array of threads, and set threads[count++] to the newly created thread in your loop. Once the loop is over, you can join your threads to make sure they all finish before mdstart() returns:

public final void mdstart() {
    Thread[] threads = new Thread[list.size()];
    for(String item:list){
        this.message=item;
        threads[count] = new Thread(this);
        threads[count].start();
        count++;
    }
    for (Thread t : threads) {
        t.join();
    }
    System.out.println("end: "+this.count);
}

Note: This will fix the start-up portion of your code. You would need to deal with synchronization issues in your run() method to complete the fix.

Upvotes: 0

Florian Schaetz
Florian Schaetz

Reputation: 10662

You are storing your Thread in t, which is null at the start but after creating the first Thread, it isn't null anymore, thus your if fails and no new Thread is created. Then you try to modify the message while this Thread runs... Honestely, the whole thing is a mess. Even if you were to create 10 Threads, they would all point to the same hash() object where the message variable is changing randomly without knowing if any Thread has already finished working.

For example, the following could happen:

  1. You start the Thread for first message
  2. Thread has not yet run, but your for loop already sets the message to the 2nd one
  3. The thread runs and calculates the message for the 2nd message
  4. Message 3 is set. Nothing happens since Thread is already finished.
  5. Message 4 is set, again, nothing happens as the Thread is done etc.

To fix it:

  • Remove the list variable from hash.
  • Create a new hash() object for each hashcode/message
  • Start a new thread for each hash() object. Then it should work.

Upvotes: 1

Related Questions