我正在尝试理解线程,所以我制作了一个简单的程序。我从文件中读取数字,我将它们放入一个数组中,然后对于数组中的每个元素,我将它自身相乘,然后,当遍历整个数组时,我将它写入文件。我为这个程序使用了n个线程。问题是,不是每次我得到我期望的答案。例如:
数字:2 3 4 1 1 4 输出:4 9 16 1 1 16 - 正确
有时我会得到相同的数字: 输出:16 81 256 1 1 256 - 显然不是我想要的。
以下是源代码:
类MyThread2,它使乘法:
package thr;
import java.util.ArrayList;
public class MyThread2 extends Thread{
private ArrayList<Integer> array;
public MyThread2(ArrayList<Integer> a){
array = a;
}
public void run(){
for(int i=0; i < array.size(); i++){
synchronized (this) {
array.set(i, array.get(i) * array.get(i));
}
}
}
};
class App - 应用程序
package thr;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
public class App {
public ArrayList<Integer> readFromFile(String str){
ArrayList<Integer> a = new ArrayList<Integer>();
try{
BufferedReader reader = new BufferedReader(new FileReader(str));
String message = null;
while((message = reader.readLine()) != null){
try{
int nr = Integer.parseInt(message);
a.add(nr);
}catch(NumberFormatException e){
System.out.println(e.getMessage());
}
}
reader.close();
}catch(IOException e){
System.out.println(e.getMessage());
}
return a;
}
public void writeToFile(ArrayList<Integer> a){
try{
BufferedWriter writer = new BufferedWriter(new FileWriter("output.txt"));
for(int i=0; i < a.size(); i++){
writer.write(a.get(i).toString());
writer.newLine();
}
writer.close();
}catch(IOException e){
System.out.println(e.getMessage());
}
}
public ArrayList<Integer> runThreads(ArrayList<Integer> a, int nrThreads) {
ArrayList<MyThread2> thread = new ArrayList<MyThread2>();
int i;
for(i=0; i < nrThreads; i++){
thread.add(new MyThread2(a));
}
for (i = 0; i < thread.size(); i++) {
thread.get(i).start();
}
System.out.println("in fctie");
print(a);
System.out.println("in fctie");
return a;
}
public void print(ArrayList<Integer> array){
for(int i=0; i < array.size(); i++){
System.out.println(array.get(i));
}
}
public static void main(String[] args){
App app = new App();
ArrayList<Integer> array;
array = app.readFromFile("numbers.txt");
app.print(array);
app.runThreads(array, 5);
app.print(array);
app.writeToFile(array);
}
}
有谁知道我做错了什么?
答案 0 :(得分:3)
您的代码中存在许多问题。
首先:您的main方法启动N个线程,然后打印并保存所有这些线程正在修改的列表内容。你不是在等待线程完成,所以主线程和所有MyThread2线程以不可预测的方式同时访问列表。
第二:有0同步。您进行同步的唯一地方是
synchronized (this) {
array.set(i, array.get(i) * array.get(i));
}
因此每个线程自身同步。所有线程都使用单独的锁,因此可以同时访问线程不安全列表。这有点像你有一个10门和10个钥匙的安全锁:在这样的设计中,10个人可以同时打开锁。您需要的是一扇门和一把钥匙。
答案 1 :(得分:2)
多个线程同时执行相同的操作。因此,每次运行时,您将根据哪些线程在哪些时间运行(这不是确定性的)来获得不同的答案。
请注意,您的同步在for循环中,这意味着每个线程将独立于同步循环。此外,您正在同步this
这意味着线程的每个实例仅与其自身同步,即根本没有同步。您可以在公共监视器对象上进行循环外同步。但是,这当然会导致每个Thread连续执行操作。但至少你的结果是确定性的。
如果你想对数组中的每个元素只进行一次乘法,那么你应该以多线程方式使用要处理的数组的特定 slice 初始化每个Thread。