Aman Deep Gautam
Aman Deep Gautam

Reputation: 8787

reduce in performance when used multithreading in java

I am new to multi-threading and I have to write a program using multiple threads to increase its efficiency. At my first attempt what I wrote produced just opposite results. Here is what I have written:

class ThreadImpl implements Callable<ArrayList<Integer>> { 
    //Bloom filter instance for one of the table
    BloomFilter<Integer> bloomFilterInstance = null;
    // Data member for complete data access.
    ArrayList< ArrayList<UserBean> > data = null;
    // Store the result of the testing 
    ArrayList<Integer> result = null;
    int tableNo;

    public ThreadImpl(BloomFilter<Integer> bloomFilterInstance, 
                        ArrayList< ArrayList<UserBean> > data, int tableNo) {
        this.bloomFilterInstance = bloomFilterInstance;
        this.data = data;
        result  = new ArrayList<Integer>(this.data.size());
        this.tableNo = tableNo;
    }

    public ArrayList<Integer> call() {
        int[] tempResult = new int[this.data.size()];
        for(int i=0; i<data.size() ;++i) {
            tempResult[i] = 0;
        }
        ArrayList<UserBean> chkDataSet = null;
        for(int i=0; i<this.data.size(); ++i) {
            if(i==tableNo) {
                //do nothing;
            } else {
                chkDataSet = new ArrayList<UserBean> (data.get(i));
                for(UserBean toChk: chkDataSet) {
                    if(bloomFilterInstance.contains(toChk.getUserId())) {
                        ++tempResult[i];
                    }
                }
            }
            this.result.add(new Integer(tempResult[i]));
        }
        return result;
    }
}

In the above class there are two data members data and bloomFilterInstance and they(the references) are passed from the main program. So actually there is only one instance of data and bloomFilterInstance and all the threads are accessing it simultaneously.

The class that launches the thread is(few irrelevant details have been left out, so all variables etc. you can assume them to be declared):

class MultithreadedVrsion {
    public static void main(String[] args) {
        if(args.length > 1) {
            ExecutorService es = Executors.newFixedThreadPool(noOfTables);
            List<Callable<ArrayList<Integer>>> threadedBloom = new ArrayList<Callable<ArrayList<Integer>>>(noOfTables);
            for (int i=0; i<noOfTables; ++i) {
                threadedBloom.add(new ThreadImpl(eval.bloomFilter.get(i), 
                                                eval.data, i)); 
            }
            try {
                List<Future<ArrayList<Integer>>> answers = es.invokeAll(threadedBloom);
                long endTime = System.currentTimeMillis();
                System.out.println("using more than one thread for bloom filters: " + (endTime - startTime) + " milliseconds");
                System.out.println("**Printing the results**");
                for(Future<ArrayList<Integer>> element: answers) {
                    ArrayList<Integer> arrInt = element.get();
                    for(Integer i: arrInt) {
                        System.out.print(i.intValue());
                        System.out.print("\t");
                    }
                    System.out.println("");
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
}

I did the profiling with jprofiler and

![here]:(http://tinypic.com/r/wh1v8p/6)

is a snapshot of cpu threads where red color shows blocked, green runnable and yellow is waiting. I problem is that threads are running one at a time I do not know why?

Note:I know that this is not thread safe but I know that I will only be doing read operations throughout now and just want to analyse raw performance gain that can be achieved, later I will implement a better version.

Upvotes: 0

Views: 1163

Answers (3)

Stephen C
Stephen C

Reputation: 719679

Can anyone please tell where I have missed

One possibility is that the cost of creating threads is swamping any possible performance gains from doing the computations in parallel. We can't really tell if this is a real possibility because you haven't included the relevant code in the question.

Another possibility is that you only have one processor / core available. Threads only run when there is a processor to run them. So your expectation of a linear speed with the number of threads and only possibly achieved (in theory) if is a free processor for each thread.

Finally, there could be memory contention due to the threads all attempting to access a shared array. If you had proper synchronization, that would potentially add further contention. (Note: I haven't tried to understand the algorithm to figure out if contention is likely in your example.)


My initial advice would be to profile your code, and see if that offers any insights.

And take a look at the way you are measuring performance to make sure that you aren't just seeing some benchmarking artefact; e.g. JVM warmup effects.

Upvotes: 2

Emil Sit
Emil Sit

Reputation: 23562

Several possibilities come to mind:

  • There is some synchronization going on inside bloomFilterInstance's implementation (which is not given).
  • There is a lot of memory allocation going on, e.g., what appears to be an unnecessary copy of an ArrayList when chkDataSet is created, use of new Integer instead of Integer.valueOf. You may be running into overhead costs for memory allocation.
  • You may be CPU-bound (if bloomFilterInstance#contains is expensive) and threads are simply blocking for CPU instead of executing.

A profiler may help reveal the actual problem.

Upvotes: 0

Jeanne Boyarsky
Jeanne Boyarsky

Reputation: 12266

That process looks CPU bound. (no I/O, database calls, network calls, etc.) I can think of two explanations:

  1. How many CPUs does your machine have? How many is Java allowed to use? - if the threads are competing for the same CPU, you've added coordination work and placed more demand on the same resource.
  2. How long does the whole method take to run? For very short times, the additional work in context switching threads could overpower the actual work. The way to deal with this is to make a longer job. Also, run it a lot of times in a loop not counting the first few iterations (like a warm up, they aren't representative.)

Upvotes: 0

Related Questions