Java中计算最小值和最大值的多线程

Java中计算最小值和最大值的多线程,java,multithreading,recursion,Java,Multithreading,Recursion,我已经编写了使用多线程计算给定数组中的最小数和最大数的代码。这个想法类似于binarysearch,我只是将数组分成两半,计算每一半的最小值和最大值,并相应地更新我的最小值和最大值字段。 这可能是一个用于多线程的愚蠢示例。但既然我考虑过这个问题,我就想实现它,看看它是如何运行的。到目前为止,代码的工作方式令人惊讶地正确。我希望它不会给出正确的结果,因为我不会等待第一个线程完成,我会立即启动第二个线程。这意味着最小值和最大值不能正确更新。 有人能指出为什么这在多次运行和任何改进空间中都能正常工作吗

我已经编写了使用多线程计算给定数组中的最小数和最大数的代码。这个想法类似于
binarysearch
,我只是将数组分成两半,计算每一半的最小值和最大值,并相应地更新我的最小值和最大值字段。 这可能是一个用于多线程的愚蠢示例。但既然我考虑过这个问题,我就想实现它,看看它是如何运行的。到目前为止,代码的工作方式令人惊讶地正确。我希望它不会给出正确的结果,因为我不会等待第一个线程完成,我会立即启动第二个线程。这意味着最小值和最大值不能正确更新。 有人能指出为什么这在多次运行和任何改进空间中都能正常工作吗

代码在这里

import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Set;



public class MinMax implements Runnable{

    Long min=Long.MAX_VALUE;
    Long max=Long.MIN_VALUE;
    int low;
    int high;
    Long[] arr;

    public  MinMax(int low, int high, Long[] arr){
        this.low = low;
        this.high=high;
        this.arr = arr;

    }
        @Override
        public void run() {
            System.out.println("called run ");
        if (low-high<=2){
            System.out.println("called ");
            List<Long> l = Arrays.asList(arr);
            min=Collections.min(l) < min ? Collections.min(l) : min;
            max=Collections.max(l) > max ? Collections.max(l) : max;
        }
        else {
                    System.out.println(Thread.currentThread());
            int mid = (high+low)/2;
            MinMax left = new MinMax(low,mid,arr);
            MinMax right = new MinMax(mid,high,arr);
            Thread t1 = new Thread(left);
            Thread t2 = new Thread(right);
            t1.start();
            t2.start();
            Set<Thread> threadset=Thread.getAllStackTraces().keySet();
             for (Thread t : threadset)
                 System.out.println(t.getName());
            try {
                t1.join();
                            t2.join();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }   
        }
    }

    public static void main(String[] args){
         long[] arr = {3,4,5,1123,567,78,90,5,35434,1,34,56,111,2,56,789,87645,343535};
         Long[] newarr= new Long[arr.length];
         int i = 0;
         for (long temp : arr)
             newarr[i++]=temp;
         MinMax m = new MinMax(0,arr.length,newarr);
         m.run();
         System.out.println(m.min);
         System.out.println(m.max);

    }

}
导入java.util.array;
导入java.util.Collections;
导入java.util.List;
导入java.util.Set;
公共类MinMax实现了Runnable{
Long min=Long.MAX_值;
长最大值=长最小值;
int低;
int高;
长[]arr;
公共最小最大值(整数低、整数高、长[]arr){
这个.低=低;
这个。高=高;
this.arr=arr;
}
@凌驾
公开募捐{
System.out.println(“称为run”);
如果(低-高-最大)集合。最大(l):最大;
}
否则{
System.out.println(Thread.currentThread());
int mid=(高+低)/2;
左最小最大值=新的最小最大值(低、中、arr);
右最小最大值=新的最小最大值(中、高、arr);
螺纹t1=新螺纹(左);
螺纹t2=新螺纹(右侧);
t1.start();
t2.start();
Set threadset=Thread.getAllStackTraces().keySet();
用于(螺纹t:螺纹组)
System.out.println(t.getName());
试一试{
t1.join();
t2.连接();
}捕捉(中断异常e){
e、 printStackTrace();
}   
}
}
公共静态void main(字符串[]args){
长[]arr={3,4,51123567,78,90,535434,1,34,56111,2,5678987645343535};
Long[]newarr=新长[arr.length];
int i=0;
用于(长期温度:arr)
newarr[i++]=temp;
最小最大值m=新的最小最大值(0,arr.length,newarr);
m、 run();
系统输出打印项次(m.min);
系统输出打印项次(m.max);
}
}

我对您的代码的评论-首先,需要声明
min
max
以确保它们的值在线程内及时更新

