熟悉Java中的线程:为什么这个程序';s的运行时间随着线程数的增加而增加
形势 我试图熟悉Java中的线程。出于这个原因,我修改了我在一本书中找到的一个程序列表。这很简单:熟悉Java中的线程:为什么这个程序';s的运行时间随着线程数的增加而增加,java,multithreading,performance,random,Java,Multithreading,Performance,Random,形势 我试图熟悉Java中的线程。出于这个原因,我修改了我在一本书中找到的一个程序列表。这很简单: 它创建一个包含100.000.000个元素的布尔[]-数组 它使用NUMBER\u服务器线程,用true或false随机填充该数组的元素 最后,它使用服务器数线程扫描该数组,并统计有多少项设置为true 有关更多详细信息,请参阅本文底部的代码 问题 当我用不同数量的线程运行代码并测量运行时,我得到了一个非常奇怪的结果;或者至少是一种我不理解的行为:当我使用更多线程时,BuildService线程会
布尔[]
-数组NUMBER\u服务器
线程,用true
或false
随机填充该数组的元素服务器数线程扫描该数组,并统计有多少项设置为true
true
分布),大约需要10秒。接下来,当我使用四个线程时,我希望运行时减少。然而,我得到了大约17秒的时间消耗
我的ScanService工作正常:线程越多,时间消耗就会减少
详情请参阅下表:
正确-分布“>
但是,如果在我的代码中更改一行并将if((int)((Math.random()*2d))==0)
-statement(对于随机true
-distribution)替换为if(i%2==0)
(因此,每秒钟一项都是真的),我会得到一个预期的行为:
正确-分布“>
问题
因此,我的问题是:
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");
}
}