2013-07-11 32 views
2

我必須通過for循環12000次初始化float [12000]。然後我掃描該陣列以查找超過某個閾值的值。如果該值超過閾值,我操縱某個對象的實例變量。使用多線程處理對java數組進行分區和分析

例子:

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次新陣列上僅查找該在另一個數據結構中索引並調用setter。從我的系統時間計算中,它應該花費大約13個小時。我的機器上有8個處理器。

我該如何利用java的多線程功能?我特別尋找分割陣列初始化和掃描的線程解決方案。源代碼使用線程將不勝感激。

+0

你對Java中的線程沒有任何經驗嗎?你有沒有使用過Runnable或者在Thread類中做了什麼?好奇你在這裏的初始知識。 – Kon

+4

13小時?一些有趣的方法一定非常有趣。 –

+0

你是什麼意思「每次在一個新陣列上做12000次」。您正在採取多少次12000次迭代。 – veritas

回答

6

您可以在八個不同的線程劃分這件事做這樣的事情

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以及如何關閉工作線程等 - here's a tutorial on that

編輯要利用你的代碼並運行12000次的8個線程,你會做以下幾點:

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(); 
} 

每八個線程運行的「初始化float數組,迭代的1500次迭代通過浮點數組「代碼。然後join方法將等待線程完成。確保// do something interesting中的代碼是線程安全的 - 你說你調用了一個setter,所以要確保多個線程不會調用同一個setter,否則setter會被同步,否則,在二傳手中使用類似AtomicInteger的東西。如果您對此有疑問,請發佈設置代碼。

+0

在第二種方法中,工作人員無法訪問每個浮動的原始索引 - 可能是許多應用程序中必需的信息。 – Keith

+0

@Keith好點,我已經編輯了我的答案 –

+0

@ Zim-Zam謝謝。我懷疑這會很好。但是,更昂貴的計算是初始化12,000個不同的陣列並每次掃描它們。 「有趣的」部分只是在另一個數據結構中查找該索引並調用setter。你可以在線程分割12,000個創建的數組而不是8個東西的情況下改變你的答案嗎? –

相關問題