简体   繁体   中英

How to merge arrays in Java Fork-Join multithreaded program?

I built a median filter and basically what it does it grabs an array of elements, filters it and returns a filtered array. Now, the sequential version works perfectly but on trying to make a Fork-Join version, I cannot get any result for arrays greater than my Sequential Threshold and it is also accompanied with ArrayIndexOutOfBounds errors.

Now, I'm not sure where I'm going wrong and after hours of research around Google and SO, I am giving up and decided to post the question here.

Here's my code snippet that does the filtering Sequentially:

//Filter Algorithm.
    private void filter(BigDecimal[] elements, int shoulder) {
        //Add boundary values in beginning
        for(int i=0; i<shoulder; i++){
            filteredElements[i] = elements[i];
        }

        //Add boundary values at end
        for(int i=arraySize-1; i>((arraySize-1) - shoulder); i--){
            filteredElements[i] = elements[i];
        }

        //Add middle values to filteredElements array
        for (int i = shoulder; i < elements.length-shoulder; i++) {
            BigDecimal[] windowValue = prepareWindow(elements, shoulder, filterSize);
            BigDecimal median = getMedian(windowValue);
            filteredElements[i] = median;
        }
    }


    /*
     * Pre-condition: Get Windowed Array
     * Post-Condition: Return Median
     */
    private static BigDecimal getMedian(BigDecimal[] windowValue) {
        Arrays.sort(windowValue);
        return windowValue[(filterSize-1)/2];
    }


    /*
     * Pre-condition: Get elements array, get shoulder value and length of filterSize. Notice that this is given name windowLength.
     * Post-Condition: Return Windowed Array
     */
    private static BigDecimal[] prepareWindow(BigDecimal[] elements, int shoulder, int windowLength) {
        BigDecimal[] out = new BigDecimal[windowLength];
        int outCounter = 0;
        for(int i = position; i<position+filterSize; i++){
            out[outCounter] = elements[i];
            outCounter++;
        }
        position++;
        return out;
    }


    //Return Filtered Array
    public BigDecimal[] getFilteredArray(){
        return filteredElements;
    }

Now, the same sequential code applied in a Fork-Join does not work if the array is larger than the sequential threshold and I would like to know where I'm going wrong here.

Here's a snippet for my Parallel implementation:

import java.math.BigDecimal;
import java.util.Arrays;
import java.util.concurrent.RecursiveTask;

public class Parallel extends RecursiveTask<BigDecimal[]>{
    BigDecimal[] elements;
    BigDecimal[] filteredElements; //Array that contains the filtered elements
    int shoulder;
    static int filterSize;  
    int begin;
    int end;
    static int position = 0;
    static final int SEQUENTIAL_CUTOFF = 4;


    public Parallel(BigDecimal[] elements, int filterSize, int begin, int end) {
        this.elements = elements;
        Parallel.filterSize = filterSize;
        this.begin = begin;
        this.end = end;
        filteredElements = new BigDecimal[elements.length]; //Array that contains the filtered elements
        shoulder = (filterSize - 1) / 2;
    }

    @Override
    protected BigDecimal[] compute() {

        if (end - begin <= SEQUENTIAL_CUTOFF) {                         
            filter(elements, shoulder); //Run Filter Method
        }else{
            Parallel curLeft = new Parallel(elements, filterSize, this.begin, ((this.begin+this.end)/2));
            Parallel curRight = new Parallel(elements, filterSize, ((this.begin+this.end)/2), this.end);
            curLeft.fork();
            curRight.compute();
            curLeft.join();

        }
        return filteredElements;
    }

    //Filter Algorithm.
        private void filter(BigDecimal[] elements, int shoulder) {          
            //Add boundary values in beginning
            for(int i=0; i<shoulder; i++){
                filteredElements[i] = elements[i];
            }

            //Add boundary values at end
            for(int i=this.elements.length-1; i>((this.elements.length-1) - shoulder); i--){
                filteredElements[i] = elements[i];
            }

            //Add middle values to filteredElements array
            for (int i = shoulder; i < elements.length-shoulder; i++) {
                BigDecimal[] windowValue = prepareWindow(elements, shoulder, filterSize);
                BigDecimal median = getMedian(windowValue);
                filteredElements[i] = median;
            }
        }


        /*
         * Pre-condition: Get Windowed Array
         * Post-Condition: Return Median
         */
        private static BigDecimal getMedian(BigDecimal[] windowValue) {
            Arrays.sort(windowValue);
            return windowValue[(filterSize-1)/2];
        }   


        /*
         * Pre-condition: Get elements array, get shoulder value and length of filterSize. Notice that this is given name windowLength.
         * Post-Condition: Return Windowed Array
         */
        private static BigDecimal[] prepareWindow(BigDecimal[] elements, int shoulder, int windowLength) {
            BigDecimal[] out = new BigDecimal[windowLength];
            int outCounter = 0;
            for(int i = position; i<position+filterSize; i++){
                out[outCounter] = elements[i];
                outCounter++;
            }
            position++;
            return out;
        }

      //Return Filtered Array
        public BigDecimal[] getFilteredArray(){
            return filteredElements;
        }

}

Basically the Parallel implementation uses the sequential methods I made but I can't get it to work. Below is a list of errors I'm getting(I added the lines that are causing the errors to make reading easier. Most of the errors are in the sequential methods and I don't understand why):

Caused by: java.lang.ArrayIndexOutOfBoundsException: 8
    at Parallel.prepareWindow(Parallel.java:80)  > out[outCounter] = elements[i];
    at Parallel.filter(Parallel.java:55) > BigDecimal[] windowValue = prepareWindow(elements, shoulder, filterSize);
    at Parallel.compute(Parallel.java:29) > filter(elements, shoulder); //Run Filter Method
    at Parallel.compute(Parallel.java:34) > curRight.compute();

Would really appreciate if someone could help with a meaningful answer.

Thanks.

We cannot see the whole code, but I see that somehow two compute() are called in parallel and they call prepareWindow() concurrently.

The big problem is that position is a static variable and both thread are incrementing the same reference, pushing it out of bounds.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM