最近在看《Java虚拟机并发编程》,在此记录一些重要的东东。
线程数的确定:
1. 获取系统可用的处理器核心数:int numOfCores = Runtime.getRuntime().availableProcessors()
2. 如果任务是计算密集型的,则线程数 = numOfCores
如果任务是IO密集型的,则线程数 = numOfCores / (1 - 阻塞系数), 其中阻塞系数在0~1之间。
注:如果任务被阻塞的时间大于执行时间, 则这些任务是IO密集型的,我们就需要创建比处理器核心数大几倍数量的线程
在解决问题的过程中使处理器一直保持忙碌状态比将负载均摊到每个子任务要实惠得多。
任务完成并不代表线程消亡。
计算密集型任务:如求1到10000000内所有素数的个数
1. AbstractPrimeFinder
public abstract classAbstractPrimeFinder {public boolean isPrime(final intnumber){if(number <= 1) return false;for(int i = 2; i <=Math.sqrt(number); i++){if (number % i == 0)return false;
}return true;
}public int countPrimesInRange(final int lower, final intupper){int total = 0;for( int i = lower; i <= upper; i++){if(isPrime(i))
total++;
}returntotal;
}public void timeAndComputer(final intnumber){long start =System.nanoTime();int numberOfPrimes =countPrimes(number);long end =System.nanoTime();
System.out.printf("Number of primes under %d is %d\n", number, numberOfPrimes);
System.out.println("Spend time(seconds) is " + (end-start)/1.0e9);
}public abstract int countPrimes(final intnumber);
}
2. ConcurrentPrimeFinder
/*** 对于计算密集型的任务,增加线程数并没有什么意义,线程数应该等于CPU内核数。如果较难把任务均摊到CPU,则
* 可以把任务切分成较多块,以确保CPU完成某块任务后,可以继续处理其它块。防止某个CPU完成任务后处于空闲状态。
*@authorshj
**/
public class ConcurrentPrimeFinder extendsAbstractPrimeFinder{private final intpoolSize;private final intnumberOfParts;public ConcurrentPrimeFinder(int poolSize, intnumberOfParts){this.poolSize =poolSize;this.numberOfParts =numberOfParts;
}
@Overridepublic int countPrimes(final intnumber) {int count = 0;try{
List> partitions = new ArrayList<>();int chunksPerPartition = number /numberOfParts;for(int i = 0; i < numberOfParts; i++){final int lower = (i * chunksPerPartition) + 1;final int upper = (i == numberOfParts - 1) ? number : lower + chunksPerPartition - 1;
partitions.add(new Callable(){publicInteger call(){returncountPrimesInRange(lower, upper);
}
});
}
ExecutorService executorPool=Executors.newFixedThreadPool(poolSize);
List> results = executorPool.invokeAll(partitions, 10000, TimeUnit.SECONDS);
executorPool.shutdown();for(Futureresult : results){
count+=result.get();
}
}catch(Exception e){
e.printStackTrace();
}returncount;
}public static voidmain(String[] args){int cores =Runtime.getRuntime().availableProcessors();int numberOfParts = 20; //划分成子区间的数量, 修改此值查看运行时间的变化
newConcurrentPrimeFinder(cores,numberOfParts).timeAndComputer(10_000_000);
}
}