简体   繁体   中英

threading work results are unexpected - java

i am new at multi threading. i am working on a program to read a file with many records (3 million integer numbers) into some linked list and then some threads work on each list and calculate the sum of the list, finding the maximum and minimum. then the main thread compares the child thread results and display the final results.

program work with this command:

compute -f file_path -t threads_Number

Now the problem is when i run the program with one thread it takes less time than some threads.

my CPU is core i7.

this is some time results:

(Threads : duration) --> (1 : 16) , (2,3 : 32) , (4,5,6,7 : 47) , (8,9 : 31) ... (17,18,19,20 : 16)

the project have 2 projects:

Worker class:

public class Worker implements Runnable {

    private List<Integer> records;
    private long[] res;
    private String name;

    Worker(String name, LinkedList<Integer> list, long[] res) {
        this.records = list;
        this.res = res;
        this.name = name;
    }

    @Override
    public void run() {

        long startTime = System.currentTimeMillis();
        long sum = 0;
        int max, min;

        if (records != null && records.size() > 0) {
            max = min = records.get(0);

            for (Integer num : records) {
                sum += num;
                if (num > max)
                    max = num;
                if (num < min)
                    min = num;
            }

            long endTime = System.currentTimeMillis();
            long duration = endTime - startTime;

            res[0] = sum;
            res[1] = max;
            res[2] = min;
            res[3] = duration;

            System.out.println(name + "\t->\ttime:\t" + duration + "\t, Records:\t" + records.size());
        }
    }
}

Main class:

public class Main {

    public static void main(String[] args) {
        //read command and get inputs:
        System.out.println("Welcome to my app : ");

        while (true) {

            Scanner scanner = new Scanner(System.in);
            String command = scanner.nextLine().trim();
            if (command.startsWith("compute")) {
                command = command.substring("compute".length() + 1);
                args = command.split(" ");
            } else {
                System.out.println("wrong command.. this app only support 'compute'");
                exit(1);
            }

            Map<String, String> map = new HashMap<>(); //-p processes , -f filepath
            for (int i = 0; i < args.length - 1; i += 2)
                map.put(args[i], args[i + 1]);

            File txtFile = new File(map.get("-f").trim());
            final int threadCount = Integer.parseInt(map.get("-t").trim());

            ArrayList<LinkedList<Integer>> lists = readFile(txtFile, threadCount);
            if (lists == null) {
                System.out.println("Error: can not found txt file..");
                exit(2);
            }

            long[][] results = new long[threadCount][4];
            Thread[] thread = new Thread[threadCount];

            for (int i = 0; i < threadCount; i++) {
                thread[i] = new Thread(new Worker("thread " + (i + 1) ,lists.get(i), results[i]));
                thread[i].start();
            }

            boolean isAlive = true;
            while (isAlive) {
                isAlive = false;
                for (int i = 0; i < threadCount; i++)
                    isAlive |= thread[i].isAlive();
            }

            long[] res = null;
            for (long[] result : results) {
                if (res != null) {
                    res[0] += result[0];
                    if (res[1] < result[1])
                        res[1] = result[1];
                    if (res[2] > result[2])
                        res[2] = result[2];
                    if (res[3] < result[3])
                        res[3] = result[3];
                } else {
                    res = result;
                }
            }

            if (res != null) {
                System.out.println("sum : " + res[0]);
                System.out.println("max : " + res[1]);
                System.out.println("min : " + res[2]);
                System.out.println("duration : " + res[3]);
            }

        }
    }

    private static ArrayList<LinkedList<Integer>> readFile(File txtFile, int procCount) {
        if(!txtFile.exists() || txtFile.isDirectory())
            return null;

        ArrayList<LinkedList<Integer>> arrayList = new ArrayList<>();

        for(int i = 0; i < procCount; i++)
            arrayList.add(new LinkedList<>());

        try {
            int index = 0;
            BufferedReader bufferedReader = new BufferedReader(new FileReader(txtFile));
            String line;
            while ((line = bufferedReader.readLine()) != null) {
                arrayList.get(index).add(Integer.parseInt(line));
                index++;
                if(index == procCount)
                    index = 0;
            }

            return arrayList;
        }   catch (IOException e) {
            e.printStackTrace();
            return null;
        }

    }
}

Why do you not use Executors ?

With the argument Integer.parseInt(map.get("-t").trim()) you create a Pool of Threads . And isAlive is not longer required. And the results the concept of Future .

Threads Pool

Future

Executors - Threads Control

Examples

I think in order to learn multi-threading it is important to know about the Amdahl's law. Amdahl's law can be used to calculate how much a computation can be sped up by running part of it in parallel. I don't want to go too much into the technical detail so you can read about it on Wikipedia: https://en.wikipedia.org/wiki/Amdahl%27s_law

Amdahl's law basically says the speedup of concurrent computing is not linear to the number of your threads, which are dependent on the number of cores in your processor (Unless your code does networking, IO, etc.). Hence you can not expect your program to double it speeds when you double your number of threads.

Moreover the class Thread, like any other class in java would take a lot of overhead to be created and will take a lot of resource. Therefore creating more threads without efficiently balancing the input for only arithmetic operations (which are already very optimized by the JVM) will make the speed of your program unpredictable or even slower.

There are lots more problems which are needed to considered. A little suggest is using the class ExecutorService of Java to manage your threads. Happy coding.

Your 'out of the ordinary' results most probably have to do with optimizations done by the JIT compiler

Your code is doing 'kind of a benchmark' here, with a configurable number of threads. For such benchmarks it's recommended to use the JMH framework .

In case you are just learning multi-threading, I recommend you avoid measuring the performance of you code. There are lots of things to be considered when doing benchmarks, and failing to do them right will result in unexpected result, such as the one you are seeing now.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM