同步线程无法正常工作

时间:2014-01-07 22:17:30

标签: java multithreading

我正在尝试理解线程,所以我制作了一个简单的程序。我从文件中读取数字,我将它们放入一个数组中,然后对于数组中的每个元素,我将它自身相乘,然后,当遍历整个数组时,我将它写入文件。我为这个程序使用了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);
    }

}

有谁知道我做错了什么?

2 个答案:

答案 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。