java 多线程学习笔记 -- 计算密集型任务

Posted 一剑侵心

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了java 多线程学习笔记 -- 计算密集型任务相关的知识,希望对你有一定的参考价值。

最近在看《Java虚拟机并发编程》,在此记录一些重要的东东。

线程数的确定:
1. 获取系统可用的处理器核心数:int numOfCores = Runtime.getRuntime().availableProcessors()
2. 如果任务是计算密集型的,则线程数 = numOfCores
        如果任务是IO密集型的,则线程数 = numOfCores / (1 - 阻塞系数), 其中阻塞系数在0~1之间。
注:如果任务被阻塞的时间大于执行时间, 则这些任务是IO密集型的,我们就需要创建比处理器核心数大几倍数量的线程


在解决问题的过程中使处理器一直保持忙碌状态比将负载均摊到每个子任务要实惠得多。
任务完成并不代表线程消亡。

 

计算密集型任务:如求1到10000000内所有素数的个数

1. AbstractPrimeFinder

 

public abstract class AbstractPrimeFinder {

    public boolean isPrime(final int number){
        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 int upper){
        int total = 0;
        for( int i = lower; i <= upper; i++){
            if(isPrime(i))
                total++;
        }
        return total;
    }
    
    public void timeAndComputer(final int number){
        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 int number);
}

 

2. ConcurrentPrimeFinder

/**
 * 对于计算密集型的任务,增加线程数并没有什么意义,线程数应该等于CPU内核数。如果较难把任务均摊到CPU,则
 * 可以把任务切分成较多块,以确保CPU完成某块任务后,可以继续处理其它块。防止某个CPU完成任务后处于空闲状态。
 * @author shj
 *
 */
public class ConcurrentPrimeFinder extends AbstractPrimeFinder{
    private final int poolSize;
    private final int numberOfParts;
    
    public ConcurrentPrimeFinder(int poolSize, int numberOfParts){
        this.poolSize = poolSize;
        this.numberOfParts = numberOfParts;
    }

    @Override
    public int countPrimes(final int number) {
        int count = 0 ;
        try{
            List<Callable<Integer>> 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<Integer>(){
                    public Integer call(){
                        return countPrimesInRange(lower, upper);
                    }
                });
            }
            
            ExecutorService executorPool = Executors.newFixedThreadPool(poolSize);
            List<Future<Integer>> results = executorPool.invokeAll(partitions, 10000, TimeUnit.SECONDS);
            executorPool.shutdown();
            
            for(Future<Integer> result : results){
                count += result.get();
            }
        }catch(Exception e){
            e.printStackTrace();
        }
        return count;
    }

    public static void main(String[] args){
        int cores = Runtime.getRuntime().availableProcessors();
        int numberOfParts = 20; //划分成子区间的数量, 修改此值查看运行时间的变化
        new ConcurrentPrimeFinder(cores,numberOfParts).timeAndComputer(10_000_000);
    }
}

 









以上是关于java 多线程学习笔记 -- 计算密集型任务的主要内容,如果未能解决你的问题,请参考以下文章

线程池应该设置多少核心线程数——Java多线程系列学习笔记

网络编程之异步IO,rabbitMQ笔记

day9-Python学习笔记(二十二)多线程,多进程

多线程执行测试用例二

线程 进程学习

NodeJs多线程、多进程、定时任务