在下面的代码中,我通过线程池多次调用一个函数。在这个函数中,我通过名为FastestMemory的全局属性跟踪函数的最快执行。
但是,当我打印出值时,在线程池循环之后,我被赋予原始值,就好像全局变量与每次循环迭代更新的变量不同。当我知道FastestMemory的值被分配给(例如)253475时,我只有2000000000返回。
1)我是否需要重新构造此代码以便能够跟踪最快的迭代?
2)我似乎能够非常快地执行此代码,它在四个Xeon x7550上每次迭代采用(ob平均值)小于1毫秒。这是正常的还是我的时间错误? C#平均需要大约400毫秒?!
public class PoolDemo {
static long FastestMemory = 2000000000;
static long SlowestMemory = 0;
static long TotalTime;
static long[] FileArray;
static DataOutputStream outs;
static FileOutputStream fout;
public static void main(String[] args) throws InterruptedException, FileNotFoundException {
int Iterations = Integer.parseInt(args[0]);
int ThreadSize = Integer.parseInt(args[1]);
FileArray = new long[Iterations];
fout = new FileOutputStream("server_testing.csv");
// fixed pool, unlimited queue
ExecutorService service = Executors.newFixedThreadPool(ThreadSize);
ThreadPoolExecutor executor = (ThreadPoolExecutor) service;
for(int i = 0; i<Iterations; i++) {
Task t = new Task(i);
executor.execute(t);
}
executor.shutdown();
service.shutdown();
System.out.println("Fastest: " + FastestMemory);
for(int j=0; j<FileArray.length; j++){
new PrintStream(fout).println(FileArray[j] + ",");
}
}
private static class Task implements Runnable {
private int ID;
static Byte myByte = 0;
public Task(int index) {
this.ID = index;
}
@Override
public void run() {
long Start = System.nanoTime();
int Size1 = 100000;
int Size2 = 2 * Size1;
int Size3 = Size1;
byte[] list1 = new byte[Size1];
byte[] list2 = new byte[Size2];
byte[] list3 = new byte[Size3];
for(int i=0; i<Size1; i++){
list1[i] = myByte;
}
for (int i = 0; i < Size2; i=i+2)
{
list2[i] = myByte;
}
for (int i = 0; i < Size3; i++)
{
byte temp = list1[i];
byte temp2 = list2[i];
list3[i] = temp;
list2[i] = temp;
list1[i] = temp2;
}
long Finish = System.nanoTime();
long Duration = Finish - Start;
FileArray[this.ID] = Duration;
TotalTime += Duration;
System.out.println("Individual Time " + this.ID + " \t: " + (Duration) + " nanoseconds");
if(Duration < FastestMemory){
FastestMemory = Duration;
}
if (Duration > SlowestMemory)
{
SlowestMemory = Duration;
}
}
}
}
答案 0 :(得分:5)
问题是您的主线程正在退出而不等待提交给执行程序的任务终止。
您可以通过在调用ExecutorService#shutdown
后简单地添加对ExecutorService#awaitTermination的来电来实现。
您将遇到的另一个问题是,您没有考虑static long
值的线程安全性,以跟踪最快的时间。您需要添加synchronize
块或使用AtomicLong
来获得安全的比较和设置操作。
答案 1 :(得分:1)
shutdown()
仅拒绝提交到池中的新任务,但对已提交和正在运行的任务不执行任何操作。为了等待所有任务完成,您应该致电:
executor.awaitTermination(1, TimeUnit.MINUTES);
service.awaitTermination(1, TimeUnit.MINUTES);
此外,FastestMemory
和SlowestMemory
的访问权必须以某种方式同步,例如:
synchronized(PoolDemo.class) {
FastestMemory = Math.min(FastestMemory, Duration);
SlowestMemory = Math.max(SlowestMemory, Duration);
}
BTW根据Java Naming Conventions:
所有实例,类和类常量都是大小写混合,带有小写的第一个字母。
答案 2 :(得分:0)
首先,你不要等待完成任何任务。 您需要等待执行程序服务完成。
executor.awaitTermination(...);
同时执行程序和服务都引用同一个对象,因此不需要同时关闭它们。实际上,我没有看到任何理由甚至有执行人。您调用的所有方法都是ExecutorService的一部分。
接下来,对长变量的更改不是线程安全的。如果另一个线程在比较后更改了值,会发生什么。即使读取和写入对于长变量也不是原子的。您应该使用AtomicLongs来获取这些变量。
您需要从AtomicLong获取当前值,并将其与当前值的运行进行比较。如果新值指示应该进行更新,请使用compareAndSet以确保没有其他人更改该值。如果其他人更改了它,请再次运行检查。