然后,此比较不是原子的,您可能需要将其包装到
synchronized
块中,或者如果
synchronized
性能不令人满意,则考虑
AtomicInteger
compareAndSet
优化:

min=Collections.min(l) < min ? Collections.min(l) : min;
max=Collections.max(l) > max ? Collections.max(l) : max;
min=Collections.min(l)最大值?集合。最大值(l):最大值;
所以问题可能是两个线程同时计算它们的最小值,但是它们在不同的时间分配它,所以赢家是谁的结果先被写入

正如@JamesKingsbery所注意到的,您可能需要在第二个线程上调用
start()


这可能是最后一件事,在您的情况下,您可能不会得到任何性能提升,但这是一个值得研究的好例子。

我对您的代码的评论-首先,
min
max
需要声明为
volatile
,以确保它们的值在线程内及时更新

然后,此比较不是原子的,您可能需要将其包装到
synchronized
块中,或者如果
synchronized
性能不令人满意,则考虑
AtomicInteger
compareAndSet
优化:

min=Collections.min(l) < min ? Collections.min(l) : min;
max=Collections.max(l) > max ? Collections.max(l) : max;
min=Collections.min(l)最大值?集合。最大值(l):最大值;
所以问题可能是两个线程同时计算它们的最小值,但是它们在不同的时间分配它,所以赢家是谁的结果先被写入

正如@JamesKingsbery所注意到的,您可能需要在第二个线程上调用
start()


这可能是最后一件事,在你的情况下,你可能不会得到任何性能提升,但这是一个很好的例子来研究。

为什么它有效?第一次
low
0
high
18
low-high为什么有效?第一次
low
0
>high
大约是
18
low-high为此使用
递归动作
类。这里我使用
递归动作
编写了程序。请查找下面的代码。有关更多信息,请查看

package org.kavi.threadexample;
导入java.util.array;
导入java.util.Collections;
导入java.util.List;
导入java.util.concurrent.ForkJoinPool;
导入java.util.concurrent.RecursiveAction;
公共类MinMax扩展了递归操作{
Long min=Long.MAX_值;
长最大值=长最小值;
int低;
int高;
长[]arr;
公共最小最大值(整数低、整数高、长[]arr){
这个.低=低;
这个。高=高;
this.arr=arr;
}
@凌驾
受保护的void compute(){
如果(低-高-最大)集合。最大(l):最大;
}
否则{
int mid=(低+高)>>>1;
左最小最大值=新的最小最大值(低、中、arr);
右最小最大值=新的最小最大值(中、高、arr);
}
}
公共静态void main(字符串[]args){
长[]arr={3,4,51123567,78,90,535434,1,34,56111,2,5678987645343535};
Long[]newarr=新长[arr.length];
int i=0;
用于(长期温度:arr){
newarr[i++]=temp;
}
最小最大值m=新的最小最大值(0,arr.length,newarr);
ForkJoinPool池=新的ForkJoinPool();
调用池(m);
系统
package org.kavi.threadexample;

import java.util.Arrays;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.RecursiveAction;

public class MinMax extends RecursiveAction {

    Long min = Long.MAX_VALUE;
    Long max = Long.MIN_VALUE;
    int low;
    int high;
    Long[] arr;

    public MinMax(int low, int high, Long[] arr) {
        this.low = low;
        this.high = high;
        this.arr = arr;
    }

    @Override
    protected void compute() {
        if (high - low <= 2) {
            System.out.println(Arrays.toString(Arrays.copyOfRange(arr, low, high)));
            if (low == high) {
                min = max = arr[low];
            } else {
                min = Math.min(arr[low], arr[low + 1]);
                max = Math.max(arr[low], arr[low + 1]);
            }
        } else {
            // make the left side an exact power of two
            int leftWidth = 1 << (30 - Integer.numberOfLeadingZeros(high - low));
            MinMax left = new MinMax(low, low + leftWidth, arr);
            MinMax right = new MinMax(low + leftWidth, high, arr);
            invokeAll(left, right);
            min = Math.min(left.min, right.min);
            max = Math.max(left.max, right.max);
        }
    }

    public static void main(String[] args) {
        Long[] arr = {3L, 4L, 5L, 1123L, 567L, 78L, 90L, 5L, 35434L, 1L, 34L, 56L, 111L, 2L, 56L, 789L, 87645L, 343535L};
        MinMax m = new MinMax(0, arr.length, arr);
        ForkJoinPool pool = new ForkJoinPool();
        pool.invoke(m);
        System.out.println(m.min);
        System.out.println(m.max);
    }
}