3

我必须通过 for 循环初始化 float[12000] 12000 次。然后我扫描数组以查找超过某个阈值的值。如果值超过阈值,我会操作某个对象的实例变量。

例子:

Random random = new Random();
float[] x = new float[12000];

for (int i = 0; i < x.length; i++) {
  x[i] = random.nextFloat();
}

for (int i = 0; i < x.length; i++) {
  if (x[i] >= 0.75) {
  \\ do something interesting
  }
}

基本上,我必须更改数组的值,并在每次长度为 12000 的新数组上执行 12000 次。“有趣的”代码只是在另一个数据结构中查找该索引并调用设置器。根据我的系统时间计算,大约需要 13 个小时。我的机器上有 8 个处理器。

如何利用 java 的多线程功能?我正在专门寻找对数组的初始化和扫描进行分区的线程解决方案。使用线程的源代码将不胜感激。

4

1 回答 1

8

你可以把它分成八个不同的线程做这样的事情

public class Worker implements Runnable {
    final private int minIndex; // first index, inclusive
    final private int maxIndex; // last index, exclusive
    final private float[] data;

    public Worker(int minIndex, int maxIndex, float[] data) {
        this.minIndex = minIndex;
        this.maxIndex = maxIndex;
        this.data = data;
    }

    public void run() {
        for(int i = minIndex; i < maxIndex; i++) {
            if(data[i] >= 0.75) {
                // do something interesting
            }
        }
    }
}


// *** Main Thread ***
float[] data = new float[12000];
int increment = data.length / 8;
for(int i = 0; i < 8; i++) {
    new Thread(new Worker(i * increment, (i + 1) * increment, data)).start();
}

这将数组划分为 8 个不同的线程。或者,另一种选择是:

public class Worker implements Runnable {
    final private BlockingQueue<Integer> queue;
    final private float[] data;

    public Worker(BlockingQueue<Integer> queue) {
        this.queue = queue;
        this.data = data;
    }

    public void run() {
        while(true) {
            int i = queue.take();
            float f = data[i];
            // do something interesting to f
        }
    }
}


// *** Main Thread ***
BlockingQueue<Integer> queue = new LinkedBlockingQueue<>();
float[] data = new float[12000];
for(int i = 0; i < 8; i++) {
    new Thread(new Worker(queue, data)).start();
}
for(int i = 0; i < data.length; i++) {
    if (data[i] >= 0.75) {
        queue.offer(i);
    }
}

这使用一个线程遍历数组并找到有趣的数字,然后使用八个工作线程对有趣的数字做一些有趣的事情。我更喜欢这种方法,因为第一种方法可能是一个工作线程最终不得不处理一千个有趣的数字,而另一个工作线程只需要处理几个有趣的数字;这种方法确保每个线程需要处理大约相同数量的有趣数字。

我省略了很多东西,比如如何使用Executors以及如何关闭你的工作线程等等——这里有一个关于它的教程

编辑要获取您的代码并在 8 个线程上运行 12000 次,您将执行以下操作:

public class Worker implements Runnable {
    private final int numberOfIterations;
    private final float[] x = new float[12000];

    public Worker(int numberOfIterations) {
        this.numberOfIterations = numberOfIterations;
    }

    public void run() {
        for(int i = 0; i < numberOfIterations; i++) {
            Random random = new Random();

            for (int i = 0; i < x.length; i++) {
                x[i] = random.nextFloat();
            }

            for (int i = 0; i < x.length; i++) {
                if (x[i] >= 0.75) {
                    \\ do something interesting
                }
            }
        }
    }
}


// *** Main Thread ***
Thread[] threads = new Thread[8];
for(int i = 0; i < 8; i++) {
    threads[i] = new Thread(new Worker(12000/8));
    threads[i].start();
}
for(int i = 0; i < 8; i++) {
    threads[i].join();
}

八个线程中的每一个都将运行“初始化浮点数组,遍历浮点数组”代码的 1500 次迭代。然后该join方法将等待线程完成。确保其中的代码// do something interesting是线程安全的——你说你正在调用一个设置器,所以要确保多个线程不会调用同一个设置器,或者设置器是同步的,或者你是AtomicInteger在二传手中使用类似的东西。如果您对此有任何疑问,请发布 setter 代码。

于 2013-07-11T03:40:30.457 回答