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);
}
}