java中构建一个新的线程是有一定代价的,因为涉及到与操作系统的交互,如果程序中创建了大量的生命期很短的线程,应该使用线程池(thread pool),一个线程池中包含许多准备运行的空闲线程,将Runnable对象交给线程池,就会有一个线程调用run方法,当run方法退出时,线程不会死亡,而是在池中准备为下一个请求提供服务。
另一个使用线程池的理由是减少并发线程的数目,创建大量线程会大大降低性能甚至使虚拟机崩溃,如果有一个会创建许多线程的算法,应该使用一个线程数“固定的”线程池以限制并发线程的总数。
执行器(Executor)类有许多静态工厂方法用了构建线程池,主要有以下:
newCachedThreadPool 必要时创建线程,空闲线程会被保留60秒;
newFixedThreadPool 该池保护固定数量的线程,空闲线程会一直被保留
newSingleThreadExecutor 只有一个线程的池,该线程顺序执行每一个提交的任务,类似与Swing事件分配线程
newScheduledThreadPool 用于预定执行而构建的固定线程池,替代java.util.Timer
newSingleThreadScheduledExecutor 用于预定执行而构建的单线程池
以下程序将遍历一个目录下的所有文件并且找出包含指定关键字的文件数目,最后将打印出执行池中的最大的线程数,我们不能通过ExecutorService这个接口得到最大的线程数,必须将该Pool对象转化为ThreadPoolExecutor类对象
1 package cn.andy.java.thread; 2 3 import java.io.File; 4 import java.io.FileInputStream; 5 import java.util.ArrayList; 6 import java.util.Scanner; 7 import java.util.concurrent.Callable; 8 import java.util.concurrent.ExecutorService; 9 import java.util.concurrent.Executors; 10 import java.util.concurrent.Future; 11 import java.util.concurrent.ThreadPoolExecutor; 12 public class ThreadPoolTest { 13 14 15 public static void main(String[] args) { 16 Scanner in=new Scanner(System.in); 17 System.out.println("输入目录(e.g. G:/JavaDoc): "); 18 String directory=in.nextLine(); 19 System.out.println("输入查找的关键字(e.g. VoidType): "); 20 String keyword=in.nextLine(); 21 22 ExecutorService pool=Executors.newCachedThreadPool(); 23 24 25 MatchCounter counter=new MatchCounter(new File(directory), keyword, pool); 26 Future<Integer> result=pool.submit(counter); 27 try { 28 System.out.println("得到"+result.get()+" 个匹配文件" ); 29 } catch (Exception e) { 30 e.printStackTrace(); 31 } 32 pool.shutdown(); 33 int largestPoolSize=((ThreadPoolExecutor)pool).getLargestPoolSize(); 34 System.out.println("池中的最大线程数是= "+largestPoolSize); 35 } 36 /** 37 * 得到一个目录总包含关键字的文件及其子文件的数目 38 * @author xiaowei 39 * 40 */ 41 static class MatchCounter implements Callable<Integer>{ 42 private File directory; 43 private String keyword; 44 private ExecutorService pool; 45 private int count; 46 47 public MatchCounter(File directory, String keyword, ExecutorService pool) { 48 super(); 49 this.directory = directory; 50 this.keyword = keyword; 51 this.pool = pool; 52 } 53 /** 54 * 用关键来查找文件 55 * @param file 要查找的文件目录 56 * @return true 如果某个文件中包含关键字了返回true 57 */ 58 public boolean serach(File file){ 59 try { 60 Scanner in=new Scanner(new FileInputStream(file)); 61 boolean found=false; 62 while(!found&&in.hasNext()){ 63 String line=in.nextLine(); 64 if(line.contains(keyword)){ 65 found=true; 66 } 67 } 68 in.close(); 69 return found; 70 } catch (Exception e) { 71 return false; 72 } 73 } 74 @Override 75 public Integer call() throws Exception { 76 count=0; 77 try { 78 File[] files=directory.listFiles(); 79 ArrayList<Future<Integer>> results=new ArrayList<Future<Integer>>(); 80 for(File file:files){ 81 if(file.isDirectory()){ 82 MatchCounter counter=new MatchCounter(file, keyword, pool); 83 Future<Integer> result=pool.submit(counter); 84 results.add(result); 85 }else{ 86 if(serach(file)) count++; 87 } 88 for(Future<Integer> result:results){ 89 try { 90 count+=result.get(); 91 } catch (Exception e) { 92 e.printStackTrace(); 93 } 94 } 95 96 } 97 } catch (Exception e) { 98 99 } 100 return count; 101 } 102 103 } 104 105 }