java多线程计算素数

Java并发是个很常用的知识点。面试基本上是必问,工作中也常用。

并发的风险:
1,程序饥饿,比如一个程序运行的时候要得到操作员的确认,但是操作员吃饭去了,这个程序将一直处于等待状态。
2,死锁:相互等待对方所占有的资源。
3,资源竞争:两个程序竞争相同的资源。
举个栗子:计算一个范围内素数的个数,首先是用常用的顺序计算,然后用多线程进行计算。比较两者的执行效率。下面是一个工具类,顺序计算和多线程计算都要用到。

package com.sunyard.demo.concurrency;

/**
 * 此类作为工具类
 */
public abstract class AbstractPrimeFinder {
    /**
     * 判断一个数是否为素数
     * @param number
     * @return
     */
    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;
    }

    /**
     * 计算一个区间内的素数的个数
     * @param lower
     * @param upper
     * @return
     */
    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;
    }

    /**
     * 统计程序计算素数所花费的时间
     * @param number
     */
    public void timeAndCompute(final int number){
        final long start = System.nanoTime();
        final long numberOfPrimes=countPrimes(number);
        final long end = System.nanoTime();
        System.out.printf("Number of primes under %d is %d\n",number,numberOfPrimes);
        System.out.println("Time (seconds) taken is:"+(end-start)/1.0e9);
    }
    public abstract int countPrimes(final int number);
}
单线程的情况如下:

package com.sunyard.demo.concurrency;

/**
 * 启动类
 */
public class SequentialPrimeFinder extends AbstractPrimeFinder {
    /**
     * 实现父类中的方法
     * @param number
     * @return
     */
    @Override
    public int countPrimes(final int number) {
        return countPrimesInRange(1,number);
    }
    /**
     * 程序主方法
     * @param args
     */
    public static void main(String[] args){
        //计算的区间为1到10000000
        new SequentialPrimeFinder().timeAndCompute(10000000);
    }
}


多线程如下:

public class ConcurrentPrimeFinder extends AbstractPrimeFinder {
    private final int poolSize;//创建线程的个数
    private final int numberOfParts;//任务的份数

    /**
     * 构造方法初始化线程的个数和任务的划分
     * @param poolSize
     * @param numberOfParts
     */
    public ConcurrentPrimeFinder(final int poolSize, final int numberOfParts) {
        this.poolSize = poolSize;
        this.numberOfParts = numberOfParts;
    }

    @Override
    public int countPrimes(final int number) {
        int count=0;//统计各区间的素数个数
        try {
            final List<Callable<Integer>> partitions=new ArrayList<Callable<Integer>>();
            final int chunksPerPartion=number /numberOfParts;
            for(int i=0; i<numberOfParts;i++){
                final int lower=(i*chunksPerPartion)+1;
                final int upper=(i==numberOfParts-1)? number:lower+chunksPerPartion-1;
                partitions.add(new Callable<Integer>() {
                    @Override
                    public Integer call() {
                        return countPrimesInRange(lower,upper);
                    }
                });
            }
            final ExecutorService executorPool= Executors.newFixedThreadPool(poolSize);//在线程池中创建线程
            final List<Future<Integer>> resultFromParts=executorPool.invokeAll(partitions,10000,TimeUnit.SECONDS);
            executorPool.shutdown();//执行完成之后关闭线程池
            for(final Future<Integer> result:resultFromParts)//统计各任务的素数个数
                count +=result.get();
        }catch (Exception ex){
            throw new RuntimeException(ex);
        }
        return count;
    }
    public static void main(String[] args){
        new ConcurrentPrimeFinder(4,4).timeAndCompute(10000000);
    }
}


猜你喜欢

转载自blog.csdn.net/lingmao555/article/details/77461495