简体   繁体   English

包含循环的静态方法是否是线程安全的?

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

I have a huge loop that I wanted to split up into 4 threads. 我有一个巨大的循环,我想分成4个线程。 I've done so using a little bit noobish method(or maybe not?) and split up the counter of the for loops into 4 intervals, created a new Printwriter, and CrucibleOptimizer for each thread so that there are no conflicts, like this: 我这样做是使用一点笨拙的方法(或者可能不是吗?),并将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();
    }
}

And this is the method that I'm asking about. 这就是我要问的方法。 I don't know if its thread safe. 我不知道它的线程是否安全。 I've been reading around and google says that as far as I don't have any local variables, I'm fine, but what concerns me is the multiple counters in those loops: 我一直在阅读,谷歌说,就我没有任何局部变量而言,我很好,但是让我担心的是那些循环中的多个计数器:

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

The "do not use static variables" advise is indeed too simplistic: the other requirement is to not pass shared objects to static methods running in different threads. “不要使用静态变量”建议确实太简单了:另一个要求是不要将共享对象传递给在不同线程中运行的static方法。

Loop counters and other primitive local variables are thread-safe. 循环计数器和其他原始局部变量是线程安全的。 The only thing that could make a method non-thread safe is shared state. 可使方法成为非线程安全的唯一方法是共享状态。 It appears that you have successfully avoided that by creating separate CrucibleOptimizer and PrintWriter objects. 通过创建单独的CrucibleOptimizerPrintWriter对象,您似乎已成功避免了这种情况。

One refactoring that I would attempt is combining your Runnable s. 我尝试的一种重构是合并您的Runnable Make a named class that takes loop boundaries, and make four instances of that class in your main . 创建一个具有循环边界的命名类,并在main中创建该类的四个实例。 This would work better than four separate anonymous classes that have very few differences: 这将比四个几乎没有什么区别的独立匿名类更好:

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

Now you can make four ThreadRunnable instances which share identical code. 现在,您可以制作四个共享相同代码的ThreadRunnable实例。

Loops in of themselves are thread safe, so no you don't need to worry about that. 循环本身是线程安全的,所以不,您不必担心。

The only thing you need to worry about is anything that might be accessed by multiple threads at once. 您唯一需要担心的是可能同时被多个线程访问的任何内容。

However your entire architecture really needs some work. 但是,您的整个体系结构确实需要一些工作。

For example why have 4 separate implementations for the runables rather than having one implementation and passing parameters into it to say which chunk to work on. 例如,为什么对可运行对象有4个单独的实现,而不是有一个实现并将参数传递到其中以说出要处理的块,为什么呢?

I also don't know what you are trying to do with all the loops but it's highly unlikely you really need any structure like that. 我也不知道您要对所有循环执行什么操作,但是您真的不太需要这样的结构。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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