Java线程 - 我在编写线程安全的代码吗?

时间:2014-08-14 16:33:18

标签: java multithreading image-processing colors

我目前正在努力进行并行处理,所以要做到这一点,我正在编写一个处理图像的程序,总体上提供有关其颜色值的信息 - 我正在对此进行一些测试具有随机生成的整数数组的类,并且运行4个线程来处理每个第4个像素,从它们各自的起始位置开始。我只是想知道这个读取是否是线程安全的?多个线程可以读取相同的数据结构,如果这是我想要的吗?

import java.awt.image.BufferedImage;
import java.lang.Thread;


public class ImageProcessor extends Thread {

    public static void main(String[] args) {

        int[] z = new int[10000000];
        for (int i = 0; i < 10000000; i++) {

            double a = (Math.random()*1000000);
            z[i] = (int) a;

        }

        ImageProcessor ip = new ImageProcessor();
        ip.imgRGBPercent(z);
    }


    public ImageProcessor() {

    }

    public void process(int[] x, int startPoint) {

        (new Thread(new ReadThread(x, startPoint))).start();    
    }

    public int[] imgRGBPercent(int[] x) {




        ReadThread first = new ReadThread(x, 0);
        ReadThread second = new ReadThread(x, 1);
        ReadThread third = new ReadThread(x, 2);
        ReadThread fourth = new ReadThread(x, 3);

        Thread a = (new Thread(first));
        Thread b = (new Thread(second));
        Thread c = (new Thread(third));
        Thread d = (new Thread(fourth));

        long timeMetric = System.currentTimeMillis();
        a.start();
        b.start();
        c.start();
        d.start();


        try {

            a.join();
        }
        catch (Exception e) {

        }

        try {

            b.join();
        }
        catch (Exception e) {

        }

        try {

            c.join();
        }
        catch (Exception e) {

        }

        try {

            d.join();
        }
        catch (Exception e) {

        }

        int redTotal, blueTotal, greenTotal;

        redTotal = first.getRGBTotals()[0] + second.getRGBTotals()[0] + third.getRGBTotals()[0] + fourth.getRGBTotals()[0];
        blueTotal = first.getRGBTotals()[1] + second.getRGBTotals()[1] + third.getRGBTotals()[1] + fourth.getRGBTotals()[1];
        greenTotal = first.getRGBTotals()[2] + second.getRGBTotals()[2] + third.getRGBTotals()[2] + fourth.getRGBTotals()[2];

        System.out.println(greenTotal);

        System.out.println(System.currentTimeMillis() - timeMetric);

        timeMetric = System.currentTimeMillis();

        ColorValue cv1 = new ColorValue();
        int sum = 0;
        int sum1 = 0;
        int sum2 = 0;
        for (int i = 0; i < x.length; i++) {

            sum += cv1.getGreen(x[i]);
            sum1 += cv1.getRed(x[i]);
            sum2 += cv1.getBlue(x[i]);
        }


        System.out.println(sum);

        System.out.println(System.currentTimeMillis() - timeMetric);

        int[] out = new int[3];
        return out;
    }


    private class ReadThread implements Runnable {

        private int[] colorArr;
        private int startPoint, redTotal, blueTotal, greenTotal;
        private ColorValue cv;

        public ReadThread(int[] x, int startPoint) {

            colorArr = x;
            this.startPoint = startPoint;
            cv = new ColorValue();
        }

        @Override
        public void run() {

            //System.out.println("hit");

            for (int i = startPoint; i < colorArr.length; i+=4 ) {
                redTotal += ColorValue.getRed(colorArr[i]);
                blueTotal += ColorValue.getBlue(colorArr[i]);
                greenTotal += ColorValue.getGreen(colorArr[i]);

            }   

        }

        public int[] getRGBTotals() {

            int[] out = new int[3];
            out[0] = redTotal;
            out[1] = blueTotal;
            out[2] = greenTotal;

            return out;
        }
    }

}

3 个答案:

答案 0 :(得分:2)

是。只要数据结构在被读取时未被修改,您就是安全的。启动线程之前完成的每个写操作都将由启动的线程显示。

答案 1 :(得分:0)

是的,多个线程可以读取相同的对象并且只要其他线程不同时修改它们就可以。根据您正在执行的操作Fork-Join framework可能有用,它会为您管理大量的线程详细信息,因此值得研究。

答案 2 :(得分:0)

这个逻辑会让我有点担心:

 for (int i = startPoint; i < colorArr.length; i+=4 ) {
     redTotal += ColorValue.getRed(colorArr[i]);
     blueTotal += ColorValue.getBlue(colorArr[i]);
     greenTotal += ColorValue.getGreen(colorArr[i]);
 }   

colorArr是对数组的引用;引用在构造函数期间传递给Runnable,但数组本身是在外部创建的。

在您发布的完整程序中,我不认为这是一个问题,因为在您启动主题之后,程序中的任何位置都不会修改此数组。但是在一个更大的,真实的世界中#34;如果有其他线程可以对colorArr[i]进行更改,则必须注意您已经三次阅读colorArr并且每次的值可能不一样。这是编写并发代码时必须注意的事项之一。这会好一点:

 for (int i = startPoint; i < colorArr.length; i+=4 ) {
     int color = colorArr[i];
     redTotal += ColorValue.getRed(color);
     blueTotal += ColorValue.getBlue(color);
     greenTotal += ColorValue.getGreen(color);
 }   

但是根据您的需求,您可能需要采取额外的步骤,以确保程序的任何部分都可以在整个循环运行时随时修改colorArr。然后你需要开始研究锁定对象和synchronized,并且你想要认真考虑为colorArr设置一个单独的类,以及用于修改和读取数组的方法synchronized方法或包含逻辑以确保事物正确同步 - 通过将数组放在自己的类中,所需的同步逻辑可以封装在该类中,因此类的客户端不必担心它。这是你开始使用并发时需要考虑的事情。