簡體   English   中英

線程工作結果出乎意料 - java

[英]threading work results are unexpected - java

我是多線程新手。 我正在開發一個程序,將一個包含許多記錄(300 萬個整數)的文件讀入某個鏈接列表,然后一些線程處理每個列表並計算列表的總和,找到最大值和最小值。 然后主線程比較子線程結果並顯示最終結果。

程序使用此命令:

計算 -f 文件路徑 -t 線程數

現在的問題是,當我用一個線程運行程序時,它比某些線程花費的時間少。

我的CPU是酷睿i7。

這是一段時間的結果:

(線程:持續時間)--> (1 : 16) , (2,3 : 32) , (4,5,6,7 : 47) , (8,9 : 31) ... (17,18,19 ,20 : 16)

該項目有2個項目:

工人階級:

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

主要類:

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

    }
}

為什么不使用執行器

使用參數 Integer.parseInt(map.get(“-t”)。trim())創建一個線程池 並且不再需要isAlive。 得出Future的概念。

線程池

未來

執行器-線程控制

例子

我認為,為了學習多線程,了解阿姆達爾定律很重要。 阿姆達爾定律可用於計算通過並行運行一部分計算可加速的計算量。 我不想過多地討論技術細節,因此您可以在Wikipedia上閱讀: https//en.wikipedia.org/wiki/Amdahl%27s_law

阿姆達爾定律從根本上說,並發計算的速度與線程數不是線性關系,線程數取決於處理器中的內核數(除非您的代碼進行網絡,IO等)。 因此,當您將線程數量加倍時,就不能指望程序將其速度提高一倍。

而且,Thread類與Java中的其他任何類一樣,將花費大量創建開銷,並且會占用大量資源。 因此,創建更多線程而沒有有效地僅對算術運算(JVM已經對其進行了非常優化)的輸入進行有效平衡時,將使程序的速度無法預測甚至變慢。

還有更多的問題需要考慮。 一個小建議是使用Java的ExecutorService類來管理您的線程。 快樂的編碼。

您“與眾不同”的結果很可能與JIT編譯器完成的優化有關

您的代碼在這里正在執行“某種基准測試”,具有可配置的線程數。 對於此類基准,建議使用JMH框架

如果您只是在學習多線程,建議您不要評估代碼的性能。 進行基准測試時,有很多事情要考慮,如果做不正確,將會導致意外的結果,例如您現在看到的結果。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM