熟悉Java中的线程:为什么这个程序';s的运行时间随着线程数的增加而增加

熟悉Java中的线程:为什么这个程序';s的运行时间随着线程数的增加而增加,java,multithreading,performance,random,Java,Multithreading,Performance,Random,形势 我试图熟悉Java中的线程。出于这个原因,我修改了我在一本书中找到的一个程序列表。这很简单: 它创建一个包含100.000.000个元素的布尔[]-数组 它使用NUMBER\u服务器线程,用true或false随机填充该数组的元素 最后,它使用服务器数线程扫描该数组,并统计有多少项设置为true 有关更多详细信息,请参阅本文底部的代码 问题 当我用不同数量的线程运行代码并测量运行时,我得到了一个非常奇怪的结果;或者至少是一种我不理解的行为:当我使用更多线程时,BuildService线程会

形势

我试图熟悉Java中的线程。出于这个原因,我修改了我在一本书中找到的一个程序列表。这很简单:

  • 它创建一个包含100.000.000个元素的
    布尔[]
    -数组
  • 它使用
    NUMBER\u服务器
    线程,用
    true
    false
    随机填充该数组的元素
  • 最后,它使用
    服务器数
    线程扫描该数组,并统计有多少项设置为
    true
  • 有关更多详细信息,请参阅本文底部的代码

    问题

    当我用不同数量的线程运行代码并测量运行时,我得到了一个非常奇怪的结果;或者至少是一种我不理解的行为:当我使用更多线程时,BuildService线程会消耗更多的运行时。仅在一个线程中构建整个阵列(基于随机
    true
    分布),大约需要10秒。接下来,当我使用四个线程时,我希望运行时减少。然而,我得到了大约17秒的时间消耗

    我的ScanService工作正常:线程越多,时间消耗就会减少

    详情请参阅下表:

    正确
    -分布“>

    但是,如果在我的代码中更改一行并将
    if((int)((Math.random()*2d))==0)
    -statement(对于随机
    true
    -distribution)替换为
    if(i%2==0)
    (因此,每秒钟一项都是真的),我会得到一个预期的行为:

    正确
    -分布“>

    问题

    因此,我的问题是:

  • 为什么在使用Math.random()函数时,更多线程会导致更长的运行时间
  • 反之亦然,当只使用一个线程使用完全相同的函数时,为什么运行时会减少
  • 当涉及到线程时,从这种行为中可以得到什么“一般规则”
  • 背景信息

    该代码在Intel core i3上运行

    代码

    public class AsynchService
    {
        private static final int ARRAY_SIZE = 100000000; //100.000.000
        private static final int NUMBER_OF_SERVERS = 16;
        private static final int HOW_MANY = ARRAY_SIZE / NUMBER_OF_SERVERS;
    
        //build array asynch
        public static boolean[] buildArrayAsynch()
        {
            //build array with NUMBER_OF_SERVERS-Threads
            boolean[] array = new boolean[ARRAY_SIZE];
            Thread[] buildServerThread = new Thread[NUMBER_OF_SERVERS];
    
            long startTime = System.currentTimeMillis();
    
            for (int i = 0; i < NUMBER_OF_SERVERS; i++)
            {
                int start = i * HOW_MANY;
                int end = (i != NUMBER_OF_SERVERS - 1) ? (i + 1) * HOW_MANY - 1 : ARRAY_SIZE - 1;
    
                buildServerThread[i] = new BuildService(array, i, start, end);
            }
    
            //synchronize and wait for result
            int expectedResult = 0;
    
            for (int i = 0; i < NUMBER_OF_SERVERS; i++)
            {
                try
                {
                    buildServerThread[i].join();
                }
                catch (InterruptedException ex) {}
    
                expectedResult += ((BuildService) buildServerThread[i]).getExpectedResult();
            }
    
            System.out.println("\nNumber of \"true\"s ==> Expected result: " + expectedResult);
            System.out.println("Build duration: " + (System.currentTimeMillis() - startTime) + " ms\n");
    
            return array;
        }
    
        //scan array asynch
        public static int scanArrayAsynch(boolean[] array)
        {
            //create services and server-threads
            Thread[] serverThread = new Thread[NUMBER_OF_SERVERS];
    
            long startTime = System.currentTimeMillis();
    
            for (int i = 0; i < NUMBER_OF_SERVERS; i++)
            {
                int start = i * HOW_MANY;
                int end = (i != NUMBER_OF_SERVERS - 1) ? (i + 1) * HOW_MANY - 1 : ARRAY_SIZE - 1;
    
                serverThread[i] = new ScanService(array, i, start, end);
            }
    
            //synchronize with servers, wait for server end
            int result = 0;
    
            for (int i = 0; i < NUMBER_OF_SERVERS; i++)
            {
                try
                {
                    serverThread[i].join();
                }
                catch (InterruptedException ex) {}
    
                result += ((ScanService) serverThread[i]).getResult();
            }
    
            System.out.println("Search duration: " + (System.currentTimeMillis() - startTime) + " ms");
            return result;
        }
    
        public static void main(String[] args)
        {
            //build array
            boolean[] array = buildArrayAsynch();
    
            //scan array
            int result = scanArrayAsynch(array);
    
            //display result
            System.out.println("\nResult: " + result);
    
        }
    }
    
    class BuildService extends Thread
    {
        private boolean[] array;
        private int start;
        private int end;
        private int expectedResult = 0;
    
        public BuildService(boolean[] array, int serviceId, int start, int end)
        {
            this.array = array;
            this.start = start;
            this.end = end;
    
            this.setName("BuildService " + serviceId);
    
            this.start();
        }
    
        public int getExpectedResult()
        {
            return expectedResult;
        }
    
        public void run()
        {
            if (start < 0 || end >= array.length) throw new IndexOutOfBoundsException();
    
            System.out.println(getName() + ": StartIndex = " + start + "; EndIndex = " + end);
    
            long startTime = System.currentTimeMillis();
    
            for (int i = start; i <= end; i++)
            {
                //if (i % 2 == 0)
                if ((int) ((Math.random() * 2d)) == 0)
                {
                    array[i] = true;
                    expectedResult++;
                }
                else
                {
                    array[i] = false;
                }
            }
    
            System.out.println(getName() + " finished! \"true\" elements: " + expectedResult + "; duration = " + (System.currentTimeMillis() - startTime) + "ms");
        }
    }
    
    class ScanService extends Thread
    {
        private boolean[] array;
        private int serviceId;
        private int start;
        private int end;
        private int result = 0;
    
        public ScanService(boolean[] array, int serviceId, int start, int end)
        {
            this.array = array;
            this.serviceId = serviceId;
            this.start = start;
            this.end = end;
    
            this.start();
        }
    
        public int getResult()
        {
            return result;
        }
    
        public void run()
        {
            if (start < 0 || end >= array.length) throw new IndexOutOfBoundsException();
    
            System.out.println("Server " + serviceId + ": StartIndex = " + start + "; EndIndex = " + end);
    
            for (int i = start; i <= end; i++)
            {
                if (array[i]) result++;
            }
        }
    }
    
    公共类异步服务
    {
    私有静态最终整数数组_SIZE=100000000;//100.000.000
    私有静态最终整型服务器数=16;
    私有静态final int HOW_MANY=数组大小/服务器数量;
    //异步构建阵列
    公共静态布尔值[]buildArrayAsynch()
    {
    //构建包含多个线程的\u服务器的数组
    boolean[]数组=新的boolean[array_SIZE];
    线程[]buildServerThread=新线程[服务器的数量];
    long startTime=System.currentTimeMillis();
    对于(int i=0;i<服务器的数量;i++)
    {
    int start=i*多少;
    int end=(i!=服务器数量-1)?(i+1)*数量-1:数组大小-1;
    buildServerThread[i]=新的BuildService(数组、i、开始、结束);
    }
    //同步并等待结果
    int expectedResult=0;
    对于(int i=0;i<服务器的数量;i++)
    {
    尝试
    {
    buildServerThread[i].join();
    }
    catch(InterruptedException ex){}
    expectedResult+=((BuildService)buildServerThread[i])。getExpectedResult();
    }
    System.out.println(“\n \“true”s==>预期结果的编号:“+expectedResult”);
    System.out.println(“构建持续时间:+(System.currentTimeMillis()-startTime)+“ms\n”);
    返回数组;
    }
    //异步扫描阵列
    公共静态int-scanArrayAsynch(布尔[]数组)
    {
    //创建服务和服务器线程
    线程[]服务器线程=新线程[服务器的数量];
    long startTime=System.currentTimeMillis();
    对于(int i=0;i<服务器的数量;i++)
    {
    int start=i*多少;
    int end=(i!=服务器数量-1)?(i+1)*数量-1:数组大小-1;
    serverThread[i]=新的扫描服务(数组、i、开始、结束);
    }
    //与服务器同步,等待服务器结束
    int结果=0;
    对于(int i=0;i<服务器的数量;i++)
    {
    尝试
    {
    serverThread[i].join();
    }
    catch(InterruptedException ex){}
    结果+=((扫描服务)服务器线程[i]).getResult();
    }
    System.out.println(“搜索持续时间:+(System.currentTimeMillis()-startTime)+“ms”);
    返回结果;
    }
    公共静态void main(字符串[]args)
    {
    //构建阵列
    布尔[]数组=buildArrayAsynch();
    //扫描阵列
    int结果=扫描阵列同步(阵列);
    //显示结果
    System.out.println(“\n结果:+结果);
    }
    }
    类BuildService扩展线程
    {
    私有布尔[]数组;
    私人int启动;
    私人互联网终端;
    private int expectedResult=0;
    公共构建服务(布尔[]数组,int serviceId,int start,int end)
    {
    this.array=数组;
    this.start=start;
    this.end=end;
    这个.setName(“BuildService”+serviceId);
    这个。start();
    }
    public int getExpectedResult()
    {
    返回预期结果;
    }
    公开募捐
    {
    if(start<0 | | end>=array.length)抛出新的IndexOutOfBoundsException();
    System.out.println(getName()+”:StartIndex=“+start+”;EndIndex=“+end”);
    long startTime=System.currentTimeMillis();
    对于(int i=start;i=array.length)抛出新的IndexOutOfBoundsException();
    System.out.println(“服务器”+serviceId+”:StartIndex=“+start+”;EndIndex=“+end”);
    
    对于(int i=start;i而言,细节才是魔鬼。
    Math.random()
    的答案是:

    此方法已正确同步,以允许多个用户正确使用
    import java.util.Random;
    
    class BuildService extends Thread
    {
        private boolean[] array;
        private int start;
        private int end;
        private int expectedResult = 0;
        private Random random = new Random();
    
        public BuildService(boolean[] array, int serviceId, int start, int end)
        {
            this.array = array;
            this.start = start;
            this.end = end;
    
            this.setName("BuildService " + serviceId);
    
            this.start();
        }
    
        public int getExpectedResult()
        {
            return expectedResult;
        }
    
        public void run()
        {
            if (start < 0 || end >= array.length) throw new IndexOutOfBoundsException();
    
            System.out.println(getName() + ": StartIndex = " + start + "; EndIndex = " + end);
    
            long startTime = System.currentTimeMillis();
    
            for (int i = start; i <= end; i++)
            {
                array[i] = random.nextBoolean();
                if (array[i]) expectedResult++;
            }
    
            System.out.println(getName() + " finished! \"true\" elements: " + expectedResult + "; duration = " + (System.currentTimeMillis() - startTime) + "ms");
        }
    }