使用方法,基本类:Executor 、ExecutorService、AbstractExecutorService、ThreadPoolExecutor、Executors
前四个类或接口是继承关系,核心的类是ThreadPoolExecutor,该类实现了executor方法。
Executors是工厂类,负责构建几种基本的线程池类。
这几种基本的线程池类的构建方法:(1)newFixedThreadPool(2)newSingleThreadExecutor(3)newCachedThreadPool
为线程池添加任务的方法:execute,submit(该方法最终也是调用execute,返回Future对象)
线程池控制的一些方法:invokeAll,invokeAny,shutdown,shutdownNow
实例1:
public static void main(String[] args) { // TODO Auto-generated method stub ThreadPoolExecutor executor = (ThreadPoolExecutor)Executors.newFixedThreadPool(10); for(int i=0;i<15;i++){ MyTask myTask = new MyTask(i); executor.execute(myTask); System.out.println("线程池中线程数目:"+executor.getPoolSize()+",队列中等待执行的任务数目:"+ executor.getQueue().size()+",已执行玩别的任务数目:"+executor.getCompletedTaskCount()); } executor.shutdown(); } static class MyTask implements Runnable { private int taskNum; public MyTask(int num) { this.taskNum = num; } @Override public void run() { System.out.println("正在执行task "+taskNum); try { Thread.currentThread().sleep(4000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("task "+taskNum+"执行完毕"); }
其中Executors.newFixedThreadPool(10);是一种线程池的配置,由工厂产生,线程池的核心数和最大数都是10,
默认的阻塞队列是LinkedBlockingQueue<Runnable>。
在这种配置下有以下种状态情况:
新建线程池,线程池还没来任务,则线程池中线程为0。来了任务,线程池中新建线程,线程数小于corePoolSize核心线程数,则再来任务,就新建线程来执行。线程数达到corePoolSize,由于newFixedThreadPool的设置corePoolSize=maximumPoolSize,则将线程放在阻塞队列中。当线程池中的有空闲了,就去阻塞队列中取任务执行。当线程数介于corePoolSize和maximumPoolSize时,多余的线程出现空闲,且空闲时间大于KeepAliveTime,该线程会被终止。现在直接使用ThreadPoolExecutor设置线程池:例如,new ThreadPoolExecutor(5, 10, 200, TimeUnit.SECONDS, new ArrayBlockingQueue(5));
这种配置下
状态3将改变:当线程数达到corePoolSize,任务还是会进入到阻塞队列,如果阻塞队列满了(这里设置大小5),则继续添加线程。
当线程数达到maximumPoolSize,说明线程池达到最高负载,再有任务来就会出现异常,可以自定义拒绝RejectedExecutionHandler方法来处理。
一般情况下,任务的执行是调用execute(Runnable)没有返回值,也可以用submit(callable),返回Future对象或者Future List。
有返回值,实例2:
public static void main(String[] args) { // TODO Auto-generated method stub ThreadPoolExecutor executor=(ThreadPoolExecutor)Executors.newFixedThreadPool(10); List<Myfindtask> mlist=new ArrayList<Myfindtask>(); File filedir = new File("D:/"); for(File f:filedir.listFiles()){ if(f.isDirectory()){ System.out.println(f.getPath()); Myfindtask mf=new Myfindtask("12345.txt",f.getPath()); mlist.add(mf); } } try { String s=executor.invokeAny(mlist); System.out.println(" 线程池中的线程数目:"+executor.getPoolSize()+",队列中等待执行的任务数目:"+ executor.getQueue().size()+",已执行完的别的任务的数目:"+executor.getCompletedTaskCount()); if(s==null) System.out.println("没有找到文件位置:"); else System.out.println("找到文件位置:"+s); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (ExecutionException e) { // TODO Auto-generated catch block e.printStackTrace(); } } static class Myfindtask implements Callable<String>{ public Myfindtask(String filename,String path){ mfilename=filename; mpath=path; } @Override public String call() throws Exception { // TODO Auto-generated method stub String s=findfile(mpath); if(s!=null) return s; else throw new Exception("没找到"); } public String mfilename; public String mpath; public String findfile(String path){ File root = new File(path); File[] files = root.listFiles(); for(File f:files){ try { Thread.currentThread().sleep(4000); } catch (InterruptedException e) { e.printStackTrace(); } if(f.getName().equals(mfilename.toString()))return f.getPath(); } return null; } } 创建任务类MyfindTask继承Callable,实现call方法。 该任务是在目录下查找文件,添加slelep当做耗时操作。如果找到返回路径,如果没找到,在call()方法中抛出异常,该异常会被捕获,证明是未完成任务,如果任何一个线程返回了正确值,则finally关闭所有线程。 Hook 方法: 在ThreadPoolExecutor方法中创建了两个空方法:beforeExecute(),afterExecute(),在自定义的线程池中可以对任务的执行的前后进行HOOK,做收集数据,添加LOG的处理。