首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >同步错误-多线程访问的ArrayList

同步错误-多线程访问的ArrayList
EN

Stack Overflow用户
提问于 2022-01-27 04:19:52
回答 2查看 112关注 0票数 0

这是用java写的。我的程序的目的是采取屏幕截图的计算机屏幕多次每秒,并找到所有像素有一个特殊的阴影红色。然后,找出所有红色像素的平均位置。

为了提高图像处理的效率,我创建了3个线程,每个线程处理像素的1/4。因此,这些线程加上原始线程将处理所有像素。但是,我一直在avgLocation()方法中得到一个错误。这是一个空指针异常,我认为这是因为其他线程改变了包含所有红色像素的列表的大小,这导致程序访问一个不存在的像素的数据。为了弥补这个问题,我在Thread1上使用了.join,在Thread3 2的代码之后使用了Thread2,然后在它的代码段之后使用了.join。因此,在我调用avgLocation方法之前,所有的线程都应该连接起来,但是每当屏幕上出现特定的红色时,它仍然会给出一个NullPointerException。这是堆栈跟踪

代码语言:javascript
复制
Exception in thread "main" java.lang.NullPointerException
    at Images.avgLocation(Images.java:151)
    at Images.processImage(Images.java:133)
    at Images.main(Images.java:169)

第151行是

代码语言:javascript
复制
                xSum += list.get(i)[0];

第133行是我的代码:

代码语言:javascript
复制
import java.awt.AWTException;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.Robot;
import java.awt.Toolkit;
import java.awt.image.BufferedImage;
import java.awt.image.DataBufferInt;
import java.util.ArrayList;

