[英]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
方法。
循环计数器和其他原始局部变量是线程安全的。 可使方法成为非线程安全的唯一方法是共享状态。 通过创建单独的CrucibleOptimizer
和PrintWriter
对象,您似乎已成功避免了这种情况。
我尝试的一种重构是合并您的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.