[英]Why this piece of Java code is not running concurrently
我寫過了Eratosthenes的篩子,它應該是平行工作的,但事實並非如此。 當我增加線程數時,計算時間不會越來越少。 有什么想法嗎?
主要課程
import java.util.Date;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class ConcurrentTest {
public static void main(String[] args) throws InterruptedException {
Sieve task = new Sieve();
int x = 1000000;
int threads = 4;
task.setArray(x);
Long beg = new Date().getTime();
ExecutorService exec = Executors.newCachedThreadPool();
for (int i = 0; i < threads; i++) {
exec.execute(task);
}
exec.shutdown();
Long time = 0L;
// Main thread is waiting until all threads are terminated
// ( it means that computing is done)
while (true)
if (exec.isTerminated()) {
time = new Date().getTime() - beg;
break;
}
System.out.println("Time is " + time);
}
}
篩分類
import java.util.concurrent.ConcurrentHashMap;
public class Sieve implements Runnable {
private ConcurrentHashMap<Integer, Boolean> array =
new ConcurrentHashMap<Integer, Boolean>();
private int x;
public void run() {
while(true){
// I am getting synchronized number to check if it's prime
int n = getCounter();
// If no more numbers to check, stop loop
if( n == -1)
break;
// If HashMap contains number, we can further
if(!array.containsKey(n))continue;
for (int i = 2 * n; i <= x; i += n) {
// Compound numbers are removed from HashMap, Eg. 6, 12 and much more.
array.remove(i);
}
}
}
private synchronized int getCounter(){
if( counter < x)
return counter++;
else return -1;
}
public void setArray(int x) {
this.x = x;
for (int i = 2; i <= x; i++)
array.put(i, false);
}
}
我用不同數量的線程進行了一些測試。 結果如下:
Nr of threads 1 Time is 1850, 1795, 1825
Nr of threads 2 Time is 1845, 1836, 1814
Nr of threads 3 Time is 1767, 1820, 1756
Nr of threads 4 Time is 1732, 1840, 2083
Nr of threads 5 Time is 1791, 1795, 1803
Nr of threads 6 Time is 1825, 1728, 1707
Nr of threads 7 Time is 1754, 1729, 1686
Nr of threads 8 Time is 1760, 1717, 1817
Nr of threads 9 Time is 1721, 1699, 1673
Nr of threads 10 Time is 1661, 1722, 1718
當我增加線程數時,計算時間不會越來越少
tl; dr :你的問題規模太小了。 如果將x增加到10000000,差異將變得更加明顯。 但是,它們不會是你所期待的。
我在八核機器上嘗試了你的代碼,稍作修改:
我嘗試使用固定線程池 , 緩存線程池和fork連接池啟動Sieve任務,並比較線程變量的不同值的結果。
我在x = 10000000的機器上看到以下結果(以毫秒為單位):
Thread count = 1 2 4 8 16 Fixed thread pool = 5451 3866 3639 3227 3120 Cached thread pool= 5434 3763 3709 3258 3078 Fork-join pool = 6732 3670 3735 3190 3102
這些結果向我們展示了從單個執行線程更改為兩個線程的明顯好處。 但是,額外線程的好處會迅速下降。 有一個有趣的高原,從兩到四個線程,邊際利益高達16。
此外,您還可以看到不同的線程機制具有不同的初始開銷:我沒想到Fork-Join池比其他機制花費更多的開始。
因此,正如所寫的那樣,對於小而重要的問題集,你不應該期望通過兩個線程獲益。
如果您想增加額外線程的好處,那么您將需要查看當前的實現。 例如,當我使用incrementAndGet()從synchronized getCounter()切換到AtomicInteger時 ,我消除了synchronized方法的開銷。 結果是我的所有四個線程數都下降了1000毫秒。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.