public class Images {
    //takes in an input image and a target color and a bound to check within, returns Point to target
        public static Point processImage(BufferedImage img, Color color, int error) throws InterruptedException  {
            long start = System.nanoTime();
            //bounds to check on color components, make sure all within [0,255]
            int redLower = color.getRed() - error;
            int redHigher =  color.getRed() + error;
            int greenLower = color.getGreen() - error;
            int greenHigher =  color.getGreen() + error;
            int blueLower = color.getBlue() - error;
            int blueHigher =  color.getBlue() + error;
            
            //place all components within [0,255]
            if (redLower < 0) redLower = 0;
            if (redHigher > 255) redHigher = 255;
            if (greenLower < 0) greenLower = 0;
            if (greenHigher > 255) greenHigher = 255;
            if (blueLower < 0) blueLower = 0;
            if (blueHigher > 255) blueHigher = 255;
            
            //create final variables to use for thread
            int redLowerF = redLower;
            int redHigherF =  redHigher;
            int greenLowerF = greenLower;
            int greenHigherF =  greenHigher;
            int blueLowerF = blueLower;
            int blueHigherF =  blueHigher;
            
            //data of image
            int[] pixels = ((DataBufferInt)img.getRaster().getDataBuffer()).getData();
            int width = img.getWidth();
            int height = img.getHeight();
            
            //stores locations
            ArrayList <Integer[]> locations = new ArrayList <>();
            for (int i = 0; i < pixels.length/4; i++) {
                int p = pixels[i];
                              
                // get red
                int r = (p >> 16) & 0xff;
          
                // get green
                int g = (p >> 8) & 0xff;
          
                // get blue
                int b = p & 0xff;
                
                //check if all components within bounds
                if (r >= redLower && r<=redHigher && g>=greenLower && g <= greenHigher && b >= blueLower && b <= blueHigher) {              
                    Integer[] point = {i % height, i/height};
                    locations.add(point);
                }
            }
            Thread thread1 = new Thread( ()  -> {
                for (int i = pixels.length/4; i < pixels.length/2; i++) {
                    int p = pixels[i];
                                  
                    // get red
                    int r = (p >> 16) & 0xff;
              
                    // get green
                    int g = (p >> 8) & 0xff;
              
                    // get blue
                    int b = p & 0xff;
                    
                    //check if all components within bounds
                    if (r >= redLowerF && r<=redHigherF && g>=greenLowerF && g <= greenHigherF && b >= blueLowerF && b <= blueHigherF) {                
                        Integer[] point = {i % height, i/height};
                        locations.add(point);
                    }
                }
            });
            thread1.start();
            Thread thread2 = new Thread( ()  -> {
                for (int i = pixels.length/2; i < pixels.length*3/4; i++) {
                    int p = pixels[i];
                                  
                    // get red
                    int r = (p >> 16) & 0xff;
              
                    // get green
                    int g = (p >> 8) & 0xff;
              
                    // get blue
                    int b = p & 0xff;
                    
                    //check if all components within bounds
                    if (r >= redLowerF && r<=redHigherF && g>=greenLowerF && g <= greenHigherF && b >= blueLowerF && b <= blueHigherF) {                
                        Integer[] point = {i % height, i/height};
                        locations.add(point);
                    }
                }
            });
            thread2.start();
            thread1.join();
            thread2.join();
            Thread thread3 = new Thread( ()  -> {
                for (int i = pixels.length*3/4; i < pixels.length; i++) {
                    int p = pixels[i];
                                  
                    // get red
                    int r = (p >> 16) & 0xff;
              
                    // get green
                    int g = (p >> 8) & 0xff;
              
                    // get blue
                    int b = p & 0xff;
                    
                    //check if all components within bounds
                    if (r >= redLowerF && r<=redHigherF && g>=greenLowerF && g <= greenHigherF && b >= blueLowerF && b <= blueHigherF) {                
                        Integer[] point = {i % height, i/height};
                        locations.add(point);
                    }
                }
            });
            thread3.start();
            thread3.join();
            long end = System.nanoTime();
            System.out.println((end-start)/1000000);
            return avgLocation(locations);  
        }
        //given 2D array of locations, finds average location of set and returns as point
        public static Point avgLocation (ArrayList<Integer[]> list) {
            //if no points in list, return an impossible point on screen
            if (list.size() == 0) {
                return new Point (-100, -100);
            }
            //coordinates of average location (set to 100 to reveal bug easily)
            int avgX = 100;
            int avgY = 100;
            
            int xSum = 0;
            int ySum = 0;
            
            //loop through array
            for (int i = 0; i < list.size(); i++) {
                //for each location, add up coordinates
                xSum += list.get(i)[0];
                ySum += list.get(i)[1];
            }
            avgX = xSum/list.size();
            avgY = ySum/list.size();
            return new Point (avgX, avgY);
        }
        public static void main (String[] args) {
            Robot robot = null;
            try {
                robot = new Robot();
            } catch (AWTException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            Dimension d = Toolkit.getDefaultToolkit().getScreenSize();
            while (true) {
                try {
                    processImage(robot.createScreenCapture(new Rectangle(0,0,d.width,d.height)), new Color (255, 0, 0), 10);
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                } 
            }
        }
}
EN

回答 2

Stack Overflow用户

发布于 2022-01-27 06:01:20

线程通过添加新元素同时修改和更改locations ArrayListArrayList不适合在没有同步的情况下进行这种并发修改。但是,有一些CopyOnWriteArrayList可以支持并发修改而不需要同步。

试着更换线路:

代码语言:javascript
复制
ArrayList<Integer[]> locations= new ArrayList<>();

行如下:

代码语言:javascript
复制
final List<Integer []> locations = new CopyOnWriteArrayList<>();
票数 2
EN

Stack Overflow用户

发布于 2022-01-27 06:07:25

ArrayList不是线程安全的

创建一个类似于

代码语言:javascript
复制
    static private void addToList (ArrayList<Integer[]> list, Integer [] p) {
        synchronized (list) {
            list.add(p);
        }
    }

可以在你的线程中调用,就像

代码语言:javascript
复制
Image.addToList(locations, point);
票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/70873304

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档