簡體   English   中英

包含循環的靜態方法是否是線程安全的?

[英]Is a static method containing loops thread-safe?

我有一個巨大的循環,我想分成4個線程。 我這樣做是使用一點笨拙的方法(或者可能不是嗎?),並將for循環的計數器分成4個間隔,為每個線程創建一個新的Printwriter和CrucibleOptimizer,這樣就不會出現沖突,如下所示:

    public static void main(String[] args) {
    Runnable run1 = new Runnable() {
        @Override
        public void run() {
            PrintWriter writer1;
            try {
                writer1 = new PrintWriter("test_result1.txt");
                CrucibleOptimizer optimizer1 = new CrucibleOptimizer();
                int[] loop1boundries = new int[]{1, 7};
                opt(optimizer1, writer1, loop1boundries[0], loop1boundries[1]);
            } catch (FileNotFoundException e) {
                System.out.println("File not found");
                e.printStackTrace();
            }
        }
    };
    Runnable run2 = new Runnable() {
        @Override
        public void run() {
            PrintWriter writer2;
            try {
                writer2 = new PrintWriter("test_result2.txt");
                CrucibleOptimizer optimizer2 = new CrucibleOptimizer();
                int[] loop2boundries = new int[]{8, 14};
                opt(optimizer2, writer2, loop2boundries[0], loop2boundries[1]);
            } catch (FileNotFoundException e) {
                System.out.println("File not found");
                e.printStackTrace();
            }
        }
    };
    Runnable run3 = new Runnable() {
        @Override
        public void run() {
            PrintWriter writer3;
            try {
                writer3 = new PrintWriter("test_result3.txt");
                CrucibleOptimizer optimizer3 = new CrucibleOptimizer();
                int[] loop3boundries = new int[]{15, 22};
                opt(optimizer3, writer3, loop3boundries[0], loop3boundries[1]);
            } catch (FileNotFoundException e) {
                System.out.println("File not found");
                e.printStackTrace();
            }
        }
    };
    Runnable run4 = new Runnable() {
        @Override
        public void run() {
            PrintWriter writer4;
            try {
                writer4 = new PrintWriter("test_result4.txt");
                CrucibleOptimizer optimizer4 = new CrucibleOptimizer();
                int[] loop4boundries = new int[]{23, 30};
                opt(optimizer4, writer4, loop4boundries[0], loop4boundries[1]);
            } catch (FileNotFoundException e) {
                System.out.println("File not found");
                e.printStackTrace();
            }
        }
    };
    Thread[] threads = new Thread[]{new Thread(run1), new Thread(run2), new Thread(run3), new Thread(run4)};
    for (Thread thr : threads){
        thr.start();
    }
}

這就是我要問的方法。 我不知道它的線程是否安全。 我一直在閱讀,谷歌說,就我沒有任何局部變量而言,我很好,但是讓我擔心的是那些循環中的多個計數器:

    public static void opt(CrucibleOptimizer opt, PrintWriter writer, int minIncluded, int maxIncluded){
    //more than this is never used
    final int oreMaterialsMaximum = 100;//100
    final int ingotMaterialMaximum = 30;//30

    //test for every possible material combination
    for (int a = minIncluded; a <= maxIncluded; a++){//for amount of ingots
        System.out.println("Testing for ingot number: " + a);
        double ratioMin = (Reference.UNITS_IMPOSSIBLE / (double)(a * Reference.UNITS_INGOT));
        for (int i = 0; i <= (int)(100 / Reference.UNITS_IMPOSSIBLE); i++){//for every ratio possible
            double currentRatio = round(i * ratioMin, 6);
            System.out.println("Testing for ratio: " + currentRatio);
            for (int b = 0; b <= ingotMaterialMaximum; b++){//with every amount of ingots
                for (int c = 0; c <= oreMaterialsMaximum; c++){//with every amount of rich ore
                    for (int d = 0; d <= oreMaterialsMaximum; d++){//with every amount of normal ore
                        for (int e = 0; e <= oreMaterialsMaximum; e++){//with every amount of poor ore
                            for (int f = 0; f <= oreMaterialsMaximum; f++){//with every amount of small ore
                                opt.set(null, null, null, a); //only the ingots are passed in this way
                                int[] res = opt.optimizeMaterial(new int[]{c, d, e, f, b}, currentRatio);
                                if (res != null){
                                    int units = 0;
                                    for (int j = 0; j < res.length; j++)
                                        units += res[j] * Reference.MATERIAL_UNITS[j];
                                    double unitsRight = Math.round(a * Reference.UNITS_INGOT * currentRatio);
                                    if (units != (int)unitsRight){ //if the units are not correct, log
                                        writer.println("I: " + a + " Rat: " + currentRatio + " I_av: " + b + " O_Ri: " + c + " O_No: " + d +
                                                " O_Po: " + e + " O_Sm: " + f + " units_wrong: " + units + " units_right: " + (int)unitsRight);
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
    System.out.println("Testing done");
    writer.close();
}

“不要使用靜態變量”建議確實太簡單了:另一個要求是不要將共享對象傳遞給在不同線程中運行的static方法。

循環計數器和其他原始局部變量是線程安全的。 可使方法成為非線程安全的唯一方法是共享狀態。 通過創建單獨的CrucibleOptimizerPrintWriter對象,您似乎已成功避免了這種情況。

我嘗試的一種重構是合並您的Runnable 創建一個具有循環邊界的命名類,並在main中創建該類的四個實例。 這將比四個幾乎沒有什么區別的獨立匿名類更好:

private static class ThreadRunnable implements Runnable {
    final String fileName;
    final int[] loopBoundaries;
    public ThreadRunnable(String fn, int[] lb) {
        fileName = fn;
        loopBoundaries = lb;
    }
    @Override
    public void run() {
        PrintWriter pw;
        try {
            pw = new PrintWriter(fileName);
            CrucibleOptimizer co = new CrucibleOptimizer();
            opt(co, pw, loop4boundries[0], loop4boundries[1]);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
    }
}

現在,您可以制作四個共享相同代碼的ThreadRunnable實例。

循環本身是線程安全的,所以不,您不必擔心。

您唯一需要擔心的是可能同時被多個線程訪問的任何內容。

但是,您的整個體系結構確實需要一些工作。

例如,為什么對可運行對象有4個單獨的實現,而不是有一個實現並將參數傳遞到其中以說出要處理的塊,為什么呢?

我也不知道您要對所有循環執行什么操作,但是您真的不太需要這樣的結構。

暫無
暫無

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

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