計算程式所需線程總數:
線程數 = CPU可用核心數/(1-阻塞係數)
其中阻塞係數的取值在0-1之間。
計算密集型任務的阻塞係數為0,而IO密集型任務的阻塞係數則接近於1。一個完全阻塞的任務是註定要掛掉的,所以我們無須擔心阻塞係數會達到1。
為了更好的確定程式所需線程數,我們需要知道下面兩個關鍵參數:
1、處理器可用核心數
2、任務的阻塞係數
第一個參數很容易確定(Runtime.getRuntime().availableProcessors())。
阻塞係數可以採用一些效能分析工具或java.lang.managenment API來確定線程話在系統I/O操作上的時間與CPU密集任務所消耗的時間比值。
Demo:
// 測試公式:線程數=CPU可用核心數/(1-阻塞係數)@Testpublic void testInvokeAll() throws InterruptedException, ExecutionException {// 向 JAVA 虛擬機器返回可用處理器的數目(我當前機器是i3雙核四線程,返回為4)int numberOfCores = Runtime.getRuntime().availableProcessors();double blockingCoefficient = 0;int poolSize = (int) (numberOfCores / (1 - blockingCoefficient));System.out.println("poolSize:" + poolSize);// 建立一個可重用固定線程數的線程池,以共用的無界隊列方式來運行這些線程ExecutorService services = Executors.newFixedThreadPool(poolSize);List<Callable<String>> tasks = new LinkedList<Callable<String>>();for (int i = 10; i >= 1; i--) {final String reStr = "current call " + i;final int j = i;tasks.add(new Callable<String>() {@Overridepublic String call() throws Exception {// 類比阻塞TimeUnit.SECONDS.sleep(j);return reStr;}});}long beginTime = System.currentTimeMillis();List<Future<String>> invokeValues = services.invokeAll(tasks);System.out.println("time:" + (System.currentTimeMillis() - beginTime));Iterator<Future<String>> iter = invokeValues.iterator();while (iter.hasNext()) {System.out.println(iter.next().get());}services.shutdown();}
當我們阻塞係數設定為0,消耗時間為15003;阻塞係數設定為0.9時,消耗時間為10001。
poolSize:4
time:15003
current call 10
current call 9
current call 8
current call 7
current call 6
current call 5
current call 4
current call 3
current call 2
current call 1
poolSize:40
time:10001
current call 10
current call 9
current call 8
current call 7
current call 6
current call 5
current call 4
current call 3
current call 2
current call 1