在Java中并行化快速排序时,线程永远不会返回join()。为什么?

在Java中并行化快速排序时,线程永远不会返回join()。为什么?,java,multithreading,parallel-processing,quicksort,Java,Multithreading,Parallel Processing,Quicksort,我用Java编写了并行化快速排序算法的简单代码,在运行方法中,我每次都创建两个独立的新线程,用于并行处理数组元素。但是,当它遇到两个创建的线程的join()语句时,线程从未返回并停止join(),似乎join()从未释放它们 下面是代码 class StartJoinQuickSort implements Runnable { private int m_Low, m_High; private int[] m_Array = null; private final

我用Java编写了并行化快速排序算法的简单代码,在运行方法中,我每次都创建两个独立的新线程,用于并行处理数组元素。但是,当它遇到两个创建的线程的join()语句时,线程从未返回并停止join(),似乎join()从未释放它们

下面是代码

class StartJoinQuickSort implements Runnable 
{
    private int m_Low, m_High;
    private int[] m_Array = null;

    private final static int NR_OF_VALUES = 10; // TOTAL_NO_VALUES
    private int PivotElement;   
    private static Random m_random = new Random( );


    public StartJoinQuickSort(int[] a_Array,int a_Low,int a_High)
    {
        this.m_Array = a_Array;
        this.m_Low = a_Low;
        this.m_High = a_High;
    }
    private void SwapArrayElements(int a_i,int a_j)
    {
        int temp = this.m_Array[a_i];
        this.m_Array[a_i] = this.m_Array[a_j];
        this.m_Array[a_j] = temp;

    }// end of SwapArrayElements

    private static int nextRandomFunctionValue(int aStart, int aEnd)
    {
        if ( aStart > aEnd )
        {
           throw new IllegalArgumentException("Start cannot exceed End.");
        }

        //get the range, casting to long to avoid overflow problems
        long range = (long)aEnd - (long)aStart + 1;

        // compute a fraction of the range, 0 <= frac < range

        long fraction = (long)(range * m_random.nextDouble());
        int randomNumber =  (int)(fraction + aStart);    
        return randomNumber;

    }// end of nextRandomFunctionValue

    private static int[] GetArrayWithRandomValues()
    {
        int[] ArrayToBePopulatedWithRandomValues  = new int[NR_OF_VALUES];
        for(int index =0; index<NR_OF_VALUES;index++)
        {
            int RandomValue = StartJoinQuickSort.nextRandomFunctionValue(0,NR_OF_VALUES);
            ArrayToBePopulatedWithRandomValues[index] =  RandomValue;

        }//end of for

        return ArrayToBePopulatedWithRandomValues;

    }//end of GetArrayWithRandomValues
    private int middleIndex(int left, int right) 
    {
        return left + (right - left) / 2;
    }
    public int Partition(int a_Start,int a_end)
    {
    //  System.out.println("Partition ..thId : " + Thread.currentThread().getId());
        int pivotIndex = 0;

        int i = a_Start;
        int j = a_end;

        try
        {
            pivotIndex = middleIndex(a_Start , a_end);
            this.PivotElement = this.m_Array[pivotIndex];

            do
            {
                while(this.m_Array[i] < PivotElement )
                    i++;

                if(j>0)
                {
                    try
                    {
                        while( this.m_Array[j] > PivotElement )
                            j--;
                    }
                    catch(Exception ex){System.out.println(" j : " + j);}

                }//end of if

                if(i<=j)
                {
                    SwapArrayElements(i,j);

                //  System.out.println("Swap .." + + Thread.currentThread().getId());

                    i++;
                    j--;

                }//end of if

            }while(i<=j);
        }
        catch(Exception except)
        {
            System.out.println("exception in Partition " + except);
        }
        return j;
    }

    public void run()  
    {

        //System.out.println("in run..");


        //System.out.println("after PARTITION");

        StartJoinQuickSort oStartQuickSort_1 = null;
        StartJoinQuickSort oStartQuickSort_2 = null;



        if(this.m_Low < this.m_High )
        {
            int Index = Partition(this.m_Low,this.m_High);



            Thread thPart_1 = new Thread ( new StartJoinQuickSort( this.m_Array,this.m_Low,Index ) );
            Thread thPart_2 = new Thread ( new StartJoinQuickSort( this.m_Array,Index + 1,this.m_High ) );

            thPart_1.start();   thPart_2.start();


        //}//end of if
        //if( Index + 1 < this.m_High)
        //{         
            try
            {           
                    thPart_1.join(); thPart_2.join();

            }catch (InterruptedException e) { e.printStackTrace();}         
        }
    }//end of run
类StartJoinQuickSort实现可运行
{
私人国际货币单位低,货币单位高;
私有int[]m_数组=null;
private final static int NR_OF_VALUES=10;//总计没有值
私有int数据透视元素;
私有静态随机m_Random=new Random();
公共StartJoinQuickSort(int[]数组,int a_低,int a_高)
{
this.m_数组=a_数组;
这个m_Low=a_Low;
这个m_高=a_高;
}
私人空间交换要素(int a_i,int a_j)
{
int temp=这个.m_数组[a_i];
this.m_数组[a_i]=this.m_数组[a_j];
这个.m_数组[a_j]=temp;
}//Swaparlayements结束
私有静态int nextRandomFunctionValue(int aStart、int aEnd)
{
如果(aStart>aEnd)
{
抛出新的IllegalArgumentException(“开始不能超过结束”);
}
//获得射程,长距离施放以避免溢出问题
长距离=(长)方向-(长)方向+1;
//计算范围的一小部分(0个元素)
j--;
}
catch(异常ex){System.out.println(“j:+j);}
}//if结束

如果(ijoin()如果你的线程没有完成,就会阻塞。你需要确定为什么你的线程没有完成。你能试着用调试器调试你的程序吗?

如果你有低=0,高=1,会发生什么?如果你的分区返回1,你将有一个无限的线程循环,对吗?

Hmmm,实现递归算法从来都不是一个好主意与此并行,您最终将创建大量线程(每个级别都是指数级的),并最终超额订阅系统

最好的办法是设置一个截止点,比如说,它等于可用内核的数量。然后,当当前递归级别的分支数量等于截止点时,切换到顺序快速排序。流的一些非常粗糙的伪代码:

parallel_quicksort(level, interval) {
    // compute subintervals interval1, interval2
    if(level < cutoff) { 
        spawn1: parallel_quicksort(level + 1, interval1);
        spawn2: parallel_quicksort(level + 1, interval2);

        join1();     
        join2();
    } else {
        quicksort(interval1);
        quicksort(interval2);
    }
}
并行快速排序(级别、间隔){ //计算子区间间隔1,间隔2 如果(电平<截止值){ 第1级:并行快速排序(级别+1,间隔1); 第2级:并行快速排序(级别+1,间隔2); join1(); join2(); }否则{ 快速排序(间隔1); 快速排序(间隔2); } }

还可以查看此实现,看看您是否遗漏了什么:

谢谢大家的建议和建议。 我自己发现了这个问题,是配分函数的问题,它有一些问题,我选择了另一个,它对我来说很好

新的分区程序是:

公共int分区(int[]a_数组,int a_左,int a_右) { //为轴心选择范围的中间值 int pivotValue=a_数组[middleIndex(a_左,a_右)]

——左一;
++是的;
while(true)
{
做
++a_左;
while(a_数组[a_Left]pivotValue);
if(左a_<右a_)
Swaparlayements(左a_,右a_);
其他的
{
返回一个_的权利;
}
}
}

BTW,这是一种非常幼稚的并行快速排序方法。创建所有线程所花费的时间将超过并行化所获得的时间。有关使用JDK7的新ForkJoinPool的解决方案,请参阅。我已经完成了ForkJoin,但我希望这部分完成(幼稚的方式)。恐怕您需要向我们展示
StartJoinQuickSort
的源代码,以便我们能够告诉我们为什么它永远不会结束。还有
分区
的代码。我在上面添加了整个快速排序代码。我只有大约50个值或100个值要排序,为什么它不结束,这是我面临的问题。它只是需要对50个值或100个值进行排序。我进行了调试,它只是在处理中始终在分区内处理不同的线程。似乎它创建了无数不同的线程,并以处理分区的方式进行处理。可能是什么问题..您应该能够在调试器中看到这一点。您应该能够确定它应该何时停止创建线程。W在这一点上会发生什么,应该发生什么?我会尝试一个较小的集合,如3或5个值,因为它可能更容易调试。然后与10个值这样的小人物共享结果。我正在调试一些方法,并进行一些干运行…多谢Tudor的建议。你能给我看一下级别吗…?如何计算级别并将其传递给quicksort过程。截止点是pivot索引…对吗?我的意思是在快速排序中,解决方法是找到一些pivot元素,然后对过程进行一些递归(这里通常为每次调用快速排序过程创建线程),那么你所说的中断是什么意思?和级别..?你能给我看一些java代码或更好的理解吗。@乌斯曼:当你开始计算时,级别将从0开始。中断将被计算为产生线程数等于核心数的级别。例如,如果你有4个核心,那么中断将是1,因为e在级别0,您生成2个线程,然后在级别1,每个线程生成另外2个线程,因此总共有4个线程。您可以使用Runtime.getRuntime().availableProcessors()获得内核的数量;默认情况下,JDK7 ForkJoinPool通常会使用与处理器数量相同的线程。然后,它会在代码中的Fork和Join之后将任务排队。
    --a_Left;
    ++a_Right;

    while (true)
    {
        do
            ++a_Left;
        while (a_Array[a_Left] < pivotValue);

        do
            --a_Right;
        while (a_Array[a_Right] > pivotValue);

        if (a_Left < a_Right)           
            SwapArrayElements(a_Left,a_Right);
        else
        {
            return a_Right;
        }
    }
}