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